mirror of
https://github.com/mapbox/vector-tile-js.git
synced 2026-01-18 14:02:48 +00:00
modernize (ESM, modern deps, GitHub Actions)
This commit is contained in:
parent
77851380b6
commit
4b81485642
19
.github/workflows/node.yml
vendored
Normal file
19
.github/workflows/node.yml
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
name: Node
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
@ -1,7 +0,0 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- 4
|
||||
script:
|
||||
- npm test
|
||||
- npm run cov
|
||||
@ -1,5 +1,4 @@
|
||||
Copyright (c) 2014, Mapbox
|
||||
|
||||
Copyright (c) 2024, Mapbox
|
||||
|
||||
All rights reserved.
|
||||
|
||||
|
||||
36
bench.js
Normal file
36
bench.js
Normal file
@ -0,0 +1,36 @@
|
||||
import Pbf from 'pbf';
|
||||
import {VectorTile} from './index.js';
|
||||
import Benchmark from 'benchmark';
|
||||
import fs from 'fs';
|
||||
|
||||
const suite = new Benchmark.Suite();
|
||||
const data = fs.readFileSync(new URL('test/fixtures/14-8801-5371.vector.pbf', import.meta.url));
|
||||
|
||||
readTile(); // output any errors before running the suite
|
||||
readTile(true);
|
||||
|
||||
suite
|
||||
.add('read tile with geometries', () => {
|
||||
readTile(true);
|
||||
})
|
||||
.add('read tile without geometries', () => {
|
||||
readTile();
|
||||
})
|
||||
.on('cycle', (event) => {
|
||||
console.log(String(event.target));
|
||||
})
|
||||
.run();
|
||||
|
||||
|
||||
function readTile(loadGeom) {
|
||||
const buf = new Pbf(data),
|
||||
vt = new VectorTile(buf);
|
||||
|
||||
for (const id in vt.layers) {
|
||||
const layer = vt.layers[id];
|
||||
for (let i = 0; i < layer.length; i++) {
|
||||
const feature = layer.feature(i);
|
||||
if (loadGeom) feature.loadGeometry();
|
||||
}
|
||||
}
|
||||
}
|
||||
10
eslint.config.js
Normal file
10
eslint.config.js
Normal file
@ -0,0 +1,10 @@
|
||||
import config from 'eslint-config-mourner';
|
||||
|
||||
export default [
|
||||
...config,
|
||||
{
|
||||
rules: {
|
||||
'no-case-declarations': 0
|
||||
}
|
||||
}
|
||||
];
|
||||
157
fixtures.js
157
fixtures.js
@ -1,157 +0,0 @@
|
||||
var mapnik = require('mapnik');
|
||||
var path = require('path');
|
||||
var fs = require('fs');
|
||||
|
||||
mapnik.register_datasource(path.join(mapnik.settings.paths.input_plugins, 'geojson.input'));
|
||||
|
||||
var fixtures = {
|
||||
"zero-point": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiPoint",
|
||||
"coordinates": []
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"zero-line": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiLineString",
|
||||
"coordinates": []
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"zero-polygon": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": []
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"singleton-multi-point": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiPoint",
|
||||
"coordinates": [[1, 2]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"singleton-multi-line": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiLineString",
|
||||
"coordinates": [[[1, 2], [3, 4]]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"singleton-multi-polygon": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [[[[0, 0], [1, 0], [1, 1], [0, 0]]]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"multi-point": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiPoint",
|
||||
"coordinates": [[1, 2], [3, 4]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"multi-line": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiLineString",
|
||||
"coordinates": [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"multi-polygon": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [[[[0, 0], [1, 0], [1, 1], [0, 0]]], [[[0, 0], [-1, 0], [-1, -1], [0, 0]]]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"polygon-with-inner": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [[[-2, 2], [2, 2], [2, -2], [-2, -2], [-2, 2]], [[-1, 1], [1, 1], [1, -1], [-1, -1], [-1, 1]]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"stacked-multipolygon": {
|
||||
"type": "FeatureCollection",
|
||||
"features": [
|
||||
{
|
||||
"type": "Feature",
|
||||
"geometry": {
|
||||
"type": "MultiPolygon",
|
||||
"coordinates": [[[[-2, 2], [2, 2], [2, -2], [-2, -2], [-2, 2]]], [[[-1, 1], [1, 1], [1, -1], [-1, -1], [-1, 1]]]]
|
||||
},
|
||||
"properties": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
for (var fixture in fixtures) {
|
||||
var vtile = new mapnik.VectorTile(0, 0, 0);
|
||||
vtile.addGeoJSON(JSON.stringify(fixtures[fixture]), "geojson");
|
||||
fs.writeFileSync('./test/fixtures/' + fixture + '.pbf', vtile.getData());
|
||||
}
|
||||
303
index.js
303
index.js
@ -1,3 +1,300 @@
|
||||
module.exports.VectorTile = require('./lib/vectortile.js');
|
||||
module.exports.VectorTileFeature = require('./lib/vectortilefeature.js');
|
||||
module.exports.VectorTileLayer = require('./lib/vectortilelayer.js');
|
||||
|
||||
import Point from '@mapbox/point-geometry';
|
||||
|
||||
export class VectorTileFeature {
|
||||
constructor(pbf, end, extent, keys, values) {
|
||||
// Public
|
||||
this.properties = {};
|
||||
this.extent = extent;
|
||||
this.type = 0;
|
||||
|
||||
// Private
|
||||
this._pbf = pbf;
|
||||
this._geometry = -1;
|
||||
this._keys = keys;
|
||||
this._values = values;
|
||||
|
||||
pbf.readFields(readFeature, this, end);
|
||||
}
|
||||
|
||||
loadGeometry() {
|
||||
const pbf = this._pbf;
|
||||
pbf.pos = this._geometry;
|
||||
|
||||
const end = pbf.readVarint() + pbf.pos;
|
||||
const lines = [];
|
||||
let cmd = 1,
|
||||
length = 0,
|
||||
x = 0,
|
||||
y = 0,
|
||||
line;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (length <= 0) {
|
||||
const cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
|
||||
if (cmd === 1) { // moveTo
|
||||
if (line) lines.push(line);
|
||||
line = [];
|
||||
}
|
||||
|
||||
line.push(new Point(x, y));
|
||||
|
||||
} else if (cmd === 7) {
|
||||
|
||||
// Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
|
||||
if (line) {
|
||||
line.push(line[0].clone()); // closePolygon
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Error(`unknown command ${ cmd}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (line) lines.push(line);
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
bbox() {
|
||||
const pbf = this._pbf;
|
||||
pbf.pos = this._geometry;
|
||||
|
||||
const end = pbf.readVarint() + pbf.pos;
|
||||
let cmd = 1,
|
||||
length = 0,
|
||||
x = 0,
|
||||
y = 0,
|
||||
x1 = Infinity,
|
||||
x2 = -Infinity,
|
||||
y1 = Infinity,
|
||||
y2 = -Infinity;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (length <= 0) {
|
||||
const cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
if (x < x1) x1 = x;
|
||||
if (x > x2) x2 = x;
|
||||
if (y < y1) y1 = y;
|
||||
if (y > y2) y2 = y;
|
||||
|
||||
} else if (cmd !== 7) {
|
||||
throw new Error(`unknown command ${ cmd}`);
|
||||
}
|
||||
}
|
||||
|
||||
return [x1, y1, x2, y2];
|
||||
}
|
||||
|
||||
toGeoJSON(x, y, z) {
|
||||
const size = this.extent * Math.pow(2, z),
|
||||
x0 = this.extent * x,
|
||||
y0 = this.extent * y;
|
||||
let type = VectorTileFeature.types[this.type],
|
||||
coords = this.loadGeometry();
|
||||
|
||||
function project(line) {
|
||||
for (let j = 0; j < line.length; j++) {
|
||||
const p = line[j], y2 = 180 - (p.y + y0) * 360 / size;
|
||||
line[j] = [
|
||||
(p.x + x0) * 360 / size - 180,
|
||||
360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.type) {
|
||||
case 1:
|
||||
const points = [];
|
||||
for (let i = 0; i < coords.length; i++) {
|
||||
points[i] = coords[i][0];
|
||||
}
|
||||
coords = points;
|
||||
project(coords);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (let i = 0; i < coords.length; i++) {
|
||||
project(coords[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
coords = classifyRings(coords);
|
||||
for (let i = 0; i < coords.length; i++) {
|
||||
for (let j = 0; j < coords[i].length; j++) {
|
||||
project(coords[i][j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (coords.length === 1) {
|
||||
coords = coords[0];
|
||||
} else {
|
||||
type = `Multi${type}`;
|
||||
}
|
||||
|
||||
const result = {
|
||||
type: 'Feature',
|
||||
geometry: {
|
||||
type,
|
||||
coordinates: coords
|
||||
},
|
||||
properties: this.properties
|
||||
};
|
||||
|
||||
if ('id' in this) {
|
||||
result.id = this.id;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
|
||||
|
||||
function readFeature(tag, feature, pbf) {
|
||||
if (tag === 1) feature.id = pbf.readVarint();
|
||||
else if (tag === 2) readTag(pbf, feature);
|
||||
else if (tag === 3) feature.type = pbf.readVarint();
|
||||
else if (tag === 4) feature._geometry = pbf.pos;
|
||||
}
|
||||
|
||||
function readTag(pbf, feature) {
|
||||
const end = pbf.readVarint() + pbf.pos;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
const key = feature._keys[pbf.readVarint()],
|
||||
value = feature._values[pbf.readVarint()];
|
||||
feature.properties[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
// classifies an array of rings into polygons with outer rings and holes
|
||||
export function classifyRings(rings) {
|
||||
const len = rings.length;
|
||||
|
||||
if (len <= 1) return [rings];
|
||||
|
||||
const polygons = [];
|
||||
let polygon, ccw;
|
||||
|
||||
for (let i = 0; i < len; i++) {
|
||||
const area = signedArea(rings[i]);
|
||||
if (area === 0) continue;
|
||||
|
||||
if (ccw === undefined) ccw = area < 0;
|
||||
|
||||
if (ccw === area < 0) {
|
||||
if (polygon) polygons.push(polygon);
|
||||
polygon = [rings[i]];
|
||||
|
||||
} else {
|
||||
polygon.push(rings[i]);
|
||||
}
|
||||
}
|
||||
if (polygon) polygons.push(polygon);
|
||||
|
||||
return polygons;
|
||||
}
|
||||
|
||||
function signedArea(ring) {
|
||||
let sum = 0;
|
||||
for (let i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
|
||||
p1 = ring[i];
|
||||
p2 = ring[j];
|
||||
sum += (p2.x - p1.x) * (p1.y + p2.y);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
export class VectorTileLayer {
|
||||
constructor(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;
|
||||
}
|
||||
|
||||
// return feature `i` from this layer as a `VectorTileFeature`
|
||||
feature(i) {
|
||||
if (i < 0 || i >= this._features.length) throw new Error('feature index out of bounds');
|
||||
|
||||
this._pbf.pos = this._features[i];
|
||||
|
||||
const end = this._pbf.readVarint() + this._pbf.pos;
|
||||
return new VectorTileFeature(this._pbf, end, this.extent, this._keys, this._values);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
let value = null;
|
||||
const end = pbf.readVarint() + pbf.pos;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
const 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;
|
||||
}
|
||||
|
||||
export class VectorTile {
|
||||
constructor(pbf, end) {
|
||||
this.layers = pbf.readFields(readTile, {}, end);
|
||||
}
|
||||
}
|
||||
|
||||
function readTile(tag, layers, pbf) {
|
||||
if (tag === 3) {
|
||||
const layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
|
||||
if (layer.length) layers[layer.name] = layer;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var VectorTileLayer = require('./vectortilelayer');
|
||||
|
||||
module.exports = VectorTile;
|
||||
|
||||
function VectorTile(pbf, end) {
|
||||
this.layers = pbf.readFields(readTile, {}, end);
|
||||
}
|
||||
|
||||
function readTile(tag, layers, pbf) {
|
||||
if (tag === 3) {
|
||||
var layer = new VectorTileLayer(pbf, pbf.readVarint() + pbf.pos);
|
||||
if (layer.length) layers[layer.name] = layer;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,233 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var Point = require('@mapbox/point-geometry');
|
||||
|
||||
module.exports = VectorTileFeature;
|
||||
|
||||
function VectorTileFeature(pbf, end, extent, keys, values) {
|
||||
// Public
|
||||
this.properties = {};
|
||||
this.extent = extent;
|
||||
this.type = 0;
|
||||
|
||||
// Private
|
||||
this._pbf = pbf;
|
||||
this._geometry = -1;
|
||||
this._keys = keys;
|
||||
this._values = values;
|
||||
|
||||
pbf.readFields(readFeature, this, end);
|
||||
}
|
||||
|
||||
function readFeature(tag, feature, pbf) {
|
||||
if (tag == 1) feature.id = pbf.readVarint();
|
||||
else if (tag == 2) readTag(pbf, feature);
|
||||
else if (tag == 3) feature.type = pbf.readVarint();
|
||||
else if (tag == 4) feature._geometry = pbf.pos;
|
||||
}
|
||||
|
||||
function readTag(pbf, feature) {
|
||||
var end = pbf.readVarint() + pbf.pos;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
var key = feature._keys[pbf.readVarint()],
|
||||
value = feature._values[pbf.readVarint()];
|
||||
feature.properties[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
VectorTileFeature.types = ['Unknown', 'Point', 'LineString', 'Polygon'];
|
||||
|
||||
VectorTileFeature.prototype.loadGeometry = function() {
|
||||
var pbf = this._pbf;
|
||||
pbf.pos = this._geometry;
|
||||
|
||||
var end = pbf.readVarint() + pbf.pos,
|
||||
cmd = 1,
|
||||
length = 0,
|
||||
x = 0,
|
||||
y = 0,
|
||||
lines = [],
|
||||
line;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (length <= 0) {
|
||||
var cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
|
||||
if (cmd === 1) { // moveTo
|
||||
if (line) lines.push(line);
|
||||
line = [];
|
||||
}
|
||||
|
||||
line.push(new Point(x, y));
|
||||
|
||||
} else if (cmd === 7) {
|
||||
|
||||
// Workaround for https://github.com/mapbox/mapnik-vector-tile/issues/90
|
||||
if (line) {
|
||||
line.push(line[0].clone()); // closePolygon
|
||||
}
|
||||
|
||||
} else {
|
||||
throw new Error('unknown command ' + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
if (line) lines.push(line);
|
||||
|
||||
return lines;
|
||||
};
|
||||
|
||||
VectorTileFeature.prototype.bbox = function() {
|
||||
var pbf = this._pbf;
|
||||
pbf.pos = this._geometry;
|
||||
|
||||
var end = pbf.readVarint() + pbf.pos,
|
||||
cmd = 1,
|
||||
length = 0,
|
||||
x = 0,
|
||||
y = 0,
|
||||
x1 = Infinity,
|
||||
x2 = -Infinity,
|
||||
y1 = Infinity,
|
||||
y2 = -Infinity;
|
||||
|
||||
while (pbf.pos < end) {
|
||||
if (length <= 0) {
|
||||
var cmdLen = pbf.readVarint();
|
||||
cmd = cmdLen & 0x7;
|
||||
length = cmdLen >> 3;
|
||||
}
|
||||
|
||||
length--;
|
||||
|
||||
if (cmd === 1 || cmd === 2) {
|
||||
x += pbf.readSVarint();
|
||||
y += pbf.readSVarint();
|
||||
if (x < x1) x1 = x;
|
||||
if (x > x2) x2 = x;
|
||||
if (y < y1) y1 = y;
|
||||
if (y > y2) y2 = y;
|
||||
|
||||
} else if (cmd !== 7) {
|
||||
throw new Error('unknown command ' + cmd);
|
||||
}
|
||||
}
|
||||
|
||||
return [x1, y1, x2, y2];
|
||||
};
|
||||
|
||||
VectorTileFeature.prototype.toGeoJSON = function(x, y, z) {
|
||||
var size = this.extent * Math.pow(2, z),
|
||||
x0 = this.extent * x,
|
||||
y0 = this.extent * y,
|
||||
coords = this.loadGeometry(),
|
||||
type = VectorTileFeature.types[this.type],
|
||||
i, j;
|
||||
|
||||
function project(line) {
|
||||
for (var j = 0; j < line.length; j++) {
|
||||
var p = line[j], y2 = 180 - (p.y + y0) * 360 / size;
|
||||
line[j] = [
|
||||
(p.x + x0) * 360 / size - 180,
|
||||
360 / Math.PI * Math.atan(Math.exp(y2 * Math.PI / 180)) - 90
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
switch (this.type) {
|
||||
case 1:
|
||||
var points = [];
|
||||
for (i = 0; i < coords.length; i++) {
|
||||
points[i] = coords[i][0];
|
||||
}
|
||||
coords = points;
|
||||
project(coords);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
for (i = 0; i < coords.length; i++) {
|
||||
project(coords[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
coords = classifyRings(coords);
|
||||
for (i = 0; i < coords.length; i++) {
|
||||
for (j = 0; j < coords[i].length; j++) {
|
||||
project(coords[i][j]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (coords.length === 1) {
|
||||
coords = coords[0];
|
||||
} else {
|
||||
type = 'Multi' + type;
|
||||
}
|
||||
|
||||
var result = {
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: type,
|
||||
coordinates: coords
|
||||
},
|
||||
properties: this.properties
|
||||
};
|
||||
|
||||
if ('id' in this) {
|
||||
result.id = this.id;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// classifies an array of rings into polygons with outer rings and holes
|
||||
|
||||
function classifyRings(rings) {
|
||||
var len = rings.length;
|
||||
|
||||
if (len <= 1) return [rings];
|
||||
|
||||
var polygons = [],
|
||||
polygon,
|
||||
ccw;
|
||||
|
||||
for (var i = 0; i < len; i++) {
|
||||
var area = signedArea(rings[i]);
|
||||
if (area === 0) continue;
|
||||
|
||||
if (ccw === undefined) ccw = area < 0;
|
||||
|
||||
if (ccw === area < 0) {
|
||||
if (polygon) polygons.push(polygon);
|
||||
polygon = [rings[i]];
|
||||
|
||||
} else {
|
||||
polygon.push(rings[i]);
|
||||
}
|
||||
}
|
||||
if (polygon) polygons.push(polygon);
|
||||
|
||||
return polygons;
|
||||
}
|
||||
|
||||
function signedArea(ring) {
|
||||
var sum = 0;
|
||||
for (var i = 0, len = ring.length, j = len - 1, p1, p2; i < len; j = i++) {
|
||||
p1 = ring[i];
|
||||
p2 = ring[j];
|
||||
sum += (p2.x - p1.x) * (p1.y + p2.y);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
@ -1,61 +0,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);
|
||||
};
|
||||
1249
package-lock.json
generated
Normal file
1249
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
31
package.json
31
package.json
@ -3,31 +3,24 @@
|
||||
"description": "Parses vector tiles",
|
||||
"repository": "https://github.com/mapbox/vector-tile-js.git",
|
||||
"version": "1.3.1",
|
||||
"type": "module",
|
||||
"exports": "./index.js",
|
||||
"license": "BSD-3-Clause",
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@mapbox/point-geometry": "~0.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"benchmark": "^1.0.0",
|
||||
"coveralls": "~2.11.2",
|
||||
"istanbul": "~0.3.6",
|
||||
"mapnik": "~3.6.0",
|
||||
"jshint": "^2.6.3",
|
||||
"pbf": "^1.3.2",
|
||||
"tape": "~3.5.0",
|
||||
"eslint": "~1.00.0",
|
||||
"eslint-config-unstyled": "^1.1.0"
|
||||
},
|
||||
"jshintConfig": {
|
||||
"trailing": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"indent": 4,
|
||||
"node": true
|
||||
"benchmark": "^2.1.4",
|
||||
"eslint": "^9.6.0",
|
||||
"eslint-config-mourner": "^4.0.1",
|
||||
"pbf": "^4.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "eslint lib index.js && jshint lib && tape test/parse.test.js",
|
||||
"cov": "istanbul cover ./node_modules/.bin/tape test/parse.test.js && coveralls < ./coverage/lcov.info"
|
||||
}
|
||||
"lint": "eslint index.js test/*.js",
|
||||
"pretest": "npm run lint",
|
||||
"test": "node --test",
|
||||
"cov": "node --test --experimental-test-coverage"
|
||||
},
|
||||
"files": []
|
||||
}
|
||||
|
||||
@ -1,36 +0,0 @@
|
||||
var Pbf = require('pbf'),
|
||||
VectorTile = require('..').VectorTile,
|
||||
Benchmark = require('benchmark'),
|
||||
fs = require('fs');
|
||||
|
||||
var suite = new Benchmark.Suite(),
|
||||
data = fs.readFileSync(__dirname + '/fixtures/14-8801-5371.vector.Pbf');
|
||||
|
||||
readTile(); // output any errors before running the suite
|
||||
readTile(true);
|
||||
|
||||
suite
|
||||
.add('read tile with geometries', function() {
|
||||
readTile(true);
|
||||
})
|
||||
.add('read tile without geometries', function() {
|
||||
readTile();
|
||||
})
|
||||
.on('cycle', function(event) {
|
||||
console.log(String(event.target));
|
||||
})
|
||||
.run();
|
||||
|
||||
|
||||
function readTile(loadGeom, loadPacked) {
|
||||
var buf = new Pbf(data),
|
||||
vt = new VectorTile(buf);
|
||||
|
||||
for (var id in vt.layers) {
|
||||
var layer = vt.layers[id];
|
||||
for (var i = 0; i < layer.length; i++) {
|
||||
var feature = layer.feature(i);
|
||||
if (loadGeom) feature.loadGeometry();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,16 @@
|
||||
var test = require('tape'),
|
||||
fs = require('fs'),
|
||||
Protobuf = require('pbf'),
|
||||
VectorTile = require('..').VectorTile,
|
||||
VectorTileLayer = require('..').VectorTileLayer,
|
||||
VectorTileFeature = require('..').VectorTileFeature;
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import fs from 'fs';
|
||||
import Protobuf from 'pbf';
|
||||
import {VectorTile, VectorTileLayer, VectorTileFeature} from '../index.js';
|
||||
import Point from '@mapbox/point-geometry';
|
||||
|
||||
function getFixtureTile(name) {
|
||||
const data = fs.readFileSync(new URL(`fixtures/${name}.pbf`, import.meta.url));
|
||||
return new VectorTile(new Protobuf(data));
|
||||
}
|
||||
|
||||
const tile = getFixtureTile('14-8801-5371.vector');
|
||||
|
||||
function approximateDeepEqual(a, b, epsilon) {
|
||||
epsilon = epsilon || 1e-6;
|
||||
@ -15,211 +22,186 @@ function approximateDeepEqual(a, b, epsilon) {
|
||||
if (a === null || typeof a !== 'object')
|
||||
return a === b;
|
||||
|
||||
var ka = Object.keys(a);
|
||||
var kb = Object.keys(b);
|
||||
const ka = Object.keys(a);
|
||||
const kb = Object.keys(b);
|
||||
|
||||
if (ka.length != kb.length)
|
||||
if (ka.length !== kb.length)
|
||||
return false;
|
||||
|
||||
ka.sort();
|
||||
kb.sort();
|
||||
|
||||
for (var i = 0; i < ka.length; i++)
|
||||
if (ka[i] != kb[i] || !approximateDeepEqual(a[ka[i]], b[ka[i]], epsilon))
|
||||
for (let i = 0; i < ka.length; i++)
|
||||
if (ka[i] !== kb[i] || !approximateDeepEqual(a[ka[i]], b[ka[i]], epsilon))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
test('parsing vector tiles', function(t) {
|
||||
var data = fs.readFileSync(__dirname + '/fixtures/14-8801-5371.vector.pbf');
|
||||
test('should have all layers', () => {
|
||||
assert.deepEqual(Object.keys(tile.layers), [
|
||||
'landuse', 'waterway', 'water', 'barrier_line', 'building',
|
||||
'landuse_overlay', 'tunnel', 'road', 'bridge', 'place_label',
|
||||
'water_label', 'poi_label', 'road_label', 'waterway_label']);
|
||||
});
|
||||
|
||||
t.test('should have all layers', function(t) {
|
||||
var tile = new VectorTile(new Protobuf(data));
|
||||
test('should extract the tags of a feature', () => {
|
||||
assert.equal(tile.layers.poi_label.length, 558);
|
||||
|
||||
t.deepEqual(Object.keys(tile.layers), [
|
||||
'landuse', 'waterway', 'water', 'barrier_line', 'building',
|
||||
'landuse_overlay', 'tunnel', 'road', 'bridge', 'place_label',
|
||||
'water_label', 'poi_label', 'road_label', 'waterway_label' ]);
|
||||
const park = tile.layers.poi_label.feature(11);
|
||||
|
||||
t.end();
|
||||
});
|
||||
assert.deepEqual(park.bbox(), [3898, 1731, 3898, 1731]);
|
||||
|
||||
t.test('should extract the tags of a feature', function(t) {
|
||||
var tile = new VectorTile(new Protobuf(data));
|
||||
assert.throws(() => {
|
||||
tile.layers.poi_label.feature(1e9);
|
||||
}, 'throws on reading a feature out of bounds');
|
||||
|
||||
t.equal(tile.layers.poi_label.length, 558);
|
||||
assert.equal(park.id, 3000003150561);
|
||||
|
||||
var park = tile.layers.poi_label.feature(11);
|
||||
assert.equal(park.properties.name, 'Mauerpark');
|
||||
assert.equal(park.properties.type, 'Park');
|
||||
|
||||
t.deepEqual(park.bbox(), [ 3898, 1731, 3898, 1731 ]);
|
||||
// Check point geometry
|
||||
assert.deepEqual(park.loadGeometry(), [[new Point(3898, 1731)]]);
|
||||
|
||||
t.throws(function() {
|
||||
var park = tile.layers.poi_label.feature(1e9);
|
||||
}, 'throws on reading a feature out of bounds');
|
||||
// Check line geometry
|
||||
assert.deepEqual(tile.layers.road.feature(656).loadGeometry(), [[new Point(1988, 306), new Point(1808, 321), new Point(1506, 347)]]);
|
||||
});
|
||||
|
||||
t.equal(park.id, 3000003150561);
|
||||
test('changing first point of a polygon should not change last point', () => {
|
||||
const building = tile.layers.building.feature(0).loadGeometry();
|
||||
assert.deepEqual(building, [[new Point(2039, -32), new Point(2035, -31), new Point(2032, -31), new Point(2032, -32), new Point(2039, -32)]]);
|
||||
building[0][0].x = 1;
|
||||
building[0][0].y = 2;
|
||||
building[0][1].x = 3;
|
||||
building[0][1].y = 4;
|
||||
assert.deepEqual(building, [[new Point(1, 2), new Point(3, 4), new Point(2032, -31), new Point(2032, -32), new Point(2039, -32)]]);
|
||||
});
|
||||
|
||||
t.equal(park.properties.name, 'Mauerpark');
|
||||
t.equal(park.properties.type, 'Park');
|
||||
|
||||
// Check point geometry
|
||||
t.deepEqual(park.loadGeometry(), [ [ { x: 3898, y: 1731 } ] ]);
|
||||
|
||||
// Check line geometry
|
||||
t.deepEqual(tile.layers.road.feature(656).loadGeometry(), [ [ { x: 1988, y: 306 }, { x: 1808, y: 321 }, { x: 1506, y: 347 } ] ]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('changing first point of a polygon should not change last point', function(t) {
|
||||
var tile = new VectorTile(new Protobuf(data));
|
||||
|
||||
var building = tile.layers.building.feature(0).loadGeometry();
|
||||
t.deepEqual(building, [ [ { x: 2039, y: -32 }, { x: 2035, y: -31 }, { x: 2032, y: -31 }, { x: 2032, y: -32 }, { x: 2039, y: -32 } ] ]);
|
||||
building[0][0].x = 1;
|
||||
building[0][0].y = 2;
|
||||
building[0][1].x = 3;
|
||||
building[0][1].y = 4;
|
||||
t.deepEqual(building, [ [ { x: 1, y: 2 }, { x: 3, y: 4 }, { x: 2032, y: -31 }, { x: 2032, y: -32 }, { x: 2039, y: -32 } ] ]);
|
||||
t.end();
|
||||
});
|
||||
|
||||
t.test('toGeoJSON', function(t) {
|
||||
var tile = new VectorTile(new Protobuf(data));
|
||||
|
||||
t.ok(approximateDeepEqual(tile.layers.poi_label.feature(11).toGeoJSON(8801, 5371, 14), {
|
||||
type: 'Feature',
|
||||
id: 3000003150561,
|
||||
properties: {
|
||||
localrank: 1,
|
||||
maki: 'park',
|
||||
name: 'Mauerpark',
|
||||
name_de: 'Mauerpark',
|
||||
name_en: 'Mauerpark',
|
||||
name_es: 'Mauerpark',
|
||||
name_fr: 'Mauerpark',
|
||||
osm_id: 3000003150561,
|
||||
ref: '',
|
||||
scalerank: 2,
|
||||
type: 'Park'
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [13.402258157730103, 52.54398925380624]
|
||||
}
|
||||
}));
|
||||
|
||||
t.ok(approximateDeepEqual(tile.layers.bridge.feature(0).toGeoJSON(8801, 5371, 14), {
|
||||
type: 'Feature',
|
||||
id: 238162948,
|
||||
properties: {
|
||||
class: 'service',
|
||||
oneway: 0,
|
||||
osm_id: 238162948,
|
||||
type: 'service'
|
||||
},
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [[13.399457931518555, 52.546334844036416], [13.399441838264465, 52.546504478525016]]
|
||||
}
|
||||
}));
|
||||
|
||||
t.ok(approximateDeepEqual(tile.layers.building.feature(0).toGeoJSON(8801, 5371, 14), {
|
||||
type: 'Feature',
|
||||
id: 1000267229912,
|
||||
properties: {
|
||||
osm_id: 1000267229912
|
||||
},
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [[[13.392285704612732, 52.54974045706258], [13.392264246940613, 52.549737195107554],
|
||||
[13.392248153686523, 52.549737195107554], [13.392248153686523, 52.54974045706258],
|
||||
[13.392285704612732, 52.54974045706258]]]
|
||||
}
|
||||
}));
|
||||
|
||||
function geoJSONFromFixture(name) {
|
||||
var tile = new VectorTile(new Protobuf(fs.readFileSync(__dirname + '/fixtures/' + name + '.pbf')));
|
||||
return tile.layers.geojson.feature(0).toGeoJSON(0, 0, 0);
|
||||
}
|
||||
|
||||
// https://github.com/mapbox/vector-tile-spec/issues/30
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("singleton-multi-point").geometry, {
|
||||
test('toGeoJSON', () => {
|
||||
assert.ok(approximateDeepEqual(tile.layers.poi_label.feature(11).toGeoJSON(8801, 5371, 14), {
|
||||
type: 'Feature',
|
||||
id: 3000003150561,
|
||||
properties: {
|
||||
localrank: 1,
|
||||
maki: 'park',
|
||||
name: 'Mauerpark',
|
||||
'name_de': 'Mauerpark',
|
||||
'name_en': 'Mauerpark',
|
||||
'name_es': 'Mauerpark',
|
||||
'name_fr': 'Mauerpark',
|
||||
'osm_id': 3000003150561,
|
||||
ref: '',
|
||||
scalerank: 2,
|
||||
type: 'Park'
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: [1, 2]
|
||||
}, 1e-1));
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("singleton-multi-line").geometry, {
|
||||
coordinates: [13.402258157730103, 52.54398925380624]
|
||||
}
|
||||
}));
|
||||
|
||||
assert.ok(approximateDeepEqual(tile.layers.bridge.feature(0).toGeoJSON(8801, 5371, 14), {
|
||||
type: 'Feature',
|
||||
id: 238162948,
|
||||
properties: {
|
||||
class: 'service',
|
||||
oneway: 0,
|
||||
'osm_id': 238162948,
|
||||
type: 'service'
|
||||
},
|
||||
geometry: {
|
||||
type: 'LineString',
|
||||
coordinates: [[1, 2], [3, 4]]
|
||||
}, 1e-1));
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("singleton-multi-polygon").geometry, {
|
||||
coordinates: [[13.399457931518555, 52.546334844036416], [13.399441838264465, 52.546504478525016]]
|
||||
}
|
||||
}));
|
||||
|
||||
assert.ok(approximateDeepEqual(tile.layers.building.feature(0).toGeoJSON(8801, 5371, 14), {
|
||||
type: 'Feature',
|
||||
id: 1000267229912,
|
||||
properties: {
|
||||
'osm_id': 1000267229912
|
||||
},
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [[[1, 0], [0, 0], [1, 1], [1, 0]]]
|
||||
}, 1e-1));
|
||||
coordinates: [[[13.392285704612732, 52.54974045706258], [13.392264246940613, 52.549737195107554],
|
||||
[13.392248153686523, 52.549737195107554], [13.392248153686523, 52.54974045706258],
|
||||
[13.392285704612732, 52.54974045706258]]]
|
||||
}
|
||||
}));
|
||||
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("multi-point").geometry, {
|
||||
type: 'MultiPoint',
|
||||
coordinates: [[1, 2], [3, 4]]
|
||||
}, 1e-1));
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("multi-line").geometry, {
|
||||
type: 'MultiLineString',
|
||||
coordinates: [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
}, 1e-1));
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("multi-polygon").geometry, {
|
||||
type: 'MultiPolygon',
|
||||
coordinates: [[[[1, 0], [0, 0], [1, 1], [1, 0]]], [[[-1, -1], [-1, 0], [0, 0], [-1, -1]]]]
|
||||
}, 1e-1));
|
||||
function geoJSONFromFixture(name) {
|
||||
const tile = getFixtureTile(name);
|
||||
return tile.layers.geojson.feature(0).toGeoJSON(0, 0, 0);
|
||||
}
|
||||
|
||||
// https://github.com/mapbox/vector-tile-js/issues/32
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("polygon-with-inner").geometry, {
|
||||
type: 'Polygon',
|
||||
coordinates: [[[2, -2], [-2, -2], [-2, 2], [2, 2], [2, -2]], [[-1, 1], [-1, -1], [1, -1], [1, 1], [-1, 1]]]
|
||||
}, 1e-1));
|
||||
t.ok(approximateDeepEqual(geoJSONFromFixture("stacked-multipolygon").geometry, {
|
||||
type: 'MultiPolygon',
|
||||
coordinates: [[[[2, -2], [-2, -2], [-2, 2], [2, 2], [2, -2]]], [[[1, -1], [-1, -1], [-1, 1], [1, 1], [1, -1]]]]
|
||||
}, 1e-1));
|
||||
// https://github.com/mapbox/vector-tile-spec/issues/30
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('singleton-multi-point').geometry, {
|
||||
type: 'Point',
|
||||
coordinates: [1, 2]
|
||||
}, 1e-1));
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('singleton-multi-line').geometry, {
|
||||
type: 'LineString',
|
||||
coordinates: [[1, 2], [3, 4]]
|
||||
}, 1e-1));
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('singleton-multi-polygon').geometry, {
|
||||
type: 'Polygon',
|
||||
coordinates: [[[1, 0], [0, 0], [1, 1], [1, 0]]]
|
||||
}, 1e-1));
|
||||
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('multi-point').geometry, {
|
||||
type: 'MultiPoint',
|
||||
coordinates: [[1, 2], [3, 4]]
|
||||
}, 1e-1));
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('multi-line').geometry, {
|
||||
type: 'MultiLineString',
|
||||
coordinates: [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
|
||||
}, 1e-1));
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('multi-polygon').geometry, {
|
||||
type: 'MultiPolygon',
|
||||
coordinates: [[[[1, 0], [0, 0], [1, 1], [1, 0]]], [[[-1, -1], [-1, 0], [0, 0], [-1, -1]]]]
|
||||
}, 1e-1));
|
||||
|
||||
// https://github.com/mapbox/vector-tile-js/issues/32
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('polygon-with-inner').geometry, {
|
||||
type: 'Polygon',
|
||||
coordinates: [[[2, -2], [-2, -2], [-2, 2], [2, 2], [2, -2]], [[-1, 1], [-1, -1], [1, -1], [1, 1], [-1, 1]]]
|
||||
}, 1e-1));
|
||||
assert.ok(approximateDeepEqual(geoJSONFromFixture('stacked-multipolygon').geometry, {
|
||||
type: 'MultiPolygon',
|
||||
coordinates: [[[[2, -2], [-2, -2], [-2, 2], [2, 2], [2, -2]]], [[[1, -1], [-1, -1], [-1, 1], [1, 1], [1, -1]]]]
|
||||
}, 1e-1));
|
||||
|
||||
t.end();
|
||||
})
|
||||
});
|
||||
|
||||
test('VectorTileLayer', function(t) {
|
||||
var emptyLayer = new VectorTileLayer(new Protobuf(new Buffer([])));
|
||||
t.ok(emptyLayer, 'can be created with no values');
|
||||
t.end();
|
||||
test('VectorTileLayer', () => {
|
||||
const emptyLayer = new VectorTileLayer(new Protobuf(Buffer.alloc(0)));
|
||||
assert.ok(emptyLayer, 'can be created with no values');
|
||||
});
|
||||
|
||||
test('VectorTileFeature', function(t) {
|
||||
var emptyFeature = new VectorTileFeature(new Protobuf(new Buffer([])));
|
||||
t.ok(emptyFeature, 'can be created with no values');
|
||||
t.ok(Array.isArray(VectorTileFeature.types));
|
||||
t.deepEqual(VectorTileFeature.types, ['Unknown', 'Point', 'LineString', 'Polygon']);
|
||||
t.end();
|
||||
test('VectorTileFeature', () => {
|
||||
const emptyFeature = new VectorTileFeature(new Protobuf(Buffer.alloc(0)));
|
||||
assert.ok(emptyFeature, 'can be created with no values');
|
||||
assert.ok(Array.isArray(VectorTileFeature.types));
|
||||
assert.deepEqual(VectorTileFeature.types, ['Unknown', 'Point', 'LineString', 'Polygon']);
|
||||
});
|
||||
|
||||
test('https://github.com/mapbox/vector-tile-js/issues/15', function(t) {
|
||||
var data = fs.readFileSync(__dirname + '/fixtures/lots-of-tags.vector.pbf');
|
||||
var tile = new VectorTile(new Protobuf(data));
|
||||
t.ok(tile.layers["stuttgart-rails"].feature(0));
|
||||
t.end();
|
||||
test('https://github.com/mapbox/vector-tile-js/issues/15', () => {
|
||||
const tile = getFixtureTile('lots-of-tags.vector');
|
||||
assert.ok(tile.layers['stuttgart-rails'].feature(0));
|
||||
});
|
||||
|
||||
test('https://github.com/mapbox/mapbox-gl-js/issues/1019', function(t) {
|
||||
var data = fs.readFileSync(__dirname + '/fixtures/12-1143-1497.vector.pbf');
|
||||
var tile = new VectorTile(new Protobuf(data));
|
||||
t.ok(tile.layers["water"].feature(1).loadGeometry());
|
||||
t.end();
|
||||
test('https://github.com/mapbox/mapbox-gl-js/issues/1019', () => {
|
||||
const tile = getFixtureTile('12-1143-1497.vector');
|
||||
assert.ok(tile.layers.water.feature(1).loadGeometry());
|
||||
});
|
||||
|
||||
test('https://github.com/mapbox/vector-tile-js/issues/60', function(t) {
|
||||
var data = fs.readFileSync(__dirname + '/fixtures/multipolygon-with-closepath.pbf');
|
||||
var tile = new VectorTile(new Protobuf(data));
|
||||
for (var id in tile.layers) {
|
||||
var layer = tile.layers[id];
|
||||
for (var i = 0; i < layer.length; i++) {
|
||||
test('https://github.com/mapbox/vector-tile-js/issues/60', () => {
|
||||
const tile = getFixtureTile('multipolygon-with-closepath');
|
||||
for (const id in tile.layers) {
|
||||
const layer = tile.layers[id];
|
||||
for (let i = 0; i < layer.length; i++) {
|
||||
layer.feature(i).loadGeometry();
|
||||
}
|
||||
}
|
||||
t.end();
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user