Skip to content

Commit

Permalink
Merge pull request #107 from mapbox/further_cleanup_improvements
Browse files Browse the repository at this point in the history
Further cleanup improvements
  • Loading branch information
sheindel authored Aug 23, 2023
2 parents 8768a97 + d3773a5 commit 6149bde
Show file tree
Hide file tree
Showing 9 changed files with 170 additions and 46 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ example/*.dbf
example/*.shp
example/*.shx
yarn.lock
package-lock.json
yarn.lock
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
[![Build Status](https://secure.travis-ci.org/mapbox/shp-write.svg?branch=master)](http://travis-ci.org/mapbox/shp-write)

# shp-write

# ANNOUNCEMENT!

The npm package location (and subsequently unpkg url) for this repo has changed!

tl;dr: `shp-write` -> `@mapbox/shp-write`


Writes shapefile in pure javascript. Uses [dbf](https://github.com/tmcw/dbf)
for the data component, and [jsZIP](http://stuk.github.io/jszip/) to generate
ZIP file downloads in-browser.
Expand Down Expand Up @@ -77,7 +82,7 @@ const options = {
types: {
point: "mypoints",
polygon: "mypolygons",
line: "mylines",
polyline: "mylines",
},
};

Expand Down Expand Up @@ -112,6 +117,15 @@ const zipData = shpwrite.zip(
);
```

## Custom .prj file
To pass a custom [WKT string](http://www.opengeospatial.org/standards/wkt-crs) in the .prj file to define a different projection the prj option can be used:

```js
var options = {
prj: 'PROJCS["Amersfoort / RD New",GEOGCS["Amersfoort",DATUM["D_Amersfoort",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0],UNIT["Degree",0.017453292519943295]],PROJECTION["Stereographic_North_Pole"],PARAMETER["standard_parallel_1",52.15616055555555],PARAMETER["central_meridian",5.38763888888889],PARAMETER["scale_factor",0.9999079],PARAMETER["false_easting",155000],PARAMETER["false_northing",463000],UNIT["Meter",1]]'
}
```

## API
### `write(data, geometrytype, geometries, callback)`

Expand Down
1 change: 1 addition & 0 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ declare module "@mapbox/shp-write" {
export interface DownloadOptions {
folder?: string;
filename?: string;
prj?: string;
types?: {
point?: string;
polygon?: string;
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<script src='bundle.js'></script>
<script src='shpwrite.js'></script>
87 changes: 87 additions & 0 deletions indexTest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
require('./src/download')({
'type': 'FeatureCollection',
'features': [{
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Polygon',
'coordinates': [
[
[
24.936046600341797,
60.175245406790246
],
[
24.920597076416016,
60.15577400466598
],
[
24.953556060791016,
60.1570553725571
],
[
24.936046600341797,
60.175245406790246
]
],
[
[
24.93523120880127,
60.169247224327165
],
[
24.945573806762695,
60.15874243076889
],
[
24.928064346313477,
60.15825127085746
],
[
24.93523120880127,
60.169247224327165
]
]
]
}
},
{
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
[
24.920940399169922,
60.17977000114811
],
[
24.953556060791016,
60.17486121440947
]
]
}
},
{
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'Point',
'coordinates': [
24.925403594970703,
60.171830205844614
]
}
}
]
}, {
file: 'my_zip_filename', // if empty, filename will be download.zip
folder: 'my_internal_shapes_folder', // leave empty to put in root
outputType: 'blob',
compression: 'DEFLATE',
types: {
point: 'points',
polygon: 'polygons',
polyline: 'lines'
}
});
13 changes: 7 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"name": "@mapbox/shp-write",
"version": "0.4.2",
"version": "0.4.3",
"description": "write shapefiles from pure javascript",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"test": "mocha -R spec",
"prepublish": "npm run make",
"make": "browserify -s shpwrite ./ > shpwrite.js"
"make": "browserify -s shpwrite ./ > shpwrite.js",
"make-test": "browserify indexTest.js > shpwrite.js"
},
"repository": {
"type": "git",
Expand All @@ -31,14 +32,14 @@
},
"dependencies": {
"dbf": "0.2.0",
"jszip": "3.6.0",
"file-saver": "2.0.5"
"file-saver": "2.0.5",
"jszip": "^3.10.1"
},
"devDependencies": {
"browserify": "^13.0.0",
"browserify": "^17.0.0",
"cz-conventional-changelog": "^1.2.0",
"expect.js": "~0.3.1",
"mocha": "~2.4.5"
"mocha": "^10.2.0"
},
"config": {
"commitizen": {
Expand Down
45 changes: 33 additions & 12 deletions src/geojson.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,53 @@ module.exports.multiline = justType("MultiLineString", "POLYLINE");
module.exports.polygon = justType("Polygon", "POLYGON");
module.exports.multipolygon = justType("MultiPolygon", "POLYGON");

function justType(type, TYPE) {
/**
* Generate a function that returns an object with the geometries, properties, and type of the given GeoJSON type
* @param {string} type the GeoJSON type
* @param {string} TYPE the Shapefile type
* @returns {(gj: { features: Feature[] }) => { geometries: number[] | number[][] | number[][][] | number[][][][], properties: {Object.<string, string>}, type: string }}
*/
function justType(gjType, shpType) {
return function (gj) {
var oftype = gj.features.filter(isType(type));
var oftype = gj.features.filter(isType(gjType));
return {
geometries: oftype.map(justCoords),
geometries: shpType === 'POLYLINE' ? [oftype.map(justCoords)] : oftype.map(justCoords),
properties: oftype.map(justProps),
type: TYPE,
type: shpType,
};
};
}

function justCoords(t) {
return t.geometry.coordinates;
/**
*
* @param {Feature} feature The feature to get the coordinates from
* @returns {number[] | number[][] | number[][][] | number[][][][]}
*/
function justCoords(feature) {
return feature.geometry.coordinates;
}

function justProps(t) {
return t.properties;
/**
*
* @param {Feature} feature The feature to get the properties from
* @returns {Object.<string, string>}
*/
function justProps(feature) {
return feature.properties;
}

function isType(t) {
if (Array.isArray(t))
/**
* Generate a function that filters features based on their geometry.type
* @param {string | string[]} type the GeoJSON type to filter with
* @returns {(f: Feature) => boolean} a function that returns true if the feature's type is in {@link type}
*/
function isType(type) {
if (Array.isArray(type))
return function (f) {
return t.includes(f.geometry.type);
return type.includes(f.geometry.type);
};
else
return function (f) {
return f.geometry.type === t;
return f.geometry.type === type;
};
}
35 changes: 15 additions & 20 deletions src/write.js
Original file line number Diff line number Diff line change
@@ -1,35 +1,30 @@
var types = require('./types'),
dbf = require('dbf'),
prj = require('./prj'),
ext = require('./extent'),
getFields = require('./fields'),
assert = require('assert'),
pointWriter = require('./points'),
polyWriter = require('./poly');
var types = require('./types');
var dbf = require('dbf');
var prj = require('./prj');
var pointWriter = require('./points');
var polyWriter = require('./poly');

var writers = {
1: pointWriter,
5: polyWriter,
3: polyWriter
};

var recordHeaderLength = 8;

module.exports = write;

// Low-level writing interface
function write(rows, geometry_type, geometries, callback) {

var TYPE = types.geometries[geometry_type],
writer = writers[TYPE],
parts = writer.parts(geometries, TYPE),
shpLength = 100 + (parts - geometries.length) * 4 + writer.shpLength(geometries),
shxLength = 100 + writer.shxLength(geometries),
shpBuffer = new ArrayBuffer(shpLength),
shpView = new DataView(shpBuffer),
shxBuffer = new ArrayBuffer(shxLength),
shxView = new DataView(shxBuffer),
extent = writer.extent(geometries);
var TYPE = types.geometries[geometry_type];
var writer = writers[TYPE];
var parts = writer.parts(geometries, TYPE);
var shpLength = 100 + (parts - geometries.length) * 4 + writer.shpLength(geometries);
var shxLength = 100 + writer.shxLength(geometries);
var shpBuffer = new ArrayBuffer(shpLength);
var shpView = new DataView(shpBuffer);
var shxBuffer = new ArrayBuffer(shxLength);
var shxView = new DataView(shxBuffer);
var extent = writer.extent(geometries);

writeHeader(shpView, TYPE);
writeHeader(shxView, TYPE);
Expand Down
11 changes: 7 additions & 4 deletions src/zip.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
var write = require("./write"),
geojson = require("./geojson"),
prj = require("./prj"),
JSZip = require("jszip");
var write = require("./write");
var geojson = require("./geojson");
var defaultPrj = require('./prj');
var JSZip = require("jszip");


module.exports = function (
gj,
Expand All @@ -14,6 +15,8 @@ module.exports = function (
zipTarget = zip.folder(options.folder);
}

var prj = (options && options.prj) ? options.prj : defaultPrj;

[
geojson.point(gj),
geojson.line(gj),
Expand Down

0 comments on commit 6149bde

Please sign in to comment.