New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

geojson-vt

Package Overview
Dependencies
Maintainers
1
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

geojson-vt - npm Package Compare versions

Comparing version 1.0.1 to 1.1.0

58

package.json
{
"name": "geojson-vt",
"version": "1.0.1",
"version": "1.1.0",
"description": "Slice GeoJSON data into vector tiles efficiently",

@@ -20,25 +20,49 @@ "homepage": "https://github.com/mapbox/geojson-vt",

"benchmark": "^1.0.0",
"browserify": "^7.0.0",
"eslint": "^0.15.1",
"faucet": "0.0.1",
"jshint": "^2.5.10",
"tape": "^3.0.3",
"uglify-js": "^2.4.16",
"watchify": "^2.1.1"
},
"scripts": {
"test": "jshint src/*.js test/test-*.js && tape test/test-*.js | faucet",
"build-min": "browserify src/index.js -s geojsonvt -o geojson-vt.js",
"build-dev": "browserify -d src/index.js -s geojsonvt -o debug/geojson-vt-dev.js",
"watch": "watchify -v -d src/index.js -s geojsonvt -o debug/geojson-vt-dev.js"
"test": "eslint src/*.js test/test-*.js && tape test/test-*.js | faucet",
"build-min": "browserify src/index.js -s geojsonvt | uglifyjs -c -m -o geojson-vt.js",
"build-dev": "browserify -d src/index.js -s geojsonvt -o geojson-vt-dev.js",
"watch": "watchify -v -d src/index.js -s geojsonvt -o geojson-vt-dev.js"
},
"jshintConfig": {
"undef": true,
"unused": true,
"trailing": true,
"eqeqeq": true,
"indent": 4,
"node": true,
"latedef": "nofunc",
"strict": true,
"globalstrict": true,
"quotmark": true
"eslintConfig": {
"rules": {
"no-use-before-define": [
2,
"nofunc"
],
"camelcase": 2,
"space-after-function-name": 2,
"space-in-parens": 2,
"space-before-blocks": 2,
"space-after-keywords": 2,
"comma-style": 2,
"no-lonely-if": 2,
"no-else-return": 2,
"new-cap": 2,
"no-empty": 2,
"no-new": 2,
"key-spacing": 2,
"no-multi-spaces": 0,
"space-in-brackets": 2,
"brace-style": 2,
"indent": 2,
"quotes": [
2,
"single"
],
"curly": 0,
"no-constant-condition": 0
},
"env": {
"node": true,
"browser": true
}
}
}

@@ -1,11 +0,32 @@

