fix: Only show rescue orgs and animal shelters when relevant

This commit is contained in:
2025-06-17 23:35:11 +02:00
parent 59d96e36a4
commit edc27b899e
2 changed files with 226 additions and 221 deletions

View File

@@ -39,253 +39,257 @@
map.on('load', async () => {
// Load adoption notices as geojson
map.addSource('adoption-notices', {
type: 'geojson',
data: '{% url "api-adoption-notice-list-geojson" %}',
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
// Layer for clusters
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'adoption-notices',
filter: ['has', 'point_count'],
paint: {
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'adoption-notices',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-size': 12,
'text-font': ['open_sans_medium'],
}
});
const rat_image = await map.loadImage('{% static 'fellchensammlung/img/logo_transparent.png' %}');
map.addImage('rat', rat_image.data);
map.addLayer({
id: 'unclustered-point',
type: 'symbol',
source: 'adoption-notices',
filter: ['!', ['has', 'point_count']],
layout: {
'icon-image': ['get', 'species'],
'icon-size': 0.07,
'icon-allow-overlap': true
}
});
// Load rescue_orgs as geojson
map.addSource('rescue-orgs', {
type: 'geojson',
data: '{% url "api-organization-list-geojson" %}',
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
// Layer for clusters
map.addLayer({
id: 'org-clusters',
type: 'circle',
source: 'rescue-orgs',
filter: ['has', 'point_count'],
paint: {
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
map.addLayer({
id: 'org-cluster-count',
type: 'symbol',
source: 'rescue-orgs',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-size': 12,
'text-font': ['open_sans_medium'],
}
});
const org_image = await map.loadImage('{% static 'fellchensammlung/img/animal_shelter.png' %}');
map.addImage('org', org_image.data);
map.addLayer({
id: 'org-unclustered-point',
type: 'symbol',
source: 'rescue-orgs',
filter: ['!', ['has', 'point_count']],
layout: {
'icon-image': 'org',
'icon-size': 0.07,
'icon-allow-overlap': true
}
});
// inspect an AN cluster on click
map.on('click', 'clusters', async (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['clusters']
{% if show_ANs %}
// Load adoption notices as geojson
map.addSource('adoption-notices', {
type: 'geojson',
data: '{% url "api-adoption-notice-list-geojson" %}',
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
const clusterId = features[0].properties.cluster_id;
const zoom = await map.getSource('adoption-notices').getClusterExpansionZoom(clusterId);
map.easeTo({
center: features[0].geometry.coordinates,
zoom
// Layer for clusters
map.addLayer({
id: 'clusters',
type: 'circle',
source: 'adoption-notices',
filter: ['has', 'point_count'],
paint: {
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
});
// inspect an org cluster on click
map.on('click', 'org-clusters', async (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['org-clusters']
map.addLayer({
id: 'cluster-count',
type: 'symbol',
source: 'adoption-notices',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-size': 12,
'text-font': ['open_sans_medium'],
}
});
const clusterId = features[0].properties.cluster_id;
const zoom = await map.getSource('rescue-orgs').getClusterExpansionZoom(clusterId);
map.easeTo({
center: features[0].geometry.coordinates,
zoom
const rat_image = await map.loadImage('{% static 'fellchensammlung/img/logo_transparent.png' %}');
map.addImage('rat', rat_image.data);
map.addLayer({
id: 'unclustered-point',
type: 'symbol',
source: 'adoption-notices',
filter: ['!', ['has', 'point_count']],
layout: {
'icon-image': ['get', 'species'],
'icon-size': 0.07,
'icon-allow-overlap': true
}
});
});
// When a click event occurs on a feature in
// the unclustered-point layer, open a popup at
// the location of the feature, with
// description HTML from its properties.
map.on('click', 'unclustered-point', (e) => {
const coordinates = e.features[0].geometry.coordinates.slice();
const title = e.features[0].properties.title;
const url = e.features[0].properties.url;
const description = e.features[0].properties.description;
const location_hr = e.features[0].properties.location_hr;
const image_url = e.features[0].properties.image_url;
const image_alt = e.features[0].properties.image_alt;
// Ensure that if the map is zoomed out such that
// multiple copies of the feature are visible, the
// popup appears over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
const description_column = `
// inspect an AN cluster on click
map.on('click', 'clusters', async (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['clusters']
});
const clusterId = features[0].properties.cluster_id;
const zoom = await map.getSource('adoption-notices').getClusterExpansionZoom(clusterId);
map.easeTo({
center: features[0].geometry.coordinates,
zoom
});
});
// When a click event occurs on a feature in
// the unclustered-point layer, open a popup at
// the location of the feature, with
// description HTML from its properties.
map.on('click', 'unclustered-point', (e) => {
const coordinates = e.features[0].geometry.coordinates.slice();
const title = e.features[0].properties.title;
const url = e.features[0].properties.url;
const description = e.features[0].properties.description;
const location_hr = e.features[0].properties.location_hr;
const image_url = e.features[0].properties.image_url;
const image_alt = e.features[0].properties.image_alt;
// Ensure that if the map is zoomed out such that
// multiple copies of the feature are visible, the
// popup appears over the copy being pointed to.
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
const description_column = `
<div class="column">
<strong><a class="is-size-7" href="${url}">${title}</a></strong> <i class="fa-solid fa-arrow-up-right-from-square"></i><br>
<span><strong>{% translate 'Ort' %}</strong>: ${location_hr}</span><br>
<p class="is-size-7">${truncate(description, 80, url)}</p>
</div>
`;
let picture_column = '';
if (image_url) {
picture_column = `
let picture_column = '';
if (image_url) {
picture_column = `
<div class="column">
<figure class="image is-128x128">
<img src="${image_url}" alt="${image_alt}"/>
</figure>
</div>`;
}
}
new maplibregl.Popup()
.setLngLat(coordinates)
.setHTML(`
new maplibregl.Popup()
.setLngLat(coordinates)
.setHTML(`
<div class="popup-content is-size-7">
<div class="columns">
${description_column}
${picture_column}
</div>
</div>`
)
.addTo(map);
});
)
.addTo(map);
});
// Same for orgs
map.on('click', 'org-unclustered-point', (e) => {
const coordinates = e.features[0].geometry.coordinates.slice();
const name = e.features[0].properties.name;
const url = e.features[0].properties.url;
const description = e.features[0].properties.description;
const location_hr = e.features[0].properties.location_hr;
map.on('mouseenter', 'clusters', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'clusters', () => {
map.getCanvas().style.cursor = '';
});
{% endif %}
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
{% if show_rescue_orgs %}
// Load rescue_orgs as geojson
map.addSource('rescue-orgs', {
type: 'geojson',
data: '{% url "api-organization-list-geojson" %}',
cluster: true,
clusterMaxZoom: 14,
clusterRadius: 50
});
// Layer for clusters
map.addLayer({
id: 'org-clusters',
type: 'circle',
source: 'rescue-orgs',
filter: ['has', 'point_count'],
paint: {
'circle-color': [
'step',
['get', 'point_count'],
'#51bbd6',
100,
'#f1f075',
750,
'#f28cb1'
],
'circle-radius': [
'step',
['get', 'point_count'],
20,
100,
30,
750,
40
]
}
});
map.addLayer({
id: 'org-cluster-count',
type: 'symbol',
source: 'rescue-orgs',
filter: ['has', 'point_count'],
layout: {
'text-field': '{point_count_abbreviated}',
'text-size': 12,
'text-font': ['open_sans_medium'],
}
});
const org_image = await map.loadImage('{% static 'fellchensammlung/img/animal_shelter.png' %}');
map.addImage('org', org_image.data);
new maplibregl.Popup()
.setLngLat(coordinates)
.setHTML(`
map.addLayer({
id: 'org-unclustered-point',
type: 'symbol',
source: 'rescue-orgs',
filter: ['!', ['has', 'point_count']],
layout: {
'icon-image': 'org',
'icon-size': 0.07,
'icon-allow-overlap': true
}
});
// inspect an org cluster on click
map.on('click', 'org-clusters', async (e) => {
const features = map.queryRenderedFeatures(e.point, {
layers: ['org-clusters']
});
const clusterId = features[0].properties.cluster_id;
const zoom = await map.getSource('rescue-orgs').getClusterExpansionZoom(clusterId);
map.easeTo({
center: features[0].geometry.coordinates,
zoom
});
});
// Same for orgs
map.on('click', 'org-unclustered-point', (e) => {
const coordinates = e.features[0].geometry.coordinates.slice();
const name = e.features[0].properties.name;
const url = e.features[0].properties.url;
const description = e.features[0].properties.description;
const location_hr = e.features[0].properties.location_hr;
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
}
new maplibregl.Popup()
.setLngLat(coordinates)
.setHTML(`
<div class="popup-content is-size-7">
<strong><a class="is-size-7" href="${url}">${name}</a></strong> <i class="fa-solid fa-arrow-up-right-from-square"></i><br>
<span><strong>{% translate 'Ort' %}</strong>: ${location_hr}</span><br>
<p class="is-size-7">${truncate(description, 80, url)}</p>
</div>`
)
.addTo(map);
});
)
.addTo(map);
});
map.on('mouseenter', 'clusters', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'clusters', () => {
map.getCanvas().style.cursor = '';
});
map.on('mouseenter', 'org-clusters', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'org-clusters', () => {
map.getCanvas().style.cursor = '';
});
map.on('mouseenter', 'org-clusters', () => {
map.getCanvas().style.cursor = 'pointer';
});
map.on('mouseleave', 'org-clusters', () => {
map.getCanvas().style.cursor = '';
});
{% endif %}
image = await map.loadImage('{% static "fellchensammlung/img/pin.png" %}');
map.addImage('pin', image.data);

View File

@@ -142,7 +142,6 @@ def adoption_notice_detail(request, adoption_notice_id):
return render(request, 'fellchensammlung/details/bulma-detail-adoption-notice.html', context=context)
@login_required()
def adoption_notice_edit(request, adoption_notice_id):
"""
@@ -178,14 +177,14 @@ def search_important_locations(request, important_location_slug):
"place_not_found": search.place_not_found,
"subscribed_search": None,
"searched": False,
"adoption_notices_map": AdoptionNotice.get_active_ANs(),
"map_center": search.position,
"search_center": search.position,
"map_pins": [search],
"location": search.location,
"search_radius": search.max_distance,
"zoom_level": zoom_level_for_radius(search.max_distance),
"geocoding_api_url": settings.GEOCODING_API_URL, }
"geocoding_api_url": settings.GEOCODING_API_URL,
"show_ANs": True}
return render(request, 'fellchensammlung/bulma-search.html', context=context)
@@ -220,14 +219,14 @@ def search(request, templatename="fellchensammlung/bulma-search.html"):
"place_not_found": search.place_not_found,
"subscribed_search": subscribed_search,
"searched": searched,
"adoption_notices_map": AdoptionNotice.get_active_ANs(),
"map_center": search.position,
"search_center": search.position,
"map_pins": [search],
"location": search.location,
"search_radius": search.max_distance,
"zoom_level": zoom_level_for_radius(search.max_distance),
"geocoding_api_url": settings.GEOCODING_API_URL, }
"geocoding_api_url": settings.GEOCODING_API_URL,
"show_ANs": True}
return render(request, templatename, context=context)
@@ -298,7 +297,6 @@ def adoption_notice_add_animal(request, adoption_notice_id):
return render(request, 'fellchensammlung/forms/form_add_animal_to_adoption.html', {'form': form})
@login_required
def add_photo_to_animal_bulma(request, animal_id):
animal = Animal.objects.get(id=animal_id)
@@ -597,8 +595,12 @@ def updatequeue(request):
"adoption_notices_active": adoption_notices_active}
return render(request, 'fellchensammlung/updatequeue.html', context=context)
def map_bulma(request):
return map(request, templatename='fellchensammlung/bulma-map.html')
context = {"show_ANs": True,
"show_rescue_orgs": True}
return render(request, 'fellchensammlung/bulma-map.html', context=context)
def metrics(request):
@@ -675,7 +677,8 @@ def external_site_warning(request, template_name='fellchensammlung/bulma-externa
def list_rescue_organizations(request, template='fellchensammlung/bulma-animal-shelters.html'):
rescue_organizations = RescueOrganization.objects.all()
context = {"rescue_organizations": rescue_organizations}
context = {"rescue_organizations": rescue_organizations,
"show_rescue_orgs": True}
return render(request, template, context=context)
@@ -683,8 +686,7 @@ def detail_view_rescue_organization(request, rescue_organization_id,
template='fellchensammlung/details/bulma-detail-rescue-organization.html'):
org = RescueOrganization.objects.get(pk=rescue_organization_id)
return render(request, template,
context={"org": org, "map_center": org.position, "zoom_level": 6, "rescue_organizations": [org]})
context={"org": org, "map_center": org.position, "zoom_level": 6, "map_pins": [org]})
def export_own_profile(request):
@@ -699,7 +701,6 @@ def export_own_profile(request):
return HttpResponse(full_json, content_type="application/json")
@login_required
def rescue_organization_check(request):
if request.method == "POST":