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);