createLayer function
KubaLorenc opened this issue · 3 comments
Describe the problem
In esri-leaflet, when we create tile using esriLeaflet.tiledMapLayer({options}), we can actually override the createTile function and for example fetch data from local storage instead of api. Unfortunatelly I don't see how we could do that with esri-leaflet-vector, since esriLeaflet.vectorTileLayer() doesn't seem to trigger createTile . Is there any equivalent of createTile for the VectorTileLayer class?
Describe the proposed solution
Solution would be to provide info of what function is triggered to fetch data from api
Edit:
there is a thread on maplibre github concernig this problem: maplibre/maplibre-gl-js#29
I tried to wire that into the MaplibreGLJSLayer in _initGL function but with little luck
_initGL: function() {
var center = this._map.getCenter();
var options = extend({}, this.options, {
container: this._container,
center: [center.lng, center.lat],
zoom: this._map.getZoom() - 1,
attributionControl: false
});
maplibreGl.addProtocol('custom', (params, callback) => {
fetch('https://${params.url.split('://')[1]}')
.then(t => {
if (t.status == 200) {
t.arrayBuffer().then(arr => {
callback(null, arr, null, null);
});
} else {
callback(new Error('Tile fetch error: ${t.statusText}'));
}
})
.catch(e => {
callback(new Error(e));
});
return { cancel: () => {} };
});
this._glMap = new maplibregl.Map({
container: this._container,
style: {
version: 8,
sources: options.style.sources,
layers: options.style.layers,
sprite: options.style.sprite,
glyphs: options.style.glyphs
},
center: options.center,
zoom: 13,
minZoom: 13,
maxZoom: 13
});
let map = this._glMap;
map.on('load', () => {
map.addSource('test-source', {
type: 'vector',
tiles: [
'custom://basemaps.arcgis.com/arcgis/rest/services/OpenStreetMap_v2/VectorTileServer/tile/{z}/{y}/{x}.pbf'
],
minzoom: 13,
maxzoom: 13,
format: 'pbf'
});
map.addLayer({
id: 'test-layer',
type: 'circle',
source: 'test-source',
'source-layer': 'mapillary-images',
paint: {
'circle-radius': 10,
'circle-color': '#ff0000'
}
});
});
this._glMap.once(
'styledata',
function(res) {
this.fire('styleLoaded');
}.bind(this)
);
this._glMap.transform.latRange = null;
this._glMap.transform.maxValidLatitude = Infinity;
this._transformGL(this._glMap);
if (this._glMap._canvas.canvas) {
this._glMap._actualCanvas = this._glMap._canvas.canvas;
} else {
this._glMap._actualCanvas = this._glMap._canvas;
}
var canvas = this._glMap._actualCanvas;
DomUtil.addClass(canvas, 'leaflet-image-layer');
DomUtil.addClass(canvas, 'leaflet-zoom-animated');
if (this.options.interactive) {
DomUtil.addClass(canvas, 'leaflet-interactive');
}
if (this.options.className) {
DomUtil.addClass(canvas, this.options.className);
}
}
Alternatives considered
No response
Additional Information
No response
@KubaLorenc I think we need to decide what the use case for this is. The purpose of L.esri.vectorTileLayer
is specially to communicate with Vector tile services hosted in ArcGIS. Loading data from somewhere like local storage doesn't interact with the service and might be beyond the scope of what we need to handle in this plugin.
It also might be possible to achieve the same thing with ServiceWorkers which could intercept the network requests.
@patrickarlt @dpraimeyuu @axelio Hi, thanks for your reply:)
I wondered because from what I understand esri-leaflet-vector delegates communication with ArcGIS to maplibre. And since we would rather not use SW for this offline functionality we thought that introducing some hook to intercept the communication with ArcGis would be the best and cleanest solution. I also think that this would be quite usefull functionality. So, my question is if you could provide me with some tips/ideas how to achieve this? This is already mentioned in some issues on maplibre-gl-js and since you are using maplibre in your solution i thought maybe there is a chance you could include it in your library.
maplibre/maplibre-gl-js#207 (comment)
mapbox/mapbox-gl-js#2920 (comment)
maplibre/maplibre-gl-js#29
@KubaLorenc it seems like in maplibre/maplibre-gl-js#207 (comment) it was recommended to solve the problem of tile access offline with a ServiceWorker. Looking at your code I don't really see any reason why it shouldn't work. Without a specific example or error messages I don't have much to go on.
The main benefit of using a ServiceWorker would be that Service workers are designed to transparently intercept and modify network requests which is exactly what you want to do:
- Cache tile responses in localstorage
- Intercept tile requests and serve them from localstorage
I don't think anything would be required in this library if you used ServiceWorkers to do this.