diff --git a/public/views/js/d.map.js b/public/views/js/d.map.js
index a6a8a33..e40c3b1 100755
--- a/public/views/js/d.map.js
+++ b/public/views/js/d.map.js
@@ -1,131 +1,212 @@
-// Carte principale et marqueurs de POI.
+// Carte principale
var mymap;
-var markers = [];
+var poiLayer;
+var icons = {};
-$( document ).ready(function() {
- // Différentes couches pour la carte.
- var topo_maptiler = L.tileLayer('https://api.maptiler.com/maps/topographique/{z}/{x}/{y}.png?key=Sm8M7mJ53GtYdl773rpi', {tms: false, attribution: 'Carte © MapTiler, Données © Contributeurs OpenStreetMap', tileSize: 512, zoomOffset: -1, minZoom: 1});
- var ign = L.tileLayer('https://data.geopf.fr/private/wmts?&REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE=normal&TILEMATRIXSET=PM&FORMAT=image/jpeg&LAYER=GEOGRAPHICALGRIDSYSTEMS.MAPS&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&apikey=ign_scan_ws', {attribution: 'Carte & Connées © IGN-F/Géoportail'});
-
- // Couches de base.
- var baseLayers = {
- "OpenStreetMap": topo_maptiler,
- "IGN France": ign
- };
-
- mymap = L.map('mapid', {
- zoomControl: false,
- layers: [topo_maptiler]
- }).setView([47, 3], 6);
- $("#map-credits").html(topo_maptiler.getAttribution());
-
- L.control.scale({
- position: "bottomleft",
- imperial: false
- }).addTo(mymap);
-
- var credits = L.easyButton('fa-info',
- function(control, mymap){
- $("footer").hide();
- $("#footer-credits").show();
- $("#footer-legend").hide();
- }, 'Credits');
- var legend = L.easyButton('fa-question',
- function(control, mymap){
- $("footer").hide();
- $("#footer-credits").hide();
- $("#footer-legend").show();
- }, 'Legend');
- L.easyBar([ credits, legend, ], {position: "bottomleft"}).addTo(mymap);
-
- L.control.fullscreen({
- position: "bottomleft"
- }).addTo(mymap);
-
- L.control.zoom({
- zoomOutText: "",
- zoomInText: "",
- position: "bottomleft"
- }).addTo(mymap);
-
- L.control.layers(baseLayers,null,{
- position: "bottomright"
- }).addTo(mymap);
-
- mymap.removeControl(mymap.attributionControl);
-
- $(".close-link").click(function() {
- $("footer").show();
- $("#footer-credits").hide();
- $("#footer-legend").hide();
- });
-
- mymap.on('baselayerchange', function(e) {
- $("#map-credits").html(e.layer.getAttribution());
- });
-
- // Ajuste la taille des icônes selon le niveau de zoom.
- mymap.on("zoomend", function () {
- var z = mymap.getZoom();
-
- var size = 32;
- if (z < 8) size = 20;
- if (z < 4) size = 12;
-
- markers.forEach(function(marker) {
- var icon = marker.options.icon;
- icon.options.iconSize = [size, size];
- icon.options.iconAnchor = [size/2, size];
- marker.setIcon(icon);
- });
- });
+$(document).ready(function() {
// ---------------------------------------------------------
- // CHARGEMENT DES POIs
+ // Fonds de carte
// ---------------------------------------------------------
- $.getJSON(root + "poi/api_list", function(pois) {
-
- var icons = {};
-
- // Préparer les icônes
- for (const type in window.poi_icons) {
- icons[type] = L.icon({
- iconUrl: window.poi_icons[type],
- iconSize: [32, 32],
- iconAnchor: [16, 32],
- popupAnchor: [0, -32]
- });
+ var topo_maptiler = L.tileLayer(
+ 'https://api.maptiler.com/maps/topographique/{z}/{x}/{y}.png?key=Sm8M7mJ53GtYdl773rpi',
+ {
+ tms: false,
+ tileSize: 512,
+ zoomOffset: -1,
+ minZoom: 1,
+ attribution:
+ 'Carte © MapTiler, Données © OpenStreetMap'
}
+ );
- // Ajouter les POIs
- pois.forEach(function(poi) {
-
- var icon = icons[poi.type] || icons["default"];
-
- var marker = L.marker([poi.lat, poi.lon], { icon: icon })
- .addTo(mymap);
-
- // Tooltip discret au survol
- marker.bindTooltip(poi.name, {
- direction: "top",
- offset: [0, -10],
- opacity: 0.9,
- className: "poi-tooltip"
- });
-
- // Clic → ouvrir la fiche directement
- marker.on("click", function() {
- window.location = root + "poi/" + poi.permalink;
- });
-
- markers.push(marker);
- });
-
- // Ajuster la vue
- if (markers.length > 0) {
- var group = L.featureGroup(markers);
- mymap.fitBounds(group.getBounds(), { padding: [30, 30] });
+ var ign = L.tileLayer(
+ 'https://data.geopf.fr/private/wmts?REQUEST=GetTile&SERVICE=WMTS&VERSION=1.0.0&STYLE=normal&TILEMATRIXSET=PM&FORMAT=image/jpeg&LAYER=GEOGRAPHICALGRIDSYSTEMS.MAPS&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&apikey=ign_scan_ws',
+ {
+ attribution: 'Carte © IGN-F/Géoportail'
}
+ );
+
+ var baseLayers = {
+ "OpenStreetMap": topo_maptiler,
+ "IGN France": ign
+ };
+
+ // ---------------------------------------------------------
+ // Carte
+ // ---------------------------------------------------------
+
+ mymap = L.map('mapid', {
+ zoomControl: false,
+ layers: [topo_maptiler]
+ }).setView([47, 3], 6);
+
+ $("#map-credits").html(topo_maptiler.getAttribution());
+
+ poiLayer = L.layerGroup().addTo(mymap);
+
+ // ---------------------------------------------------------
+ // Contrôles
+ // ---------------------------------------------------------
+
+ L.control.scale({
+ position: "bottomleft",
+ imperial: false
+ }).addTo(mymap);
+
+ var credits = L.easyButton(
+ 'fa-info',
+ function() {
+ $("footer").hide();
+ $("#footer-credits").show();
+ $("#footer-legend").hide();
+ },
+ 'Credits'
+ );
+
+ var legend = L.easyButton(
+ 'fa-question',
+ function() {
+ $("footer").hide();
+ $("#footer-credits").hide();
+ $("#footer-legend").show();
+ },
+ 'Legend'
+ );
+
+ L.easyBar(
+ [credits, legend],
+ {
+ position: "bottomleft"
+ }
+ ).addTo(mymap);
+
+ L.control.fullscreen({
+ position: "bottomleft"
+ }).addTo(mymap);
+
+ L.control.zoom({
+ zoomOutText: '',
+ zoomInText: '',
+ position: "bottomleft"
+ }).addTo(mymap);
+
+ L.control.layers(
+ baseLayers,
+ null,
+ {
+ position: "bottomright"
+ }
+ ).addTo(mymap);
+
+ mymap.removeControl(mymap.attributionControl);
+
+ // ---------------------------------------------------------
+ // Footer
+ // ---------------------------------------------------------
+
+ $(".close-link").click(function() {
+ $("footer").show();
+ $("#footer-credits").hide();
+ $("#footer-legend").hide();
});
-});
+
+ mymap.on('baselayerchange', function(e) {
+ $("#map-credits").html(
+ e.layer.getAttribution()
+ );
+ });
+
+ // ---------------------------------------------------------
+ // Icônes
+ // ---------------------------------------------------------
+
+ for (const type in window.poi_icons) {
+
+ icons[type] = L.icon({
+ iconUrl: window.poi_icons[type],
+ iconSize: [32, 32],
+ iconAnchor: [16, 32],
+ popupAnchor: [0, -32]
+ });
+
+ }
+
+ // ---------------------------------------------------------
+ // Chargement des POI visibles
+ // ---------------------------------------------------------
+
+ function loadVisiblePois() {
+ if (mymap.getZoom() < 10) {
+
+ poiLayer.clearLayers();
+
+ return;
+ }
+
+ var b = mymap.getBounds();
+
+ $.getJSON(
+ root + "poi/api_bbox",
+ {
+ north: b.getNorth(),
+ south: b.getSouth(),
+ east: b.getEast(),
+ west: b.getWest()
+ },
+ function(pois) {
+
+ poiLayer.clearLayers();
+
+ pois.forEach(function(poi) {
+
+ var icon =
+ icons[poi.type] ||
+ icons["default"];
+
+ var marker = L.marker(
+ [poi.lat, poi.lon],
+ {
+ icon: icon
+ }
+ );
+
+ marker.bindTooltip(
+ poi.name,
+ {
+ direction: "top",
+ offset: [0, -10],
+ opacity: 0.9,
+ className:
+ "poi-tooltip"
+ }
+ );
+
+ marker.on(
+ "click",
+ function() {
+ window.location =
+ root +
+ "poi/" +
+ poi.permalink;
+ }
+ );
+
+ poiLayer.addLayer(marker);
+
+ });
+ }
+ );
+ }
+
+ // ---------------------------------------------------------
+ // Rechargement automatique
+ // ---------------------------------------------------------
+
+ mymap.on("moveend", loadVisiblePois);
+ mymap.on("zoomend", loadVisiblePois);
+
+ // Premier chargement
+ loadVisiblePois();
+});
\ No newline at end of file
diff --git a/src/Controllers/d.poi.php b/src/Controllers/d.poi.php
index 056368b..6c23be5 100755
--- a/src/Controllers/d.poi.php
+++ b/src/Controllers/d.poi.php
@@ -113,12 +113,22 @@ switch ($controller->splitted_url[1]) {
}
break;
- case "api_list":
+ case "api_bbox":
// API JSON pour la liste des POIs (carte).
header("Content-Type: application/json; charset=utf-8");
+ $north = (float)$_GET['north'];
+ $south = (float)$_GET['south'];
+ $east = (float)$_GET['east'];
+ $west = (float)$_GET['west'];
+
$pois = new Kabano\Pois();
- $pois->listPois($user->rankIsHigher("premium") ? 1 : 0);
+ $pois->listPoisBBOX(
+ $north,
+ $south,
+ $east,
+ $west,
+ $user->rankIsHigher("premium") ? 1 : 0);
$out = [];
diff --git a/src/Models/d.poi.php b/src/Models/d.poi.php
index ebcf241..6142855 100755
--- a/src/Models/d.poi.php
+++ b/src/Models/d.poi.php
@@ -397,7 +397,7 @@ class Pois
public $number = 0;
// Liste des POIs publiés (ou archivés si demandé).
- public function listPois($archive=0) {
+ public function listPoisBBOX($n,$s,$e,$w,$archive=0) {
global $config;
// Chargement des POIs avec leurs versions actives.
@@ -442,15 +442,23 @@ class Pois
ON sources.id = specs.source_id
WHERE contents.type = 'poi'
- AND content_versions.is_archive = FALSE";
+ AND content_versions.is_archive = FALSE
+ AND specs.geom && ST_MakeEnvelope(
+ $1,
+ $2,
+ $3,
+ $4,
+ 4326
+ )
+ ";
if ($archive != 1)
$query .= " AND contents.is_public=TRUE ";
$query .= " ORDER BY content_versions.update_date DESC";
- pg_prepare($con, "pois_list", $query);
- $result = pg_execute($con, "pois_list", []);
+ pg_prepare($con, "pois_bbox", $query);
+ $result = pg_execute($con, "pois_bbox", [$w, $s, $e, $n]);
pg_close($con);