From 9c68959083a35d8f3c5022e0d159c173ec33c90a Mon Sep 17 00:00:00 2001 From: leosw Date: Sun, 18 Oct 2026 15:19:59 +0200 Subject: [PATCH] =?UTF-8?q?Pemi=C3=A8re=20version=20des=20tuiles=20pbf=20d?= =?UTF-8?q?e=20cabanes=20=C3=A0=20faible=20zoom?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/views/js/d.map.js | 391 ++++++++++-------- .../Leaflet.VectorGrid.bundled.min.js | 2 + src/Controllers/d.map.php | 2 +- src/Controllers/d.poi.php | 12 + src/Models/d.poi.php | 306 ++++++++------ 5 files changed, 418 insertions(+), 295 deletions(-) create mode 100644 public/views/third/leaflet-vectorgrid/Leaflet.VectorGrid.bundled.min.js diff --git a/public/views/js/d.map.js b/public/views/js/d.map.js index e40c3b1..d319337 100755 --- a/public/views/js/d.map.js +++ b/public/views/js/d.map.js @@ -1,212 +1,275 @@ // Carte principale var mymap; var poiLayer; +var vectorLayer; var icons = {}; $(document).ready(function() { - // --------------------------------------------------------- - // Fonds de carte - // --------------------------------------------------------- + // --------------------------------------------------------- + // Fonds de carte + // --------------------------------------------------------- - 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' - } - ); + 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' + } + ); - 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 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 - }; + var baseLayers = { + "OpenStreetMap": topo_maptiler, + "IGN France": ign + }; - // --------------------------------------------------------- - // Carte - // --------------------------------------------------------- + // --------------------------------------------------------- + // Carte + // --------------------------------------------------------- - mymap = L.map('mapid', { - zoomControl: false, - layers: [topo_maptiler] - }).setView([47, 3], 6); + mymap = L.map('mapid', { + zoomControl: false, + layers: [topo_maptiler] + }).setView([47, 3], 6); - $("#map-credits").html(topo_maptiler.getAttribution()); + $("#map-credits").html(topo_maptiler.getAttribution()); - poiLayer = L.layerGroup().addTo(mymap); + poiLayer = L.layerGroup().addTo(mymap); - // --------------------------------------------------------- - // Contrôles - // --------------------------------------------------------- + // Couche vectorielle utilisée pour les faibles zooms + vectorLayer = L.vectorGrid.protobuf( + root + "poi/tile/{z}/{x}/{y}.pbf", + { + interactive: true, - L.control.scale({ - position: "bottomleft", - imperial: false - }).addTo(mymap); + maxZoom: 9, - var credits = L.easyButton( - 'fa-info', - function() { - $("footer").hide(); - $("#footer-credits").show(); - $("#footer-legend").hide(); - }, - 'Credits' - ); + vectorTileLayerStyles: { + pois: {} + } - var legend = L.easyButton( - 'fa-question', - function() { - $("footer").hide(); - $("#footer-credits").hide(); - $("#footer-legend").show(); - }, - 'Legend' - ); + } + ); - L.easyBar( - [credits, legend], - { - position: "bottomleft" - } - ).addTo(mymap); + // Clic sur un POI vectoriel + vectorLayer.on("click", function(e) { - L.control.fullscreen({ - position: "bottomleft" - }).addTo(mymap); + if ( + e.layer && + e.layer.properties && + e.layer.properties.permalink + ) { - L.control.zoom({ - zoomOutText: '', - zoomInText: '', - position: "bottomleft" - }).addTo(mymap); + window.location = + root + + "poi/" + + e.layer.properties.permalink; + } - L.control.layers( - baseLayers, - null, - { - position: "bottomright" - } - ).addTo(mymap); + }); - mymap.removeControl(mymap.attributionControl); + // --------------------------------------------------------- + // Contrôles + // --------------------------------------------------------- - // --------------------------------------------------------- - // Footer - // --------------------------------------------------------- + L.control.scale({ + position: "bottomleft", + imperial: false + }).addTo(mymap); - $(".close-link").click(function() { - $("footer").show(); - $("#footer-credits").hide(); - $("#footer-legend").hide(); - }); + var credits = L.easyButton( + 'fa-info', + function() { + $("footer").hide(); + $("#footer-credits").show(); + $("#footer-legend").hide(); + }, + 'Credits' + ); - mymap.on('baselayerchange', function(e) { - $("#map-credits").html( - e.layer.getAttribution() - ); - }); + var legend = L.easyButton( + 'fa-question', + function() { + $("footer").hide(); + $("#footer-credits").hide(); + $("#footer-legend").show(); + }, + 'Legend' + ); - // --------------------------------------------------------- - // Icônes - // --------------------------------------------------------- + L.easyBar( + [credits, legend], + { + position: "bottomleft" + } + ).addTo(mymap); - for (const type in window.poi_icons) { + L.control.fullscreen({ + position: "bottomleft" + }).addTo(mymap); - icons[type] = L.icon({ - iconUrl: window.poi_icons[type], - iconSize: [32, 32], - iconAnchor: [16, 32], - popupAnchor: [0, -32] - }); + L.control.zoom({ + zoomOutText: '', + zoomInText: '', + position: "bottomleft" + }).addTo(mymap); - } + L.control.layers( + baseLayers, + null, + { + position: "bottomright" + } + ).addTo(mymap); - // --------------------------------------------------------- - // Chargement des POI visibles - // --------------------------------------------------------- + mymap.removeControl(mymap.attributionControl); - function loadVisiblePois() { - if (mymap.getZoom() < 10) { + // --------------------------------------------------------- + // Footer + // --------------------------------------------------------- - poiLayer.clearLayers(); + $(".close-link").click(function() { + $("footer").show(); + $("#footer-credits").hide(); + $("#footer-legend").hide(); + }); - return; - } + mymap.on('baselayerchange', function(e) { + $("#map-credits").html( + e.layer.getAttribution() + ); + }); - var b = mymap.getBounds(); + // --------------------------------------------------------- + // Icônes + // --------------------------------------------------------- - $.getJSON( - root + "poi/api_bbox", - { - north: b.getNorth(), - south: b.getSouth(), - east: b.getEast(), - west: b.getWest() - }, - function(pois) { + for (const type in window.poi_icons) { - poiLayer.clearLayers(); + icons[type] = L.icon({ + iconUrl: window.poi_icons[type], + iconSize: [32, 32], + iconAnchor: [16, 32], + popupAnchor: [0, -32] + }); - pois.forEach(function(poi) { + } - var icon = - icons[poi.type] || - icons["default"]; + // --------------------------------------------------------- + // Chargement des POI visibles + // --------------------------------------------------------- - var marker = L.marker( - [poi.lat, poi.lon], - { - icon: icon - } - ); + function loadVisiblePois() { - marker.bindTooltip( - poi.name, - { - direction: "top", - offset: [0, -10], - opacity: 0.9, - className: - "poi-tooltip" - } - ); + if (mymap.getZoom() < 10) + return; - marker.on( - "click", - function() { - window.location = - root + - "poi/" + - poi.permalink; - } - ); + var b = mymap.getBounds(); - poiLayer.addLayer(marker); + $.getJSON( + root + "poi/api_bbox", + { + north: b.getNorth(), + south: b.getSouth(), + east: b.getEast(), + west: b.getWest() + }, + function(pois) { - }); - } - ); - } + poiLayer.clearLayers(); - // --------------------------------------------------------- - // Rechargement automatique - // --------------------------------------------------------- + pois.forEach(function(poi) { - mymap.on("moveend", loadVisiblePois); - mymap.on("zoomend", loadVisiblePois); + var icon = + icons[poi.type] || + icons["default"]; - // Premier chargement - loadVisiblePois(); + 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); + + }); + + } + ); + } + + // --------------------------------------------------------- + // Bascule entre le calque tle et geojson + // --------------------------------------------------------- + + function switchLayers() { + + var z = mymap.getZoom(); + + if (z < 10) { + + poiLayer.clearLayers(); + + if (!mymap.hasLayer(vectorLayer)) { + mymap.addLayer(vectorLayer); + } + + } else { + + if (mymap.hasLayer(vectorLayer)) { + mymap.removeLayer(vectorLayer); + } + + loadVisiblePois(); + } + } + + // --------------------------------------------------------- + // Rechargement automatique + // --------------------------------------------------------- + + mymap.on("zoomend", switchLayers); + mymap.on("moveend", function() { + + if (mymap.getZoom() >= 10) { + loadVisiblePois(); + } + + }); + + switchLayers(); }); \ No newline at end of file diff --git a/public/views/third/leaflet-vectorgrid/Leaflet.VectorGrid.bundled.min.js b/public/views/third/leaflet-vectorgrid/Leaflet.VectorGrid.bundled.min.js new file mode 100644 index 0000000..1640f3d --- /dev/null +++ b/public/views/third/leaflet-vectorgrid/Leaflet.VectorGrid.bundled.min.js @@ -0,0 +1,2 @@ +"use strict";function __$strToBlobUri(t,e,r){try{return window.URL.createObjectURL(new Blob([Uint8Array.from(t.split("").map(function(t){return t.charCodeAt(0)}))],{type:e}))}catch(i){return"data:"+e+(r?";base64,":",")+t}}function Pbf(t){this.buf=ArrayBuffer.isView&&ArrayBuffer.isView(t)?t:new Uint8Array(t||0),this.pos=0,this.type=0,this.length=this.buf.length}function readVarintRemainder(t,e,r){var i,n,o=r.buf;if(n=o[r.pos++],i=(112&n)>>4,n<128)return toNum(t,i,e);if(n=o[r.pos++],i|=(127&n)<<3,n<128)return toNum(t,i,e);if(n=o[r.pos++],i|=(127&n)<<10,n<128)return toNum(t,i,e);if(n=o[r.pos++],i|=(127&n)<<17,n<128)return toNum(t,i,e);if(n=o[r.pos++],i|=(127&n)<<24,n<128)return toNum(t,i,e);if(n=o[r.pos++],i|=(1&n)<<31,n<128)return toNum(t,i,e);throw new Error("Expected varint not more than 10 bytes")}function readPackedEnd(t){return t.type===Pbf.Bytes?t.readVarint()+t.pos:t.pos+1}function toNum(t,e,r){return r?4294967296*e+(t>>>0):4294967296*(e>>>0)+(t>>>0)}function writeBigVarint(t,e){var r,i;if(t>=0?(r=t%4294967296|0,i=t/4294967296|0):(r=~(-t%4294967296),i=~(-t/4294967296),4294967295^r?r=r+1|0:(r=0,i=i+1|0)),t>=0x10000000000000000||t<-0x10000000000000000)throw new Error("Given varint doesn't fit into 10 bytes");e.realloc(10),writeBigVarintLow(r,i,e),writeBigVarintHigh(i,e)}function writeBigVarintLow(t,e,r){r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos]=127&t}function writeBigVarintHigh(t,e){var r=(7&t)<<4;e.buf[e.pos++]|=r|((t>>>=3)?128:0),t&&(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),t&&(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),t&&(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),t&&(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),t&&(e.buf[e.pos++]=127&t)))))}function makeRoomForExtraLength(t,e,r){var i=e<=16383?1:e<=2097151?2:e<=268435455?3:Math.ceil(Math.log(e)/(7*Math.LN2));r.realloc(i);for(var n=r.pos-1;n>=t;n--)r.buf[n+i]=r.buf[n]}function writePackedVarint(t,e){for(var r=0;r>>8,t[r+2]=e>>>16,t[r+3]=e>>>24}function readInt32(t,e){return(t[e]|t[e+1]<<8|t[e+2]<<16)+(t[e+3]<<24)}function readUtf8(t,e,r){for(var i="",n=e;n239?4:o>223?3:o>191?2:1;if(n+a>r)break;var u,h,l;1===a?o<128&&(s=o):2===a?128==(192&(u=t[n+1]))&&(s=(31&o)<<6|63&u)<=127&&(s=null):3===a?(u=t[n+1],h=t[n+2],128==(192&u)&&128==(192&h)&&((s=(15&o)<<12|(63&u)<<6|63&h)<=2047||s>=55296&&s<=57343)&&(s=null)):4===a&&(u=t[n+1],h=t[n+2],l=t[n+3],128==(192&u)&&128==(192&h)&&128==(192&l)&&((s=(15&o)<<18|(63&u)<<12|(63&h)<<6|63&l)<=65535||s>=1114112)&&(s=null)),null===s?(s=65533,a=1):s>65535&&(s-=65536,i+=String.fromCharCode(s>>>10&1023|55296),s=56320|1023&s),i+=String.fromCharCode(s),n+=a}return i}function writeUtf8(t,e,r){for(var i,n,o=0;o55295&&i<57344){if(!n){i>56319||o+1===e.length?(t[r++]=239,t[r++]=191,t[r++]=189):n=i;continue}if(i<56320){t[r++]=239,t[r++]=191,t[r++]=189,n=i;continue}i=n-55296<<10|i-56320|65536,n=null}else n&&(t[r++]=239,t[r++]=191,t[r++]=189,n=null);i<128?t[r++]=i:(i<2048?t[r++]=i>>6|192:(i<65536?t[r++]=i>>12|224:(t[r++]=i>>18|240,t[r++]=i>>12&63|128),t[r++]=i>>6&63|128),t[r++]=63&i|128)}return r}function Point$1(t,e){this.x=t,this.y=e}function VectorTileFeature$2(t,e,r,i,n){this.properties={},this.extent=r,this.type=0,this._pbf=t,this._geometry=-1,this._keys=i,this._values=n,t.readFields(readFeature,this,e)}function readFeature(t,e,r){1==t?e.id=r.readVarint():2==t?readTag(r,e):3==t?e.type=r.readVarint():4==t&&(e._geometry=r.pos)}function readTag(t,e){for(var r=t.readVarint()+t.pos;t.pos>3;e=1===i?t.readString():2===i?t.readFloat():3===i?t.readDouble():4===i?t.readVarint64():5===i?t.readVarint():6===i?t.readSVarint():7===i?t.readBoolean():null}return e}function VectorTile$1(t,e){this.layers=t.readFields(readTile,{},e)}function readTile(t,e,r){if(3===t){var i=new VectorTileLayer$1(r,r.readVarint()+r.pos);i.length&&(e[i.name]=i)}}!function(t){function e(t){if("string"!=typeof t&&(t=String(t)),/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(t))throw new TypeError("Invalid character in header field name");return t.toLowerCase()}function r(t){return"string"!=typeof t&&(t=String(t)),t}function i(t){var e={next:function(){var e=t.shift();return{done:void 0===e,value:e}}};return v.iterable&&(e[Symbol.iterator]=function(){return e}),e}function n(t){this.map={},t instanceof n?t.forEach(function(t,e){this.append(e,t)},this):Array.isArray(t)?t.forEach(function(t){this.append(t[0],t[1])},this):t&&Object.getOwnPropertyNames(t).forEach(function(e){this.append(e,t[e])},this)}function o(t){if(t.bodyUsed)return Promise.reject(new TypeError("Already read"));t.bodyUsed=!0}function s(t){return new Promise(function(e,r){t.onload=function(){e(t.result)},t.onerror=function(){r(t.error)}})}function a(t){var e=new FileReader,r=s(e);return e.readAsArrayBuffer(t),r}function u(t){var e=new FileReader,r=s(e);return e.readAsText(t),r}function h(t){for(var e=new Uint8Array(t),r=new Array(e.length),i=0;i-1?e:t}function p(t,e){e=e||{};var r=e.body;if(t instanceof p){if(t.bodyUsed)throw new TypeError("Already read");this.url=t.url,this.credentials=t.credentials,e.headers||(this.headers=new n(t.headers)),this.method=t.method,this.mode=t.mode,r||null==t._bodyInit||(r=t._bodyInit,t.bodyUsed=!0)}else this.url=String(t);if(this.credentials=e.credentials||this.credentials||"omit",!e.headers&&this.headers||(this.headers=new n(e.headers)),this.method=f(e.method||this.method||"GET"),this.mode=e.mode||this.mode||null,this.referrer=null,("GET"===this.method||"HEAD"===this.method)&&r)throw new TypeError("Body not allowed for GET or HEAD requests");this._initBody(r)}function d(t){var e=new FormData;return t.trim().split("&").forEach(function(t){if(t){var r=t.split("="),i=r.shift().replace(/\+/g," "),n=r.join("=").replace(/\+/g," ");e.append(decodeURIComponent(i),decodeURIComponent(n))}}),e}function y(t){var e=new n;return t.split(/\r?\n/).forEach(function(t){var r=t.split(":"),i=r.shift().trim();if(i){var n=r.join(":").trim();e.append(i,n)}}),e}function m(t,e){e||(e={}),this.type="default",this.status="status"in e?e.status:200,this.ok=this.status>=200&&this.status<300,this.statusText="statusText"in e?e.statusText:"OK",this.headers=new n(e.headers),this.url=e.url||"",this._initBody(t)}if(!t.fetch){var v={searchParams:"URLSearchParams"in t,iterable:"Symbol"in t&&"iterator"in Symbol,blob:"FileReader"in t&&"Blob"in t&&function(){try{return new Blob,!0}catch(t){return!1}}(),formData:"FormData"in t,arrayBuffer:"ArrayBuffer"in t};if(v.arrayBuffer)var g=["[object Int8Array]","[object Uint8Array]","[object Uint8ClampedArray]","[object Int16Array]","[object Uint16Array]","[object Int32Array]","[object Uint32Array]","[object Float32Array]","[object Float64Array]"],b=function(t){return t&&DataView.prototype.isPrototypeOf(t)},w=ArrayBuffer.isView||function(t){return t&&g.indexOf(Object.prototype.toString.call(t))>-1};n.prototype.append=function(t,i){t=e(t),i=r(i);var n=this.map[t];this.map[t]=n?n+","+i:i},n.prototype.delete=function(t){delete this.map[e(t)]},n.prototype.get=function(t){return t=e(t),this.has(t)?this.map[t]:null},n.prototype.has=function(t){return this.map.hasOwnProperty(e(t))},n.prototype.set=function(t,i){this.map[e(t)]=r(i)},n.prototype.forEach=function(t,e){var r=this;for(var i in this.map)r.map.hasOwnProperty(i)&&t.call(e,r.map[i],i,r)},n.prototype.keys=function(){var t=[];return this.forEach(function(e,r){t.push(r)}),i(t)},n.prototype.values=function(){var t=[];return this.forEach(function(e){t.push(e)}),i(t)},n.prototype.entries=function(){var t=[];return this.forEach(function(e,r){t.push([r,e])}),i(t)},v.iterable&&(n.prototype[Symbol.iterator]=n.prototype.entries);var _=["DELETE","GET","HEAD","OPTIONS","POST","PUT"];p.prototype.clone=function(){return new p(this,{body:this._bodyInit})},c.call(p.prototype),c.call(m.prototype),m.prototype.clone=function(){return new m(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new n(this.headers),url:this.url})},m.error=function(){var t=new m(null,{status:0,statusText:""});return t.type="error",t};var x=[301,302,303,307,308];m.redirect=function(t,e){if(-1===x.indexOf(e))throw new RangeError("Invalid status code");return new m(null,{status:e,headers:{location:t}})},t.Headers=n,t.Request=p,t.Response=m,t.fetch=function(t,e){return new Promise(function(r,i){var n=new p(t,e),o=new XMLHttpRequest;o.onload=function(){var t={status:o.status,statusText:o.statusText,headers:y(o.getAllResponseHeaders()||"")};t.url="responseURL"in o?o.responseURL:t.headers.get("X-Request-URL");var e="response"in o?o.response:o.responseText;r(new m(e,t))},o.onerror=function(){i(new TypeError("Network request failed"))},o.ontimeout=function(){i(new TypeError("Network request failed"))},o.open(n.method,n.url,!0),"include"===n.credentials&&(o.withCredentials=!0),"responseType"in o&&v.blob&&(o.responseType="blob"),n.headers.forEach(function(t,e){o.setRequestHeader(e,t)}),o.send(void 0===n._bodyInit?null:n._bodyInit)})},t.fetch.polyfill=!0}}("undefined"!=typeof self?self:void 0);var read=function(t,e,r,i,n){var o,s,a=8*n-i-1,u=(1<>1,l=-7,c=r?n-1:0,f=r?-1:1,p=t[e+c];for(c+=f,o=p&(1<<-l)-1,p>>=-l,l+=a;l>0;o=256*o+t[e+c],c+=f,l-=8);for(s=o&(1<<-l)-1,o>>=-l,l+=i;l>0;s=256*s+t[e+c],c+=f,l-=8);if(0===o)o=1-h;else{if(o===u)return s?NaN:1/0*(p?-1:1);s+=Math.pow(2,i),o-=h}return(p?-1:1)*s*Math.pow(2,o-i)},write=function(t,e,r,i,n,o){var s,a,u,h=8*o-n-1,l=(1<>1,f=23===n?Math.pow(2,-24)-Math.pow(2,-77):0,p=i?0:o-1,d=i?1:-1,y=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(a=isNaN(e)?1:0,s=l):(s=Math.floor(Math.log(e)/Math.LN2),e*(u=Math.pow(2,-s))<1&&(s--,u*=2),e+=s+c>=1?f/u:f*Math.pow(2,1-c),e*u>=2&&(s++,u/=2),s+c>=l?(a=0,s=l):s+c>=1?(a=(e*u-1)*Math.pow(2,n),s+=c):(a=e*Math.pow(2,c-1)*Math.pow(2,n),s=0));n>=8;t[r+p]=255&a,p+=d,a/=256,n-=8);for(s=s<0;t[r+p]=255&s,p+=d,s/=256,h-=8);t[r+p-d]|=128*y},index$1={read:read,write:write},index=Pbf,ieee754=index$1;Pbf.Varint=0,Pbf.Fixed64=1,Pbf.Bytes=2,Pbf.Fixed32=5;var SHIFT_LEFT_32=4294967296,SHIFT_RIGHT_32=1/SHIFT_LEFT_32;Pbf.prototype={destroy:function(){this.buf=null},readFields:function(t,e,r){var i=this;for(r=r||this.length;this.pos>3,s=i.pos;i.type=7&n,t(o,e,i),i.pos===s&&i.skip(n)}return e},readMessage:function(t,e){return this.readFields(t,e,this.readVarint()+this.pos)},readFixed32:function(){var t=readUInt32(this.buf,this.pos);return this.pos+=4,t},readSFixed32:function(){var t=readInt32(this.buf,this.pos);return this.pos+=4,t},readFixed64:function(){var t=readUInt32(this.buf,this.pos)+readUInt32(this.buf,this.pos+4)*SHIFT_LEFT_32;return this.pos+=8,t},readSFixed64:function(){var t=readUInt32(this.buf,this.pos)+readInt32(this.buf,this.pos+4)*SHIFT_LEFT_32;return this.pos+=8,t},readFloat:function(){var t=ieee754.read(this.buf,this.pos,!0,23,4);return this.pos+=4,t},readDouble:function(){var t=ieee754.read(this.buf,this.pos,!0,52,8);return this.pos+=8,t},readVarint:function(t){var e,r,i=this.buf;return r=i[this.pos++],e=127&r,r<128?e:(r=i[this.pos++],e|=(127&r)<<7,r<128?e:(r=i[this.pos++],e|=(127&r)<<14,r<128?e:(r=i[this.pos++],e|=(127&r)<<21,r<128?e:(r=i[this.pos],e|=(15&r)<<28,readVarintRemainder(e,t,this)))))},readVarint64:function(){return this.readVarint(!0)},readSVarint:function(){var t=this.readVarint();return t%2==1?(t+1)/-2:t/2},readBoolean:function(){return Boolean(this.readVarint())},readString:function(){var t=this.readVarint()+this.pos,e=readUtf8(this.buf,this.pos,t);return this.pos=t,e},readBytes:function(){var t=this.readVarint()+this.pos,e=this.buf.subarray(this.pos,t);return this.pos=t,e},readPackedVarint:function(t,e){var r=this,i=readPackedEnd(this);for(t=t||[];this.pos127;);else if(e===Pbf.Bytes)this.pos=this.readVarint()+this.pos;else if(e===Pbf.Fixed32)this.pos+=4;else{if(e!==Pbf.Fixed64)throw new Error("Unimplemented type: "+e);this.pos+=8}},writeTag:function(t,e){this.writeVarint(t<<3|e)},realloc:function(t){for(var e=this.length||16;e268435455||t<0)return void writeBigVarint(t,this);this.realloc(4),this.buf[this.pos++]=127&t|(t>127?128:0),t<=127||(this.buf[this.pos++]=127&(t>>>=7)|(t>127?128:0),t<=127||(this.buf[this.pos++]=127&(t>>>=7)|(t>127?128:0),t<=127||(this.buf[this.pos++]=t>>>7&127)))},writeSVarint:function(t){this.writeVarint(t<0?2*-t-1:2*t)},writeBoolean:function(t){this.writeVarint(Boolean(t))},writeString:function(t){t=String(t),this.realloc(4*t.length),this.pos++;var e=this.pos;this.pos=writeUtf8(this.buf,t,this.pos);var r=this.pos-e;r>=128&&makeRoomForExtraLength(e,r,this),this.pos=e-1,this.writeVarint(r),this.pos+=r},writeFloat:function(t){this.realloc(4),ieee754.write(this.buf,t,this.pos,!0,23,4),this.pos+=4},writeDouble:function(t){this.realloc(8),ieee754.write(this.buf,t,this.pos,!0,52,8),this.pos+=8},writeBytes:function(t){var e=this,r=t.length;this.writeVarint(r),this.realloc(r);for(var i=0;i=128&&makeRoomForExtraLength(r,i,this),this.pos=r-1,this.writeVarint(i),this.pos+=i},writeMessage:function(t,e,r){this.writeTag(t,Pbf.Bytes),this.writeRawMessage(e,r)},writePackedVarint:function(t,e){this.writeMessage(t,writePackedVarint,e)},writePackedSVarint:function(t,e){this.writeMessage(t,writePackedSVarint,e)},writePackedBoolean:function(t,e){this.writeMessage(t,writePackedBoolean,e)},writePackedFloat:function(t,e){this.writeMessage(t,writePackedFloat,e)},writePackedDouble:function(t,e){this.writeMessage(t,writePackedDouble,e)},writePackedFixed32:function(t,e){this.writeMessage(t,writePackedFixed32,e)},writePackedSFixed32:function(t,e){this.writeMessage(t,writePackedSFixed32,e)},writePackedFixed64:function(t,e){this.writeMessage(t,writePackedFixed64,e)},writePackedSFixed64:function(t,e){this.writeMessage(t,writePackedSFixed64,e)},writeBytesField:function(t,e){this.writeTag(t,Pbf.Bytes),this.writeBytes(e)},writeFixed32Field:function(t,e){this.writeTag(t,Pbf.Fixed32),this.writeFixed32(e)},writeSFixed32Field:function(t,e){this.writeTag(t,Pbf.Fixed32),this.writeSFixed32(e)},writeFixed64Field:function(t,e){this.writeTag(t,Pbf.Fixed64),this.writeFixed64(e)},writeSFixed64Field:function(t,e){this.writeTag(t,Pbf.Fixed64),this.writeSFixed64(e)},writeVarintField:function(t,e){this.writeTag(t,Pbf.Varint),this.writeVarint(e)},writeSVarintField:function(t,e){this.writeTag(t,Pbf.Varint),this.writeSVarint(e)},writeStringField:function(t,e){this.writeTag(t,Pbf.Bytes),this.writeString(e)},writeFloatField:function(t,e){this.writeTag(t,Pbf.Fixed32),this.writeFloat(e)},writeDoubleField:function(t,e){this.writeTag(t,Pbf.Fixed64),this.writeDouble(e)},writeBooleanField:function(t,e){this.writeVarintField(t,Boolean(e))}};var index$5=Point$1;Point$1.prototype={clone:function(){return new Point$1(this.x,this.y)},add:function(t){return this.clone()._add(t)},sub:function(t){return this.clone()._sub(t)},mult:function(t){return this.clone()._mult(t)},div:function(t){return this.clone()._div(t)},rotate:function(t){return this.clone()._rotate(t)},matMult:function(t){return this.clone()._matMult(t)},unit:function(){return this.clone()._unit()},perp:function(){return this.clone()._perp()},round:function(){return this.clone()._round()},mag:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},equals:function(t){return this.x===t.x&&this.y===t.y},dist:function(t){return Math.sqrt(this.distSqr(t))},distSqr:function(t){var e=t.x-this.x,r=t.y-this.y;return e*e+r*r},angle:function(){return Math.atan2(this.y,this.x)},angleTo:function(t){return Math.atan2(this.y-t.y,this.x-t.x)},angleWith:function(t){return this.angleWithSep(t.x,t.y)},angleWithSep:function(t,e){return Math.atan2(this.x*e-this.y*t,this.x*t+this.y*e)},_matMult:function(t){var e=t[0]*this.x+t[1]*this.y,r=t[2]*this.x+t[3]*this.y;return this.x=e,this.y=r,this},_add:function(t){return this.x+=t.x,this.y+=t.y,this},_sub:function(t){return this.x-=t.x,this.y-=t.y,this},_mult:function(t){return this.x*=t,this.y*=t,this},_div:function(t){return this.x/=t,this.y/=t,this},_unit:function(){return this._div(this.mag()),this},_perp:function(){var t=this.y;return this.y=this.x,this.x=-t,this},_rotate:function(t){var e=Math.cos(t),r=Math.sin(t),i=e*this.x-r*this.y,n=r*this.x+e*this.y;return this.x=i,this.y=n,this},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this}},Point$1.convert=function(t){return t instanceof Point$1?t:Array.isArray(t)?new Point$1(t[0],t[1]):t};var Point=index$5,vectortilefeature=VectorTileFeature$2;VectorTileFeature$2.types=["Unknown","Point","LineString","Polygon"],VectorTileFeature$2.prototype.loadGeometry=function(){var t=this._pbf;t.pos=this._geometry;for(var e,r=t.readVarint()+t.pos,i=1,n=0,o=0,s=0,a=[];t.pos>3}if(n--,1===i||2===i)o+=t.readSVarint(),s+=t.readSVarint(),1===i&&(e&&a.push(e),e=[]),e.push(new Point(o,s));else{if(7!==i)throw new Error("unknown command "+i);e&&e.push(e[0].clone())}}return e&&a.push(e),a},VectorTileFeature$2.prototype.bbox=function(){var t=this._pbf;t.pos=this._geometry;for(var e=t.readVarint()+t.pos,r=1,i=0,n=0,o=0,s=1/0,a=-1/0,u=1/0,h=-1/0;t.pos>3}if(i--,1===r||2===r)n+=t.readSVarint(),o+=t.readSVarint(),na&&(a=n),oh&&(h=o);else if(7!==r)throw new Error("unknown command "+r)}return[s,u,a,h]},VectorTileFeature$2.prototype.toGeoJSON=function(t,e,r){function i(t){for(var e=0;e=this._features.length)throw new Error("feature index out of bounds");this._pbf.pos=this._features[t];var e=this._pbf.readVarint()+this._pbf.pos;return new VectorTileFeature$1(this._pbf,e,this.extent,this._keys,this._values)};var VectorTileLayer$1=vectortilelayer,vectortile=VectorTile$1,VectorTile=vectortile;L.SVG.Tile=L.SVG.extend({initialize:function(t,e,r){L.SVG.prototype.initialize.call(this,r),this._tileCoord=t,this._size=e,this._initContainer(),this._container.setAttribute("width",this._size.x),this._container.setAttribute("height",this._size.y),this._container.setAttribute("viewBox",[0,0,this._size.x,this._size.y].join(" ")),this._layers={}},getCoord:function(){return this._tileCoord},getContainer:function(){return this._container},onAdd:L.Util.falseFn,addTo:function(t){if(this._map=t,this.options.interactive)for(var e in this._layers){var r=this._layers[e];r._path.style.pointerEvents="auto",this._map._targets[L.stamp(r._path)]=r}},removeFrom:function(t){if(this.options.interactive)for(var e in this._layers){var r=this._layers[e];delete this._map._targets[L.stamp(r._path)]}delete this._map},_initContainer:function(){L.SVG.prototype._initContainer.call(this);L.SVG.create("rect")},_addPath:function(t){this._rootGroup.appendChild(t._path),this._layers[L.stamp(t)]=t},_updateIcon:function(t){var e=t._path=L.SVG.create("image"),r=t.options.icon,i=r.options,n=L.point(i.iconSize),o=i.iconAnchor||n&&n.divideBy(2,!0),s=t._point.subtract(o);e.setAttribute("x",s.x),e.setAttribute("y",s.y),e.setAttribute("width",n.x+"px"),e.setAttribute("height",n.y+"px"),e.setAttribute("href",i.iconUrl)}}),L.svg.tile=function(t,e,r){return new L.SVG.Tile(t,e,r)};var Symbolizer=L.Class.extend({render:function(t,e){this._renderer=t,this.options=e,t._initPath(this),t._updateStyle(this)},updateStyle:function(t,e){this.options=e,t._updateStyle(this)},_getPixelBounds:function(){for(var t=this._parts,e=L.bounds([]),r=0;rn&&(i=r,n=o);n>a?(e[i][2]=n,c.push(l),c.push(i),l=i):(u=c.pop(),l=c.pop())}}function getSqSegDist(e,t,r){var n=t[0],o=t[1],i=r[0],a=r[1],s=e[0],l=e[1],u=i-n,c=a-o;if(0!==u||0!==c){var f=((s-n)*u+(l-o)*c)/(u*u+c*c);f>1?(n=i,o=a):f>0&&(n+=u*f,o+=c*f)}return u=s-n,c=l-o,u*u+c*c}function convert$1(e,t){var r=[];if("FeatureCollection"===e.type)for(var n=0;n1?1:n,[r,n,0]}function calcSize(e){for(var t,r,n=0,o=0,i=0;i=r&&s<=n)return e;if(a>n||s=r&&f<=n)l.push(p);else if(!(c>n||f=t&&s<=r&&o.push(a)}return o}function clipGeometry(e,t,r,n,o,i){for(var a=[],s=0;sr?(x.push(o(l,h,t),o(l,h,r)),i||(x=newSlice(a,x,g,d,v))):p>=t&&x.push(o(l,h,t)):f>r?pr&&(x.push(o(l,h,r)),i||(x=newSlice(a,x,g,d,v))));l=m[y-1],f=l[n],f>=t&&f<=r&&x.push(l),c=x[x.length-1],i&&c&&(x[0][0]!==c[0]||x[0][1]!==c[1])&&x.push(x[0]),newSlice(a,x,g,d,v)}return a}function newSlice(e,t,r,n,o){return t.length&&(t.area=r,t.dist=n,void 0!==o&&(t.outer=o),e.push(t)),[]}function wrap$1(e,t,r){var n=e,o=clip$2(e,1,-1-t,t,0,r,-1,2),i=clip$2(e,1,1-t,2+t,0,r,-1,2);return(o||i)&&(n=clip$2(e,1,-t,1+t,0,r,-1,2),o&&(n=shiftFeatureCoords(o,1).concat(n)),i&&(n=n.concat(shiftFeatureCoords(i,-1)))),n}function shiftFeatureCoords(e,t){for(var r=[],n=0;na.max[0]&&(a.max[0]=u[0]),u[1]>a.max[1]&&(a.max[1]=u[1])}return a}function addFeature(e,t,r,n){var o,i,a,s,l=t.geometry,u=t.type,c=[],f=r*r;if(1===u)for(o=0;of)&&(p.push(s),e.numSimplified++),e.numPoints++;3===u&&rewind(p,a.outer),c.push(p)}else e.numPoints+=a.length;c.length&&e.features.push({geometry:c,type:u,tags:t.tags||null})}function rewind(e,t){signedArea(e)<0===t&&e.reverse()}function signedArea(e){for(var t,r,n=0,o=0,i=e.length,a=i-1;o1)return!1;var i=o.geometry[0].length;if(5!==i)return!1;for(var a=0;a1&&console.time("creation"),m=s.tiles[h]=createTile(e,p,r,n,g,t===u.maxZoom),s.tileCoords.push({z:t,x:r,y:n}),c)){c>1&&(console.log("tile z%d-%d-%d (features: %d, points: %d, simplified: %d)",t,r,n,m.numFeatures,m.numPoints,m.numSimplified),console.timeEnd("creation"));var d="z"+t;s.stats[d]=(s.stats[d]||0)+1,s.total++}if(m.source=e,o){if(t===u.maxZoom||t===o)continue;var v=1<1&&console.time("clipping");var y,x,b,M,P,S,w=.5*u.buffer/u.extent,$=.5-w,C=.5+w,F=1+w;y=x=b=M=null,P=clip(e,p,r-w,r+C,0,intersectX,m.min[0],m.max[0]),S=clip(e,p,r+$,r+F,0,intersectX,m.min[0],m.max[0]),P&&(y=clip(P,p,n-w,n+C,1,intersectY,m.min[1],m.max[1]),x=clip(P,p,n+$,n+F,1,intersectY,m.min[1],m.max[1])),S&&(b=clip(S,p,n-w,n+C,1,intersectY,m.min[1],m.max[1]),M=clip(S,p,n+$,n+F,1,intersectY,m.min[1],m.max[1])),c>1&&console.timeEnd("clipping"),y&&l.push(y,t+1,2*r,2*n),x&&l.push(x,t+1,2*r,2*n+1),b&&l.push(b,t+1,2*r+1,2*n),M&&l.push(M,t+1,2*r+1,2*n+1)}else o&&(f=t)}return f},GeoJSONVT.prototype.getTile=function(e,t,r){var n=this,o=this.options,i=o.extent,a=o.debug,s=1<1&&console.log("drilling down to z%d-%d-%d",e,t,r);for(var u,c=e,f=t,p=r;!u&&c>0;)c--,f=Math.floor(f/2),p=Math.floor(p/2),u=n.tiles[toID(c,f,p)];if(!u||!u.source)return null;if(a>1&&console.log("found parent tile z%d-%d-%d",c,f,p),isClippedSquare(u,i,o.buffer))return transform.tile(u,i);a>1&&console.time("drilling down");var h=this.splitTile(u.source,c,f,p,e,t,r);if(a>1&&console.timeEnd("drilling down"),null!==h){var m=1<c&&(c=s[0]),s[1]f&&(f=s[1])}function r(e){switch(e.type){case"GeometryCollection":e.geometries.forEach(r);break;case"Point":t(e.coordinates);break;case"MultiPoint":e.coordinates.forEach(t)}}var n=e.bbox;if(!n){var o,i,a=transform$3(e),s=new Array(2),l=1/0,u=l,c=-l,f=-l;e.arcs.forEach(function(e){for(var t=-1,r=e.length;++tc&&(c=s[0]),s[1]f&&(f=s[1])});for(i in e.objects)r(e.objects[i]);n=e.bbox=[l,u,c,f]}return n},reverse=function(e,t){for(var r,n=e.length,o=n-t;o<--n;)r=e[o],e[o++]=e[n],e[n]=r},feature=function(e,t){return"GeometryCollection"===t.type?{type:"FeatureCollection",features:t.geometries.map(function(t){return feature$1(e,t)})}:feature$1(e,t)},stitch=function(e,t){function r(t){var r,n=e.arcs[t<0?~t:t],o=n[0];return e.transform?(r=[0,0],n.forEach(function(e){r[0]+=e[0],r[1]+=e[1]})):r=n[n.length-1],t<0?[r,o]:[o,r]}function n(e,t){for(var r in e){var n=e[r];delete t[n.start],delete n.start,delete n.end,n.forEach(function(e){o[e<0?~e:e]=1}),s.push(n)}}var o={},i={},a={},s=[],l=-1;return t.forEach(function(r,n){var o,i=e.arcs[r<0?~r:r];i.length<3&&!i[1][0]&&!i[1][1]&&(o=t[++l],t[l]=r,t[n]=o)}),t.forEach(function(e){var t,n,o=r(e),s=o[0],l=o[1];if(t=a[s])if(delete a[t.end],t.push(e),t.end=l,n=i[l]){delete i[n.start];var u=n===t?t:t.concat(n);i[u.start=t.start]=a[u.end=n.end]=u}else i[t.start]=a[t.end]=t;else if(t=i[l])if(delete i[t.start],t.unshift(e),t.start=s,n=a[s]){delete a[n.end];var c=n===t?t:n.concat(t);i[c.start=n.start]=a[c.end=t.end]=c}else i[t.start]=a[t.end]=t;else t=[e],i[t.start=s]=a[t.end=l]=t}),n(a,i),n(i,a),t.forEach(function(e){o[e<0?~e:e]||s.push([e])}),s},bisect=function(e,t){for(var r=0,n=e.length;r>>1;e[o]splitted_url[1]) && $controller->splitted_url[1] != '') { else { // Chargement de la carte et des dépendances Leaflet. $head['title'] = "Carte"; - $head['third'] = "leaflet/leaflet.js;leaflet-fullscreen/Leaflet.fullscreen.min.js;leaflet-easybutton/easy-button.js"; + $head['third'] = "leaflet/leaflet.js;leaflet-fullscreen/Leaflet.fullscreen.min.js;leaflet-easybutton/easy-button.js;leaflet-vectorgrid/Leaflet.VectorGrid.bundled.min.js"; $head['css'] .= ";d.map.css;../third/leaflet/leaflet.css;../third/leaflet-fullscreen/leaflet.fullscreen.css;../third/leaflet-easybutton/easy-button.css"; $head['js'] = "d.map.js"; diff --git a/src/Controllers/d.poi.php b/src/Controllers/d.poi.php index 6c23be5..e92ac7e 100755 --- a/src/Controllers/d.poi.php +++ b/src/Controllers/d.poi.php @@ -146,6 +146,18 @@ switch ($controller->splitted_url[1]) { echo json_encode($out, JSON_UNESCAPED_UNICODE); break; + case "tile": + $z = intval($controller->splitted_url[2]); + $x = intval($controller->splitted_url[3]); + $y = intval(str_replace(".pbf","",$controller->splitted_url[4])); + + $pois = new Kabano\Pois(); + + header("Content-Type: application/x-protobuf"); + + echo $pois->getVectorTile($z,$x,$y); + break; + default: // Affichage / édition / suppression d’un POI if ($poi->checkPermalink($controller->splitted_url[1], $user->rankIsHigher("premium"))) { diff --git a/src/Models/d.poi.php b/src/Models/d.poi.php index 6142855..3bcfffb 100755 --- a/src/Models/d.poi.php +++ b/src/Models/d.poi.php @@ -60,73 +60,72 @@ class Poi ** Checks if a page at this URL exists and return the ID *****/ public function checkPermalink($permalink, $withArchive=0, $elementNb=0) { - global $config; // Récupère la dernière version du POI. $con = sql_connect(); - $query = "SELECT - content_versions.id AS version_id, - content_versions.version, - content_versions.update_date, - content_versions.is_archive, - content_versions.name, - content_versions.content AS parameters, + $query = "SELECT + content_versions.id AS version_id, + content_versions.version, + content_versions.update_date, + content_versions.is_archive, + content_versions.name, + content_versions.content AS parameters, - contents.id AS content_id, - contents.permalink, - contents.creation_date, - contents.is_public, - contents.is_commentable, - contents.type, - contents.poi_type, + contents.id AS content_id, + contents.permalink, + contents.creation_date, + contents.is_public, + contents.is_commentable, + contents.type, + contents.poi_type, - content_locales.id AS locale_id, - content_locales.locale, - content_locales.author, + content_locales.id AS locale_id, + content_locales.locale, + content_locales.author, - specs.source_id, - specs.remote_source_id, - ST_X(specs.geom) AS lon, - ST_Y(specs.geom) AS lat, - ST_Z(specs.geom) AS ele, + specs.source_id, + specs.remote_source_id, + ST_X(specs.geom) AS lon, + ST_Y(specs.geom) AS lat, + ST_Z(specs.geom) AS ele, - sources.display_name AS source + sources.display_name AS source - FROM contents - INNER JOIN content_locales - ON contents.id = content_locales.content_id - INNER JOIN content_versions - ON content_locales.id = content_versions.locale_id - LEFT JOIN content_version_poi_specifications specs - ON specs.content_version_id = content_versions.id - LEFT JOIN sources - ON sources.id = specs.source_id + FROM contents + INNER JOIN content_locales + ON contents.id = content_locales.content_id + INNER JOIN content_versions + ON content_locales.id = content_versions.locale_id + LEFT JOIN content_version_poi_specifications specs + ON specs.content_version_id = content_versions.id + LEFT JOIN sources + ON sources.id = specs.source_id - WHERE contents.permalink = $1 - AND contents.type = 'poi'"; + WHERE contents.permalink = $1 + AND contents.type = 'poi'"; - if ($withArchive == 0) { - $query .= " AND content_versions.is_archive = FALSE AND contents.is_public = TRUE"; - } + if ($withArchive == 0) { + $query .= " AND content_versions.is_archive = FALSE AND contents.is_public = TRUE"; + } - $query .= " ORDER BY content_versions.update_date DESC LIMIT 1 OFFSET $2"; + $query .= " ORDER BY content_versions.update_date DESC LIMIT 1 OFFSET $2"; - pg_prepare($con, "poi_check_permalink", $query) - or die ("Cannot prepare statement\n"); + pg_prepare($con, "poi_check_permalink", $query) + or die ("Cannot prepare statement\n"); - $result = pg_execute($con, "poi_check_permalink", [$permalink, $elementNb]) - or die ("Cannot execute statement\n"); + $result = pg_execute($con, "poi_check_permalink", [$permalink, $elementNb]) + or die ("Cannot execute statement\n"); - pg_close($con); + pg_close($con); - if (pg_num_rows($result) == 1) { - $row = pg_fetch_assoc($result); - $this->populate($row); - return 1; - } + if (pg_num_rows($result) == 1) { + $row = pg_fetch_assoc($result); + $this->populate($row); + return 1; + } - return 0; + return 0; } /***** @@ -215,7 +214,6 @@ class Poi ** Create a new poi *****/ public function insert() { - global $config; global $user; // Création d'un nouveau POI. @@ -284,7 +282,6 @@ class Poi ** Edit a POI by archiving the current version and inserting a new one *****/ public function update() { - global $config; global $user; // Vérifie que les identifiants sont chargés. @@ -345,7 +342,6 @@ class Poi ** Archive a POI *****/ public function delete() { - global $config; global $user; // Archivage logique du POI. @@ -369,7 +365,6 @@ class Poi ** Restore a POI *****/ public function restore() { - global $config; global $user; // Restauration d'un POI archivé. @@ -398,59 +393,58 @@ class Pois // Liste des POIs publiés (ou archivés si demandé). public function listPoisBBOX($n,$s,$e,$w,$archive=0) { - global $config; // Chargement des POIs avec leurs versions actives. $con = sql_connect(); $query = "SELECT - content_versions.id AS version_id, - content_versions.version, - content_versions.update_date, - content_versions.is_archive, - content_versions.name, - content_versions.content AS parameters, + content_versions.id AS version_id, + content_versions.version, + content_versions.update_date, + content_versions.is_archive, + content_versions.name, + content_versions.content AS parameters, - contents.id AS content_id, - contents.permalink, - contents.creation_date, - contents.is_public, - contents.is_commentable, - contents.type, - contents.poi_type, + contents.id AS content_id, + contents.permalink, + contents.creation_date, + contents.is_public, + contents.is_commentable, + contents.type, + contents.poi_type, - content_locales.id AS locale_id, - content_locales.locale, - content_locales.author, + content_locales.id AS locale_id, + content_locales.locale, + content_locales.author, - specs.source_id, - specs.remote_source_id, - ST_X(specs.geom) AS lon, - ST_Y(specs.geom) AS lat, - ST_Z(specs.geom) AS ele, + specs.source_id, + specs.remote_source_id, + ST_X(specs.geom) AS lon, + ST_Y(specs.geom) AS lat, + ST_Z(specs.geom) AS ele, - sources.display_name AS source + sources.display_name AS source - FROM contents - INNER JOIN content_locales - ON contents.id = content_locales.content_id - INNER JOIN content_versions - ON content_locales.id = content_versions.locale_id - LEFT JOIN content_version_poi_specifications specs - ON specs.content_version_id = content_versions.id - LEFT JOIN sources - ON sources.id = specs.source_id + FROM contents + INNER JOIN content_locales + ON contents.id = content_locales.content_id + INNER JOIN content_versions + ON content_locales.id = content_versions.locale_id + LEFT JOIN content_version_poi_specifications specs + ON specs.content_version_id = content_versions.id + LEFT JOIN sources + ON sources.id = specs.source_id - WHERE contents.type = 'poi' - AND content_versions.is_archive = FALSE - AND specs.geom && ST_MakeEnvelope( - $1, - $2, - $3, - $4, - 4326 - ) - "; + WHERE contents.type = 'poi' + 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 "; @@ -469,52 +463,104 @@ class Pois } } + public function getVectorTile($z, $x, $y) + { + $con = sql_connect(); + pg_query($con, "SET jit=off"); + + $sql = "WITH tile AS ( SELECT + ST_TileEnvelope($1, $2, $3) AS tile_geom + ), + + mvtgeom AS ( SELECT CAST(contents.id AS integer) AS id, + contents.poi_type::text AS poi_type, + contents.permalink::text AS permalink, + ST_AsMVTGeom( ST_Transform( + specs.geom, + 3857 + ), + tile.tile_geom, 4096, 64, true ) AS geom + FROM content_version_poi_specifications specs + INNER JOIN content_versions + ON specs.content_version_id = content_versions.id + INNER JOIN content_locales + ON content_versions.locale_id = content_locales.id + INNER JOIN contents + ON content_locales.content_id = contents.id + CROSS JOIN tile + + WHERE contents.type = 'poi' + AND specs.geom IS NOT NULL + AND ST_Transform(specs.geom, 3857) && tile.tile_geom + ) + SELECT ST_AsMVT( mvtgeom, 'pois', 4096, 'geom' ) + FROM mvtgeom + WHERE geom IS NOT NULL"; + + $result = pg_query_params( + $con, + $sql, + [$z, $x, $y] + ); + + if (!$result) { + throw new \Exception( + pg_last_error($con) + ); + } + + $row = pg_fetch_row($result); + + pg_close($con); + + return pg_unescape_bytea($row[0]); + } + public function getHistory($permalink) { - global $config; // Historique des versions d'un POI. $con = sql_connect(); $query = "SELECT - content_versions.id AS version_id, - content_versions.version, - content_versions.update_date, - content_versions.is_archive, - content_versions.name, - content_versions.content AS parameters, + content_versions.id AS version_id, + content_versions.version, + content_versions.update_date, + content_versions.is_archive, + content_versions.name, + content_versions.content AS parameters, - contents.id AS content_id, - contents.permalink, - contents.creation_date, - contents.is_public, - contents.is_commentable, - contents.type, - contents.poi_type, + contents.id AS content_id, + contents.permalink, + contents.creation_date, + contents.is_public, + contents.is_commentable, + contents.type, + contents.poi_type, - content_locales.id AS locale_id, - content_locales.locale, - content_locales.author, + content_locales.id AS locale_id, + content_locales.locale, + content_locales.author, - specs.source_id, - specs.remote_source_id, - ST_X(specs.geom) AS lon, - ST_Y(specs.geom) AS lat, - ST_Z(specs.geom) AS ele, + specs.source_id, + specs.remote_source_id, + ST_X(specs.geom) AS lon, + ST_Y(specs.geom) AS lat, + ST_Z(specs.geom) AS ele, - sources.display_name AS source + sources.display_name AS source - FROM contents - INNER JOIN content_locales - ON contents.id = content_locales.content_id - INNER JOIN content_versions - ON content_locales.id = content_versions.locale_id - LEFT JOIN content_version_poi_specifications specs - ON specs.content_version_id = content_versions.id - LEFT JOIN sources - ON sources.id = specs.source_id + FROM contents + INNER JOIN content_locales + ON contents.id = content_locales.content_id + INNER JOIN content_versions + ON content_locales.id = content_versions.locale_id + LEFT JOIN content_version_poi_specifications specs + ON specs.content_version_id = content_versions.id + LEFT JOIN sources + ON sources.id = specs.source_id - WHERE contents.permalink = $1 - AND contents.type = 'poi' + WHERE contents.permalink = $1 + AND contents.type = 'poi' ORDER BY content_versions.update_date DESC ";