Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modernize (ES entry point, drop transpilation, better tests) #180

Merged
merged 2 commits into from
Jun 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
language: node_js
node_js: 14
node_js: 20
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,18 +74,18 @@ GeoJSON-VT only operates on zoom levels up to 24.

### Install

Install using NPM (`npm install geojson-vt`) or Yarn (`yarn add geojson-vt`), then:
Install using NPM (`npm install geojson-vt`), then:

```js
// import as a ES module
import geojsonvt from 'geojson-vt';

// or require in Node / Browserify
const geojsonvt = require('geojson-vt');
// import from a CDN in the browser:
import geojsonvt from 'https://esm.run/geojson-vt';
```

Or use a browser build directly:

```html
<script src="https://unpkg.com/geojson-vt@3.2.0/geojson-vt.js"></script>
<script src="https://unpkg.com/geojson-vt/geojson-vt.js"></script>
```
19 changes: 11 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
"version": "3.2.1",
"description": "Slice GeoJSON data into vector tiles efficiently",
"homepage": "https://github.com/mapbox/geojson-vt",
"type": "module",
"exports": "src/index.js",
"sideEffects": false,
"keywords": [
"spatial",
"geojson",
Expand All @@ -19,26 +22,26 @@
"jsdelivr": "geojson-vt.js",
"unpkg": "geojson-vt.js",
"devDependencies": {
"@rollup/plugin-buble": "^1.0.2",
"@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-terser": "^0.4.4",
"benchmark": "^2.1.4",
"c8": "^7.12.0",
"eslint": "^8.33.0",
"c8": "^10.1.1",
"eslint": "^8.57.0",
"eslint-config-mourner": "^3.0.0",
"esm": "^3.2.25",
"rollup": "^3.12.0",
"tape": "^5.6.3"
"rollup": "^3.29.3"
},
"eslintConfig": {
"extends": "mourner",
"parserOptions": {
"ecmaVersion": 2020
},
"globals": {
"topojson": true
}
},
"license": "ISC",
"scripts": {
"pretest": "eslint src/*.js test/*.js debug/viz.js",
"test": "c8 tape -r esm test/test-*.js",
"test": "c8 node --test",
"build": "rollup -c",
"watch": "rollup -cw",
"prepublishOnly": "npm run test && npm run build"
Expand Down
12 changes: 2 additions & 10 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import terser from '@rollup/plugin-terser';
import buble from '@rollup/plugin-buble';

const config = (file, plugins) => ({
input: 'src/index.js',
Expand All @@ -12,14 +11,7 @@ const config = (file, plugins) => ({
plugins
});

const bubleConfig = {
transforms: {
dangerousForOf: true,
},
objectAssign: 'Object.assign',
};

export default [
config('geojson-vt-dev.js', [buble(bubleConfig)]),
config('geojson-vt.js', [terser(), buble(bubleConfig)])
config('geojson-vt-dev.js', []),
config('geojson-vt.js', [terser()])
];
28 changes: 11 additions & 17 deletions test/test-clip.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@

import test from 'tape';
import test from 'node:test';
import assert from 'node:assert/strict';

import clip from '../src/clip.js';

/*eslint comma-spacing:0*/

const geom1 = [0,0,0,50,0,0,50,10,0,20,10,0,20,20,0,30,20,0,30,30,0,50,30,0,50,40,0,25,40,0,25,50,0,0,50,0,0,60,0,25,60,0];
const geom2 = [0,0,0,50,0,0,50,10,0,0,10,0];

test('clips polylines', (t) => {
test('clips polylines', () => {

const clipped = clip([
{geometry: geom1, type: 'LineString', tags: 1, minX: 0, minY: 0, maxX: 50, maxY: 60},
Expand All @@ -25,12 +27,10 @@ test('clips polylines', (t) => {
[40,10,1,10,10,1]], tags: 2, minX: 10, minY: 0, maxX: 40, maxY: 10}
];

t.equal(JSON.stringify(clipped), JSON.stringify(expected));

t.end();
assert.equal(JSON.stringify(clipped), JSON.stringify(expected));
});

test('clips lines with line metrics on', (t) => {
test('clips lines with line metrics on', () => {

const geom = geom1.slice();
geom.size = 0;
Expand All @@ -45,19 +45,17 @@ test('clips lines with line metrics on', (t) => {
const clipped = clip([{geometry: geom, type: 'LineString', minX: 0, minY: 0, maxX: 50, maxY: 60}],
1, 10, 40, 0, -Infinity, Infinity, {lineMetrics: true});

t.same(
assert.deepEqual(
clipped.map(f => [f.geometry.start, f.geometry.end]),
[[10, 40], [70, 130], [160, 200], [230, 245]]
);

t.end();
});

function closed(geometry) {
return [geometry.concat(geometry.slice(0, 3))];
}

test('clips polygons', (t) => {
test('clips polygons', () => {

const clipped = clip([
{geometry: closed(geom1), type: 'Polygon', tags: 1, minX: 0, minY: 0, maxX: 50, maxY: 60},
Expand All @@ -69,20 +67,16 @@ test('clips polygons', (t) => {
{id: null, type: 'Polygon', geometry: [[10,0,1,40,0,1,40,10,1,10,10,1,10,0,1]], tags: 2, minX: 10, minY: 0, maxX: 40, maxY: 10}
];

t.equal(JSON.stringify(clipped), JSON.stringify(expected));

t.end();
assert.equal(JSON.stringify(clipped), JSON.stringify(expected));
});

test('clips points', (t) => {
test('clips points', () => {

const clipped = clip([
{geometry: geom1, type: 'MultiPoint', tags: 1, minX: 0, minY: 0, maxX: 50, maxY: 60},
{geometry: geom2, type: 'MultiPoint', tags: 2, minX: 0, minY: 0, maxX: 50, maxY: 10}
], 1, 10, 40, 0, -Infinity, Infinity, {});

t.same(clipped, [{id: null, type: 'MultiPoint',
assert.deepEqual(clipped, [{id: null, type: 'MultiPoint',
geometry: [20,10,0,20,20,0,30,20,0,30,30,0,25,40,0,25,50,0,25,60,0], tags: 1, minX: 20, minY: 10, maxX: 30, maxY: 60}]);

t.end();
});
29 changes: 13 additions & 16 deletions test/test-full.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

import test from 'tape';
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'fs';
import path from 'path';

import geojsonvt from '../src/index.js';

testTiles('us-states.json', 'us-states-tiles.json', {indexMaxZoom: 7, indexMaxPoints: 200});
Expand All @@ -13,35 +14,31 @@ testTiles('single-geom.json', 'single-geom-tiles.json', {indexMaxZoom: 0, indexM
testTiles('ids.json', 'ids-promote-id-tiles.json', {indexMaxZoom: 0, promoteId: 'prop0'});
testTiles('ids.json', 'ids-generate-id-tiles.json', {indexMaxZoom: 0, generateId: true});

test('throws on invalid GeoJSON', (t) => {
t.throws(() => {
test('throws on invalid GeoJSON', () => {
assert.throws(() => {
genTiles({type: 'Pologon'});
});
t.end();
});

function testTiles(inputFile, expectedFile, options) {
test(`full tiling test: ${ expectedFile.replace('-tiles.json', '')}`, (t) => {
test(`full tiling test: ${ expectedFile.replace('-tiles.json', '')}`, () => {
const tiles = genTiles(getJSON(inputFile), options);
// fs.writeFileSync(path.join(__dirname, '/fixtures/' + expectedFile), JSON.stringify(tiles));
t.same(tiles, getJSON(expectedFile));
t.end();
assert.deepEqual(tiles, getJSON(expectedFile));
});
}

test('empty geojson', (t) => {
t.same({}, genTiles(getJSON('empty.json')));
t.end();
test('empty geojson', () => {
assert.deepEqual({}, genTiles(getJSON('empty.json')));
});

test('null geometry', (t) => {
test('null geometry', () => {
// should ignore features with null geometry
t.same({}, genTiles(getJSON('feature-null-geometry.json')));
t.end();
assert.deepEqual({}, genTiles(getJSON('feature-null-geometry.json')));
});

function getJSON(name) {
return JSON.parse(fs.readFileSync(path.join(__dirname, `/fixtures/${ name}`)));
return JSON.parse(fs.readFileSync(new URL(`fixtures/${name}`, import.meta.url)));
}

function genTiles(data, options) {
Expand All @@ -55,7 +52,7 @@ function genTiles(data, options) {
for (const id in index.tiles) {
const tile = index.tiles[id];
const z = tile.z;
output[`z${ z }-${ tile.x }-${ tile.y}`] = index.getTile(z, tile.x, tile.y).features;
output[`z${z}-${tile.x}-${tile.y}`] = index.getTile(z, tile.x, tile.y).features;
}

return output;
Expand Down
46 changes: 20 additions & 26 deletions test/test-get-tile.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

import test from 'tape';
import test from 'node:test';
import assert from 'node:assert/strict';
import fs from 'fs';
import path from 'path';

import geojsonvt from '../src/index.js';

const square = [{
Expand All @@ -11,56 +12,51 @@ const square = [{
id: '42'
}];

test('getTile: us-states.json', (t) => {
test('getTile: us-states.json', () => {
const log = console.log;

console.log = function () {};
const index = geojsonvt(getJSON('us-states.json'), {debug: 2});

t.same(index.getTile(7, 37, 48).features, getJSON('us-states-z7-37-48.json'), 'z7-37-48');
t.same(index.getTile('7', '37', '48').features, getJSON('us-states-z7-37-48.json'), 'z, x, y as strings');
assert.deepEqual(index.getTile(7, 37, 48).features, getJSON('us-states-z7-37-48.json'), 'z7-37-48');
assert.deepEqual(index.getTile('7', '37', '48').features, getJSON('us-states-z7-37-48.json'), 'z, x, y as strings');

t.same(index.getTile(9, 148, 192).features, square, 'z9-148-192 (clipped square)');
// t.same(index.getTile(11, 592, 768).features, square, 'z11-592-768 (clipped square)');
assert.deepEqual(index.getTile(9, 148, 192).features, square, 'z9-148-192 (clipped square)');

t.equal(index.getTile(11, 800, 400), null, 'non-existing tile');
t.equal(index.getTile(-5, 123.25, 400.25), null, 'invalid tile');
t.equal(index.getTile(25, 200, 200), null, 'invalid tile');
assert.equal(index.getTile(11, 800, 400), null, 'non-existing tile');
assert.equal(index.getTile(-5, 123.25, 400.25), null, 'invalid tile');
assert.equal(index.getTile(25, 200, 200), null, 'invalid tile');

console.log = log;

t.equal(index.total, 37);

t.end();
assert.equal(index.total, 37);
});

test('getTile: unbuffered tile left/right edges', (t) => {
test('getTile: unbuffered tile left/right edges', () => {
const index = geojsonvt({
type: 'LineString',
coordinates: [[0, 90], [0, -90]]
}, {
buffer: 0
});

t.same(index.getTile(2, 1, 1), null);
t.same(index.getTile(2, 2, 1).features, [{geometry: [[[0, 0], [0, 4096]]], type: 2, tags: null}]);
t.end();
assert.deepEqual(index.getTile(2, 1, 1), null);
assert.deepEqual(index.getTile(2, 2, 1).features, [{geometry: [[[0, 0], [0, 4096]]], type: 2, tags: null}]);
});

test('getTile: unbuffered tile top/bottom edges', (t) => {
test('getTile: unbuffered tile top/bottom edges', () => {
const index = geojsonvt({
type: 'LineString',
coordinates: [[-90, 66.51326044311188], [90, 66.51326044311188]]
}, {
buffer: 0
});

t.same(index.getTile(2, 1, 0).features, [{geometry: [[[0, 4096], [4096, 4096]]], type: 2, tags: null}]);
t.same(index.getTile(2, 1, 1).features, []);
t.end();
assert.deepEqual(index.getTile(2, 1, 0).features, [{geometry: [[[0, 4096], [4096, 4096]]], type: 2, tags: null}]);
assert.deepEqual(index.getTile(2, 1, 1).features, []);
});

test('getTile: polygon clipping on the boundary', (t) => {
test('getTile: polygon clipping on the boundary', () => {
const index = geojsonvt({
type: 'Polygon',
coordinates: [[
Expand All @@ -74,15 +70,13 @@ test('getTile: polygon clipping on the boundary', (t) => {
buffer: 1024
});

t.same(index.getTile(5, 19, 9).features, [{
assert.deepEqual(index.getTile(5, 19, 9).features, [{
geometry: [[[3072, 3072], [5120, 3072], [5120, 5120], [3072, 5120], [3072, 3072]]],
type: 3,
tags: null
}]);

t.end();
});

function getJSON(name) {
return JSON.parse(fs.readFileSync(path.join(__dirname, `/fixtures/${ name}`)));
return JSON.parse(fs.readFileSync(new URL(`fixtures/${name}`, import.meta.url)));
}
Loading
Loading