### GeoJSON Vector Tiles
### geojson-vt — GeoJSON Vector Tiles
A highly efficient JavaScript library for slicing GeoJSON data
into [vector tiles](https://github.com/mapbox/vector-tile-spec/)
(or rather their JSON equivalent) on the fly,
primarily for rendering purposes.
A highly efficient JavaScript library for **slicing GeoJSON data into vector tiles on the fly**,
primarily designed to enable rendering and interacting with large geospatial datasets
on the browser side (without a server).
Created to power GeoJSON rendering in [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js),
but can be useful for other data visualization purposes.
Created to power GeoJSON in [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js),
but can be useful in other visualization platforms
like [Leaflet](https://github.com/Leaflet/Leaflet) and [d3](https://github.com/mbostock/d3).
It can also be easily used on the server as well.
Resulting tiles conform to the JSON equivalent
of the [vector tile specification](https://github.com/mapbox/vector-tile-spec/).
To make data rendering and interaction fast, the tiles are simplified,
retaining the minimum level of detail appropriate for each zoom level
(simplifying shapes, filtering out tiny polygons and polylines).
#### Demo
Here's **geojson-vt** action in [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js),
dynamically loading a 100Mb US zip codes GeoJSON with 5.4 million points:
![](https://cloud.githubusercontent.com/assets/25395/5360312/86028d8e-7f91-11e4-811f-87f24acb09ca.gif)
There's a convenient debug page to test out **geojson-vt** on different data.
Make sure you have the [dev version built](#browser-builds);
open `debug/index.html` in your browser,
and drag any GeoJSON on the page, watching the console.
![](https://cloud.githubusercontent.com/assets/25395/5363235/41955c6e-7fa8-11e4-9575-a66ef54cb6d9.gif)
#### Usage

@@ -15,8 +36,3 @@

// build an initial index of tiles
var tileIndex = geojsonvt(geoJSON, {
baseZoom: 14, // max zoom to preserve detail on
maxZoom: 14, // zoom to slice down on first pass
maxPoints: 100, // during first pass, stop slicing each tile below this number of points
debug: 0 // debug level: 1 = some timing info; 2 = individual tiles timing;
});
var tileIndex = geojsonvt(geoJSON);

@@ -27,8 +43,25 @@ // request a particular tile

#### Demo
#### Options
To see a **geojson-vt** in action, run `npm run build-dev`,
then open `debug/index.html` in your browser and drag any GeoJSON on the page.
It was tested on files up to 100Mb:
You can fine-tune the results with an options object,
although the defaults are sensible and work well for most use cases.
![](https://cloud.githubusercontent.com/assets/25395/5328953/4edebdac-7d64-11e4-8e99-dddfd00851fb.gif)
```js
var tileIndes = geojsonvt(data, {
baseZoom: 14, // max zoom to preserve detail on
maxZoom: 4, // zoom to slice down to on first pass
maxPoints: 100, // stop slicing each tile below this number of points
tolerance: 3, // simplification tolerance (higher means simpler)
extent: 4096, // tile extent (both width and height)
buffer: 64, // tile buffer on each side
debug: 0 // logging level (0 to disable, 1 or 2)
});
```
#### Browser builds
```bash
npm install
npm run build-dev # development build, used by the debug page
npm run build-min # minified production build
```

@@ -41,2 +41,4 @@ 'use strict';

if (slices.length) {
// if a feature got clipped, it will likely get clipped on the next zoom level as well,
// so there's no need to recalculate bboxes
clipped.push({

@@ -120,2 +122,3 @@ geometry: slices,

// add the last point
a = points[len - 1];

@@ -125,6 +128,4 @@ ak = a[axis];

var sliceLen = slice.length;
// close the polygon if its endpoints are not the same after clipping
if (closed && slice[0] !== slice[sliceLen - 1]) slice.push(slice[0]);
if (closed && slice[0] !== slice[slice.length - 1]) slice.push(slice[0]);

@@ -140,4 +141,7 @@ // add the final slice

if (slice.length) {
// we don't recalculate the area/length of the unclipped geometry because the case where it goes
// below the visibility threshold as a result of clipping is rare, so we avoid doing unnecessary work
slice.area = area;
slice.dist = dist;
slices.push(slice);

@@ -144,0 +148,0 @@ }

@@ -7,3 +7,3 @@ 'use strict';

// converts GeoJSON feature into an intermediate JSON vector format with projection & simplification
// converts GeoJSON feature into an intermediate projected JSON vector format with simplification data

@@ -21,2 +21,3 @@ function convert(data, tolerance) {

} else {
// single geometry or a geometry collection
convertFeature(features, {geometry: data}, tolerance);

@@ -77,4 +78,4 @@ }

tags: tags || null,
min: [1, 1],
max: [0, 0]
min: [1, 1], // initial bbox values;
max: [0, 0] // note that all coords are in [0..1] range
};

@@ -106,11 +107,15 @@ calcBBox(feature);

function calcSize(points) {
var sum = 0,
var area = 0,
dist = 0;
for (var i = 0, a, b; i < points.length - 1; i++) {
a = b || points[i];
b = points[i + 1];
sum += a[0] * b[1] - b[0] * a[1];
dist += Math.abs(b[0] - a[0]) + Math.abs(b[1] - a[1]); // Manhattan distance
area += a[0] * b[1] - b[0] * a[1];
// use Manhattan distance instead of Euclidian one to avoid expensive square root computation
dist += Math.abs(b[0] - a[0]) + Math.abs(b[1] - a[1]);
}
points.area = Math.abs(sum / 2);
points.area = Math.abs(area / 2);
points.dist = dist;

@@ -125,13 +130,9 @@ }

if (feature.type === 1) {
calcRingBBOX(min, max, geometry);
} else {
for (var i = 0; i < geometry.length; i++) {
calcRingBBOX(min, max, geometry[i]);
}
}
if (feature.type === 1) calcRingBBox(min, max, geometry);
else for (var i = 0; i < geometry.length; i++) calcRingBBox(min, max, geometry[i]);
return feature;
}
function calcRingBBOX(min, max, points) {
function calcRingBBox(min, max, points) {
for (var i = 0, p; i < points.length; i++) {

@@ -138,0 +139,0 @@ p = points[i];

@@ -5,13 +5,7 @@ 'use strict';

var clip = require('./clip'),
convert = require('./convert'),
createTile = require('./tile'),
var convert = require('./convert'), // GeoJSON conversion and preprocessing
clip = require('./clip'), // stripe clipping algorithm
createTile = require('./tile'); // final simplified tile generation
extent = 4096,
padding = 8 / 512, // padding on each side of the tile (in percentage of extent)
minPx = Math.round(-padding * extent),
maxPx = Math.round((1 + padding) * extent);
function geojsonvt(data, options) {

@@ -28,4 +22,4 @@ return new GeoJSONVT(data, options);

var z2 = 1 << options.baseZoom,
features = convert(data, options.tolerance / (z2 * extent));
var z2 = 1 << options.baseZoom, // 2^z
features = convert(data, options.tolerance / (z2 * options.extent));

@@ -37,6 +31,7 @@ this.tiles = {};

console.time('generate tiles up to z' + options.maxZoom);
this.stats = [];
this.stats = {};
this.total = 0;
}
// start slicing from the top tile down
this.splitTile(features, 0, 0, 0);

@@ -47,3 +42,3 @@

console.timeEnd('generate tiles up to z' + options.maxZoom);
console.log('tiles generated:', this.total, this.stats);
console.log('tiles generated:', this.total, JSON.stringify(this.stats));
}

@@ -53,7 +48,9 @@ }

GeoJSONVT.prototype.options = {
maxZoom: 4,
baseZoom: 14,
maxPoints: 100,
tolerance: 3,
debug: 0
baseZoom: 14, // max zoom to preserve detail on
maxZoom: 4, // zoom to slice down to on first pass
maxPoints: 100, // stop slicing a tile below this number of points
tolerance: 3, // simplification tolerance (higher means simpler)
extent: 4096, // tile extent
buffer: 64, // tile buffer on each side
debug: 0 // logging level (0, 1 or 2)
};

@@ -65,4 +62,7 @@

options = this.options,
debug = options.debug;
debug = options.debug,
extent = options.extent,
buffer = options.buffer;
// avoid recursion by using a processing queue
while (stack.length) {

@@ -90,3 +90,4 @@ features = stack.shift();

}
this.stats[z] = (this.stats[z] || 0) + 1;
var key = 'z' + z + ':';
this.stats[key] = (this.stats[key] || 0) + 1;
this.total++;

@@ -97,3 +98,3 @@ }

if (!cz && (z === options.maxZoom || tile.numPoints <= options.maxPoints ||
isClippedSquare(tile.features)) || z === options.baseZoom || z === cz) {
isClippedSquare(tile.features, extent, buffer)) || z === options.baseZoom || z === cz) {
tile.source = features;

@@ -108,3 +109,4 @@ continue; // stop tiling

var k1 = 0.5 * padding,
// values we'll use for clipping
var k1 = 0.5 * buffer / extent,
k2 = 0.5 - k1,

@@ -151,3 +153,4 @@ k3 = 0.5 + k1,

var debug = this.options.debug;
var options = this.options,
debug = options.debug;

@@ -170,4 +173,5 @@ if (debug > 1) console.log('drilling down to z%d-%d-%d', z, x, y);

// if we found a parent tile containing the original geometry, we can drill down from it
if (parent.source) {
if (isClippedSquare(parent.features)) return parent;
if (isClippedSquare(parent.features, options.extent, options.buffer)) return parent;

@@ -183,3 +187,3 @@ if (debug) console.time('drilling down');

// checks whether a tile is a whole-area fill after clipping; if it is, there's no sense slicing it further
function isClippedSquare(features) {
function isClippedSquare(features, extent, buffer) {
if (features.length !== 1) return false;

@@ -192,4 +196,4 @@

var p = feature.geometry[0][i];
if ((p[0] !== minPx && p[0] !== maxPx) ||
(p[1] !== minPx && p[1] !== maxPx)) return false;
if ((p[0] !== -buffer && p[0] !== extent + buffer) ||
(p[1] !== -buffer && p[1] !== extent + buffer)) return false;
}

@@ -206,3 +210,2 @@ return true;

}
function intersectY(a, b, y) {

@@ -213,6 +216,4 @@ return [(y - a[1]) * (b[0] - a[0]) / (b[1] - a[1]) + a[0], y, 1];

function extend(dest, src) {
for (var i in src) {
dest[i] = src[i];
}
for (var i in src) dest[i] = src[i];
return dest;
}

@@ -16,5 +16,7 @@ 'use strict';

// always retain the endpoints (1 is the max value)
points[first][2] = 1;
points[last][2] = 1;
// avoid recursion by using a stack
while (last) {

@@ -34,3 +36,3 @@

if (maxSqDist > sqTolerance) {
points[index][2] = maxSqDist;
points[index][2] = maxSqDist; // save the point importance in squared pixels as a z coordinate
stack.push(first, index, index, last);

@@ -37,0 +39,0 @@ }

@@ -52,3 +52,3 @@ 'use strict';

p = ring[j];
// keep points with significance > tolerance and points introduced by clipping
// keep points with importance > tolerance
if (noSimplify || p[2] > sqTolerance) {

@@ -55,0 +55,0 @@ transformedRing.push(transformPoint(p, z2, tx, ty, extent));

@@ -6,2 +6,3 @@ 'use strict';

/*eslint comma-spacing:0*/

@@ -26,10 +27,10 @@ function intersectX(p0, p1, x) {

var expected = [
{geometry:[
{geometry: [
[[10,0],[40,0]],
[[40,10],[20,10],[20,20],[30,20],[30,30],[40,30]],
[[40,40],[25,40],[25,50],[10,50]],
[[10,60],[25,60]]], type:2,tags:1},
{geometry:[
[[10,60],[25,60]]], type: 2, tags: 1},
{geometry: [
[[10,0],[40,0]],
[[40,10],[10,10]]], type:2,tags:2}];
[[40,10],[10,10]]], type: 2, tags: 2}];

@@ -53,5 +54,5 @@ t.equal(JSON.stringify(clipped), JSON.stringify(expected));

var expected = [
{geometry:[[[10,0],[40,0],[40,10],[20,10],[20,20],[30,20],[30,30],[40,30],
[40,40],[25,40],[25,50],[10,50],[10,60],[25,60],[10,24],[10,0]]],type:3,tags:1},
{geometry:[[[10,0],[40,0],[40,10],[10,10],[10,0]]],type:3,tags:2}
{geometry: [[[10,0],[40,0],[40,10],[20,10],[20,20],[30,20],[30,30],[40,30],
[40,40],[25,40],[25,50],[10,50],[10,60],[25,60],[10,24],[10,0]]], type: 3, tags: 1},
{geometry: [[[10,0],[40,0],[40,10],[10,10],[10,0]]], type: 3, tags: 2}
];

@@ -71,5 +72,5 @@

t.same(clipped, [{geometry:[[20,10],[20,20],[30,20],[30,30],[25,40],[25,50],[25,60]],type:1,tags:1}]);
t.same(clipped, [{geometry: [[20,10],[20,20],[30,20],[30,30],[25,40],[25,50],[25,60]], type: 1, tags: 1}]);
t.end();
});

@@ -6,2 +6,4 @@ 'use strict';

/*eslint comma-spacing:0, no-shadow: 0*/
var points = [

@@ -8,0 +10,0 @@ [0.22455,0.25015],[0.22691,0.24419],[0.23331,0.24145],[0.23498,0.23606],

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc