From 9a0c7016a59a4c6da60c3a1b4ce094853bdf1c24 Mon Sep 17 00:00:00 2001 From: Jean-Marie Favreau Date: Sun, 4 May 2025 23:19:12 +0200 Subject: [PATCH] =?UTF-8?q?On=20introduit=20une=20API=20pour=20avoir=20un?= =?UTF-8?q?=20chargement=20plus=20fluide=20de=20la=20carte=20d'=C3=A9ditio?= =?UTF-8?q?n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #378 --- src/agenda_culturel/serializers/__init__.py | 1 + .../serializers/place_serializer.py | 30 +++++++++++ src/agenda_culturel/settings/base.py | 1 + .../static/location_field/js/form.js | 26 +++------ .../templates/agenda_culturel/place_form.html | 53 +++++++++++++++---- src/agenda_culturel/urls.py | 3 ++ src/agenda_culturel/views/places_views.py | 27 ++++++++-- src/requirements.txt | 1 + 8 files changed, 107 insertions(+), 35 deletions(-) create mode 100644 src/agenda_culturel/serializers/__init__.py create mode 100644 src/agenda_culturel/serializers/place_serializer.py diff --git a/src/agenda_culturel/serializers/__init__.py b/src/agenda_culturel/serializers/__init__.py new file mode 100644 index 0000000..40bb118 --- /dev/null +++ b/src/agenda_culturel/serializers/__init__.py @@ -0,0 +1 @@ +from .place_serializer import PlaceSerializer diff --git a/src/agenda_culturel/serializers/place_serializer.py b/src/agenda_culturel/serializers/place_serializer.py new file mode 100644 index 0000000..c9dfc47 --- /dev/null +++ b/src/agenda_culturel/serializers/place_serializer.py @@ -0,0 +1,30 @@ +from rest_framework import serializers +from ..models import Place + + +class PlaceSerializer(serializers.ModelSerializer): + lat = serializers.SerializerMethodField() + lng = serializers.SerializerMethodField() + url = serializers.SerializerMethodField() + + class Meta: + model = Place + fields = [ + "name", + "address", + "postcode", + "city", + "description", + "lat", + "lng", + "url", + ] + + def get_lat(self, obj): + return obj.location[1] if obj.location else None + + def get_lng(self, obj): + return obj.location[0] if obj.location else None + + def get_url(self, obj): + return obj.get_absolute_url() diff --git a/src/agenda_culturel/settings/base.py b/src/agenda_culturel/settings/base.py index d2149f2..bf3b341 100644 --- a/src/agenda_culturel/settings/base.py +++ b/src/agenda_culturel/settings/base.py @@ -72,6 +72,7 @@ INSTALLED_APPS = [ "django_cleanup.apps.CleanupConfig", "django_unused_media", "solo.apps.SoloAppConfig", + "rest_framework", ] SOLO_CACHE_TIMEOUT = 60 * 15 # 15 minutes diff --git a/src/agenda_culturel/static/location_field/js/form.js b/src/agenda_culturel/static/location_field/js/form.js index 528c0c4..561c623 100644 --- a/src/agenda_culturel/static/location_field/js/form.js +++ b/src/agenda_culturel/static/location_field/js/form.js @@ -375,6 +375,10 @@ var SequentialLoader = function() { _getMap: function(mapOptions) { var map = new L.Map(this.options.id, mapOptions), layer; + if (window.loadTiles !== undefined) { + window.loadTiles(map); + } + if (this.options.provider == 'google') { layer = new L.gridLayer.googleMutant({ type: this.options.providerOptions.google.mapType.toLowerCase(), @@ -397,25 +401,6 @@ var SequentialLoader = function() { map.addLayer(layer); - if ((window.other_markers !== null) && (window.other_markers.length > 0)) { - var layerGroup = L.layerGroup().addTo(map); - window.other_markers.forEach(x => layerGroup.addLayer(x)); - map.removeLayer(layerGroup); - map.on('zoomend', function () { - var currentZoom = map.getZoom(); - - if (currentZoom > 12) { - if (!map.hasLayer(layerGroup)) { - map.addLayer(layerGroup); - } - } else { - if (map.hasLayer(layerGroup)) { - map.removeLayer(layerGroup); - } - } - }); - } - return map; }, @@ -434,7 +419,8 @@ var SequentialLoader = function() { var self = this, markerOptions = { draggable: true, - icon: window.pinIcon + icon: window.pinIcon, + zIndexOffset: 1000, }; var marker = L.marker(center, markerOptions).addTo(map); diff --git a/src/agenda_culturel/templates/agenda_culturel/place_form.html b/src/agenda_culturel/templates/agenda_culturel/place_form.html index 50390d1..091123b 100644 --- a/src/agenda_culturel/templates/agenda_culturel/place_form.html +++ b/src/agenda_culturel/templates/agenda_culturel/place_form.html @@ -37,18 +37,51 @@ shadowSize: [19, 19] }); + window.loadedTiles = new Set(); + window.loadTiles = (map) => { + var layerGroup = L.layerGroup().addTo(map); + var dl_places = () => { + const zoom = map.getZoom(); + if (zoom < 12) { + if (map.hasLayer(layerGroup)) + map.removeLayer(layerGroup); + return; + } + else + if (!map.hasLayer(layerGroup)) { + map.addLayer(layerGroup); + layerGroup.bringToBack(); + } - window.other_markers = []; - {% with cache_timeout=user.is_authenticated|yesno:"300,6000" %} - {% cache cache_timeout place_lists_js user.is_authenticated %} + const bounds = map.getBounds(); + const tileSize = 0.1; + + const latStart = Math.floor(bounds.getSouth() / tileSize); + const latEnd = Math.ceil(bounds.getNorth() / tileSize); + const lngStart = Math.floor(bounds.getWest() / tileSize); + const lngEnd = Math.ceil(bounds.getEast() / tileSize); + + for (let x = lngStart; x <= lngEnd; x++) { + for (let y = latStart; y <= latEnd; y++) { + const tileKey = `${x}_${y}`; + if (window.loadedTiles.has(tileKey)) continue; + + fetch(`/api/places/tile/?tile_x=${x}&tile_y=${y}&tile_size=${tileSize}`) + .then((res) => res.json()) + .then((data) => { + data.forEach((place) => { + layerGroup.addLayer(L.marker([place.lat, place.lng], {'icon': circleIcon}) + .bindPopup(`${place.name}`)); + }); + window.loadedTiles.add(tileKey); + }); + } + } + }; + map.on("moveend", dl_places); + dl_places(); + }; - {% if place_list %} - {% for place in place_list %} - window.other_markers.push(L.marker([{{ place.location|tocoords }}], {'icon': circleIcon}).bindPopup('{{ place.name }}
{% if place.address %}{{ place.address }}, {% endif %}{{ place.city }}')); - {% endfor %} - {% endif %} - {% endcache %} - {% endwith %}