Leaflet / Leaflet.VectorGrid

Display gridded vector data (sliced GeoJSON or protobuf vector tiles) in Leaflet 1.0.0
598 stars 194 forks source link

Offline .pbf files not working: ERROR Error: Unimplemented type: 3 #121

Closed rklerck closed 6 years ago

rklerck commented 6 years ago

Hi,

Not an issue, more a question.. Is there a way to make offline pbf files work? I exported a mbtiles file to multiple pbf files and changed the url served to:

L.vectorGrid.protobuf("assets/tiles/14/8680/8100.pbf

But than I receive the error: ERROR Error: Unimplemented type: 3. This probably has something to do with gzip encoding(?) but I can't get it to work...

IvanSanchez commented 6 years ago

Please provide a protobuf tile (or a few), your version of VectorGrid (as well as the vectortile dependency, if not using the default or building your own), and a full stack trace. There is not enough information to know what's going on.

rklerck commented 6 years ago

Tiles.zip

Sorry! I've added a few tiles. I used Mbutil to extract the pbf's from the mbtiles file.

These are the versions in my package.json:

"leaflet": "^1.0.3",
"leaflet.vectorgrid": "^1.3.0",

Not sure where to find the vectortile dependency...

And the stacktrace:

ERROR Error: Unimplemented type: 3
    at g (polyfills.js:3)
    at Pbf.skip (main.js:115619)
    at Pbf.readFields (main.js:115619)
    at new VectorTileLayer$2 (main.js:115619)
    at readTile (main.js:115619)
    at Pbf.readFields (main.js:115619)
    at new VectorTile$1 (main.js:115619)
    at FileReader.<anonymous> (main.js:115619)
    at t.invokeTask (polyfills.js:3)
    at Object.onInvokeTask (main.js:4415)
    at t.invokeTask (polyfills.js:3)
    at n.runTask (polyfills.js:3)
    at FileReader.invoke (polyfills.js:3)

defaultErrorLogger | @ | main.js:1364
-- | -- | --
  | ErrorHandler.handleError | @ | main.js:1424
  | IonicErrorHandler.handleError | @ | main.js:115598
  | next | @ | main.js:5053
  | schedulerFn | @ | main.js:4127
  | SafeSubscriber.__tryOrUnsub | @ | main.js:40219
  | SafeSubscriber.next | @ | main.js:40168
  | Subscriber._next | @ | main.js:40110
  | Subscriber.next | @ | main.js:40074
  | Subject.next | @ | main.js:56596
  | EventEmitter.emit | @ | main.js:4113
  | NgZone.triggerError | @ | main.js:4484
  | onHandleError | @ | main.js:4445
  | t.handleError | @ | polyfills.js:3
  | n.runTask | @ | polyfills.js:3
  | invoke | @ | polyfills.js:3
  | FileReader (async) |   |  
  | XMLHttpRequest.n.responseBlob.t.function.o.(anonymous function).M.(anonymous function).(anonymous function) | @ | polyfills.js:2
  | (anonymous) | @ | main.js:115619
  | t | @ | polyfills.js:3
  | (anonymous) | @ | main.js:115619
  | t.invoke | @ | polyfills.js:3
  | onInvoke | @ | main.js:4424
  | t.invoke | @ | polyfills.js:3
  | n.run | @ | polyfills.js:3
  | (anonymous) | @ | polyfills.js:3
  | t.invokeTask | @ | polyfills.js:3
  | onInvokeTask | @ | main.js:4415
  | t.invokeTask | @ | polyfills.js:3
  | n.runTask | @ | polyfills.js:3
  | a | @ | polyfills.js:3
  | Promise resolved (async) |   |  
  | e | @ | polyfills.js:3
  | r | @ | polyfills.js:3
  | t.scheduleTask | @ | polyfills.js:3
  | onScheduleTask | @ | polyfills.js:3
  | t.scheduleTask | @ | polyfills.js:3
  | n.scheduleTask | @ | polyfills.js:3
  | n.scheduleMicroTask | @ | polyfills.js:3
  | p | @ | polyfills.js:3
  | l | @ | polyfills.js:3
  | (anonymous) | @ | polyfills.js:3
  | Promise resolved (async) |   |  
  | (anonymous) | @ | polyfills.js:3
  | t | @ | polyfills.js:3
  | t.then | @ | polyfills.js:3
  | (anonymous) | @ | main.js:115619
  | t.invoke | @ | polyfills.js:3
  | onInvoke | @ | main.js:4424
  | t.invoke | @ | polyfills.js:3
  | n.run | @ | polyfills.js:3
  | (anonymous) | @ | polyfills.js:3
  | t.invokeTask | @ | polyfills.js:3
  | onInvokeTask | @ | main.js:4415
  | t.invokeTask | @ | polyfills.js:3
  | n.runTask | @ | polyfills.js:3
  | a | @ | polyfills.js:3
  | Promise resolved (async) |   |  
  | e | @ | polyfills.js:3
  | r | @ | polyfills.js:3
  | t.scheduleTask | @ | polyfills.js:3
  | onScheduleTask | @ | polyfills.js:3
  | t.scheduleTask | @ | polyfills.js:3
  | n.scheduleTask | @ | polyfills.js:3
  | n.scheduleMicroTask | @ | polyfills.js:3
  | p | @ | polyfills.js:3
  | l | @ | polyfills.js:3
  | (anonymous) | @ | polyfills.js:3
  | Promise resolved (async) |   |  
  | (anonymous) | @ | polyfills.js:3
  | t | @ | polyfills.js:3
  | t.then | @ | polyfills.js:3
  | _getVectorTilePromise | @ | main.js:115619
  | createTile | @ | main.js:115619
  | _addTile | @ | main.js:126672
  | _update | @ | main.js:126569
  | _setView | @ | main.js:126433
  | _resetView | @ | main.js:126391
  | onAdd | @ | main.js:126028
  | _layerAdd | @ | main.js:122027
  | whenReady | @ | main.js:119923
  | addLayer | @ | main.js:122089
  | addTo | @ | main.js:121969
  | (anonymous) | @ | main.js:57589
  | t.invokeTask | @ | polyfills.js:3
  | onInvokeTask | @ | main.js:4415
  | t.invokeTask | @ | polyfills.js:3
  | n.runTask | @ | polyfills.js:3
  | invoke | @ | polyfills.js:3
  | e | @ | polyfills.js:2
  | setTimeout (async) |   |  
  | o | @ | polyfills.js:2
  | t.scheduleTask | @ | polyfills.js:3
  | onScheduleTask | @ | polyfills.js:3
  | t.scheduleTask | @ | polyfills.js:3
  | n.scheduleTask | @ | polyfills.js:3
  | n.scheduleMacroTask | @ | polyfills.js:3
  | (anonymous) | @ | polyfills.js:2
  | setTimeout
  | PropertyListPage.showMap | @ | main.js:57578
  | (anonymous) | @ | ng:///AppModule/PropertyListPage.ngfactory.js:805
  | handleEvent | @ | main.js:12131
  | callWithDebugContext | @ | main.js:13339
  | debugHandleEvent | @ | main.js:12927
  | dispatchEvent | @ | main.js:9109
  | (anonymous) | @ | main.js:10971
  | schedulerFn | @ | main.js:4139
  | SafeSubscriber.__tryOrUnsub | @ | main.js:40219
  | SafeSubscriber.next | @ | main.js:40168
  | Subscriber._next | @ | main.js:40110
  | Subscriber.next | @ | main.js:40074
  | Subject.next | @ | main.js:56596
  | EventEmitter.emit | @ | main.js:4113
  | SegmentButton.onClick | @ | main.js:52699
  | (anonymous) | @ | ng:///AppModule/PropertyListPage.ngfactory.js:801
  | handleEvent | @ | main.js:12131
  | callWithDebugContext | @ | main.js:13339
  | debugHandleEvent | @ | main.js:12927
  | dispatchEvent | @ | main.js:9109
  | (anonymous) | @ | main.js:9698
  | (anonymous) | @ | main.js:37438
  | t.invokeTask | @ | polyfills.js:3
  | onInvokeTask | @ | main.js:4415
  | t.invokeTask | @ | polyfills.js:3
  | n.runTask | @ | polyfills.js:3
  | invoke | @ | polyfills.js:3

I'm using Ionic so everything is inside main.js... Is this enough?

IvanSanchez commented 6 years ago

ugh, main.js:115619 looks like you don't have sourcemaps for those. Any chance to tell which library is involved in each step of the stack trace?

rklerck commented 6 years ago

Well, don't know if this is what you're looking for? This is the source from where it goes wrong.

var reader = new FileReader();
return new Promise(function(resolve){
        reader.addEventListener("loadend", function() {
            // reader.result contains the contents of blob as a typed array

            // blob.type === 'application/x-protobuf'
            var pbf = new Pbf( reader.result );

            return resolve(new VectorTile( pbf ));

        });
                    reader.readAsArrayBuffer(blob);
});

Vectortile is version 1.3.0.

'use strict';

var VectorTileFeature = require('./vectortilefeature.js');

module.exports = VectorTileLayer;

function VectorTileLayer(pbf, end) {
    // Public
    this.version = 1;
    this.name = null;
    this.extent = 4096;
    this.length = 0;

    // Private
    this._pbf = pbf;
    this._keys = [];
    this._values = [];
    this._features = [];

    pbf.readFields(readLayer, this, end);

    this.length = this._features.length;
}

function readLayer(tag, layer, pbf) {
    if (tag === 15) layer.version = pbf.readVarint();
    else if (tag === 1) layer.name = pbf.readString();
    else if (tag === 5) layer.extent = pbf.readVarint();
    else if (tag === 2) layer._features.push(pbf.pos);
    else if (tag === 3) layer._keys.push(pbf.readString());
    else if (tag === 4) layer._values.push(readValueMessage(pbf));
}

function readValueMessage(pbf) {
    var value = null,
        end = pbf.readVarint() + pbf.pos;

    while (pbf.pos < end) {
        var tag = pbf.readVarint() >> 3;

        value = tag === 1 ? pbf.readString() :
            tag === 2 ? pbf.readFloat() :
            tag === 3 ? pbf.readDouble() :
            tag === 4 ? pbf.readVarint64() :
            tag === 5 ? pbf.readVarint() :
            tag === 6 ? pbf.readSVarint() :
            tag === 7 ? pbf.readBoolean() : null;
    }

    return value;
}

// return feature `i` from this layer as a `VectorTileFeature`
VectorTileLayer.prototype.feature = function(i) {
    if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');

    this._pbf.pos = this._features[i];

    var end = this._pbf.readVarint() + this._pbf.pos;
    return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
};
IvanSanchez commented 6 years ago

I'm gonna guess that VectorGrid is behaving as expected, and passing the protobuffer to Mapbox's vector-tile for decoding, and something in there is crashing. I would even go as far as guessing that the problem might be either malformed vector tiles or a conflicting old version of vector-tile.

I suggest you try to debug this in a small stand-alone nodejs script, reading a .pbf file, creating an instance of Pbf (via pbf)and then instantiating a VectorTile. That should trigger the same error.

So far this is not looking as a VectorGrid bug. I'm tempted to close it unless it can be reproduced with a readily available vector tile source.

rklerck commented 6 years ago

I will close it, I found the issue. I had to use gzip to decompress the .pbf file! Thanks for the help @IvanSanchez

leye0 commented 6 years ago

As I have the same issue as above, I'd like to comment here. I'm producing pbf vector tiles using tilemaker. My tiles look like so. The error message is exactly as above: Unimplemented Type 3.

My tiles appear to be gzip as gunziping them will produce a much larger file. I tried to serve them zipped and unzipped with no chance.

Here are two samples.

leye0-Tiles.zip

Are tiles produced with https://github.com/systemed/tilemaker compliant with this plugin?

leye0 commented 6 years ago

@rklerck Could I be in a case similar to yours?

tomchadwin commented 6 years ago

Are tiles produced with https://github.com/systemed/tilemaker compliant with this plugin?

@systemed?

miguelcobain commented 4 years ago

I'm also using https://github.com/systemed/tilemaker to produce the tiles and ended up with the same Uncaught Error: Unimplemented type: 3.

systemed commented 4 years ago

It's almost certainly a compression issue as per above.

Three questions to ask yourself:

  1. Does Leaflet.VectorGrid expect compressed or uncompressed tiles?
  2. Are you producing compressed or uncompressed tiles with Tilemaker?
  3. Are you serving those tiles with the headers that Leaflet.VectorGrid expects?
miguelcobain commented 4 years ago

@systemed any suggestion you could think of for fixing this? Does tilemaker compress the output tile files?

EDIT: just saw that tilemaker has a compress option that is gzip by default. Trying with none to see if that helps.

miguelcobain commented 4 years ago

Indeed, it was a compression issue. When I configured tilemaker to not compress output files and then served them normally (without any gzip headers, etc), it all worked out. Thank you!

systemed commented 4 years ago

Excellent!