From 1d5067de7c570bc364a39dd815f57807fd84bbab Mon Sep 17 00:00:00 2001 From: Silver Vesi Date: Mon, 3 Mar 2025 14:47:06 +0200 Subject: [PATCH] Add error handling to fetching tiles Handles errors when fetching the tiles fails, also triggers a tileerror event so the initial caller knows it has failed. --- src/Leaflet.VectorGrid.Protobuf.js | 15 ++-- src/Leaflet.VectorGrid.js | 140 ++++++++++++++--------------- 2 files changed, 79 insertions(+), 76 deletions(-) diff --git a/src/Leaflet.VectorGrid.Protobuf.js b/src/Leaflet.VectorGrid.Protobuf.js index 4c34f7a..ba2aeb9 100644 --- a/src/Leaflet.VectorGrid.Protobuf.js +++ b/src/Leaflet.VectorGrid.Protobuf.js @@ -96,7 +96,7 @@ L.VectorGrid.Protobuf = L.VectorGrid.extend({ var currentZoom = zoom === coords.z; var tileBounds = this._tileCoordsToBounds(coords); - var currentBounds = this._map.getBounds().overlaps(tileBounds); + var currentBounds = this._map.getBounds().overlaps(tileBounds); return currentZoom && currentBounds; @@ -127,13 +127,14 @@ L.VectorGrid.Protobuf = L.VectorGrid.extend({ return fetch(tileUrl, this.options.fetchOptions).then(function(response){ if (!response.ok || !this._isCurrentTile(coords)) { - return {layers:[]}; - } + throw new Error('Failed to fetch tile: HTTP response ' + response.status + + ' ' + response.statusText); + } - return response.blob().then( function (blob) { + return response.blob().then(function (blob) { var reader = new FileReader(); - return new Promise(function(resolve){ + return new Promise(function(resolve, reject){ reader.addEventListener("loadend", function() { // reader.result contains the contents of blob as a typed array // blob.type === 'application/x-protobuf' @@ -141,6 +142,8 @@ L.VectorGrid.Protobuf = L.VectorGrid.extend({ return resolve(new VectorTile( pbf )); }); + reader.addEventListener("error", reject); + reader.addEventListener("abort", reject); reader.readAsArrayBuffer(blob); }); }); @@ -161,6 +164,8 @@ L.VectorGrid.Protobuf = L.VectorGrid.extend({ } return json; + }).catch(function (err) { + console.log(err); }); } }); diff --git a/src/Leaflet.VectorGrid.js b/src/Leaflet.VectorGrid.js index 6ad3b46..6b8b86e 100644 --- a/src/Leaflet.VectorGrid.js +++ b/src/Leaflet.VectorGrid.js @@ -67,7 +67,7 @@ L.VectorGrid = L.GridLayer.extend({ var tileSize = this.getTileSize(); var renderer = this.options.rendererFactory(coords, tileSize, this.options); - var tileBounds = this._tileCoordsToBounds(coords); + var tileBounds = this._tileCoordsToBounds(coords); var vectorTilePromise = this._getVectorTilePromise(coords, tileBounds); @@ -76,87 +76,85 @@ L.VectorGrid = L.GridLayer.extend({ renderer._features = {}; } - vectorTilePromise.then( function renderTile(vectorTile) { - - if (vectorTile.layers && vectorTile.layers.length !== 0) { - - for (var layerName in vectorTile.layers) { - this._dataLayerNames[layerName] = true; - var layer = vectorTile.layers[layerName]; - - var pxPerExtent = this.getTileSize().divideBy(layer.extent); - - var layerStyle = this.options.vectorTileLayerStyles[ layerName ] || - L.Path.prototype.options; - - for (var i = 0; i < layer.features.length; i++) { - var feat = layer.features[i]; - var id; - - if (this.options.filter instanceof Function && - !this.options.filter(feat.properties, coords.z)) { - continue; - } + vectorTilePromise.then(function renderTile(vectorTile) { + if (!vectorTile) { + this.fire('tileerror'); + return; + } + for (var layerName in vectorTile.layers) { + this._dataLayerNames[layerName] = true; + var layer = vectorTile.layers[layerName]; + + var pxPerExtent = this.getTileSize().divideBy(layer.extent); + + var layerStyle = this.options.vectorTileLayerStyles[ layerName ] || + L.Path.prototype.options; + + for (var i = 0; i < layer.features.length; i++) { + var feat = layer.features[i]; + var id; + + if (this.options.filter instanceof Function && + !this.options.filter(feat.properties, coords.z)) { + continue; + } - var styleOptions = layerStyle; - if (storeFeatures) { - id = this.options.getFeatureId(feat); - var styleOverride = this._overriddenStyles[id]; - if (styleOverride) { - if (styleOverride[layerName]) { - styleOptions = styleOverride[layerName]; - } else { - styleOptions = styleOverride; - } + var styleOptions = layerStyle; + if (storeFeatures) { + id = this.options.getFeatureId(feat); + var styleOverride = this._overriddenStyles[id]; + if (styleOverride) { + if (styleOverride[layerName]) { + styleOptions = styleOverride[layerName]; + } else { + styleOptions = styleOverride; } } - - if (styleOptions instanceof Function) { - styleOptions = styleOptions(feat.properties, coords.z); - } - - if (!(styleOptions instanceof Array)) { - styleOptions = [styleOptions]; - } - - if (!styleOptions.length) { - continue; - } - - var featureLayer = this._createLayer(feat, pxPerExtent); - - for (var j = 0; j < styleOptions.length; j++) { - var style = L.extend({}, L.Path.prototype.options, styleOptions[j]); - featureLayer.render(renderer, style); - renderer._addPath(featureLayer); - } - - if (this.options.interactive) { - featureLayer.makeInteractive(); - } - - if (storeFeatures) { - // multiple features may share the same id, add them - // to an array of features - if (!renderer._features[id]) { - renderer._features[id] = []; - } + } - renderer._features[id].push({ - layerName: layerName, - feature: featureLayer - }); + if (styleOptions instanceof Function) { + styleOptions = styleOptions(feat.properties, coords.z); + } + + if (!(styleOptions instanceof Array)) { + styleOptions = [styleOptions]; + } + + if (!styleOptions.length) { + continue; + } + + var featureLayer = this._createLayer(feat, pxPerExtent); + + for (var j = 0; j < styleOptions.length; j++) { + var style = L.extend({}, L.Path.prototype.options, styleOptions[j]); + featureLayer.render(renderer, style); + renderer._addPath(featureLayer); + } + + if (this.options.interactive) { + featureLayer.makeInteractive(); + } + + if (storeFeatures) { + // multiple features may share the same id, add them + // to an array of features + if (!renderer._features[id]) { + renderer._features[id] = []; } + + renderer._features[id].push({ + layerName: layerName, + feature: featureLayer + }); } - } - } - + if (this._map != null) { renderer.addTo(this._map); } - + L.Util.requestAnimFrame(done.bind(coords, null, null)); }.bind(this));