diff --git a/.gitignore b/.gitignore index 3db12b15..2f6661c0 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ shpwrite.js +node_modules diff --git a/src/fields.js b/src/fields.js index 7a7843ab..d30570a6 100644 --- a/src/fields.js +++ b/src/fields.js @@ -5,7 +5,7 @@ module.exports.obj = obj; function geojson(features) { var fields = {}; - features.forEach(collect); + forEach(features, collect); function collect(f) { inherit(fields, f.properties); } return obj(fields); } diff --git a/src/points.js b/src/points.js index af27df9f..d7f4147e 100644 --- a/src/points.js +++ b/src/points.js @@ -1,4 +1,5 @@ var ext = require('./extent'); +const { reduce, forEach } = require('./util') module.exports.write = function writePoints(coordinates, extent, shpView, shxView) { @@ -7,7 +8,7 @@ module.exports.write = function writePoints(coordinates, extent, shpView, shxVie shpI = 0, shxI = 0; - coordinates.forEach(function writePoint(coords, i) { + forEach(coordinates, function writePoint(coords, i) { // HEADER // 4 record number // 4 content length in 16-bit words (20/2) @@ -31,7 +32,7 @@ module.exports.write = function writePoints(coordinates, extent, shpView, shxVie }; module.exports.extent = function(coordinates) { - return coordinates.reduce(function(extent, coords) { + return reduce(coordinates, function(extent, coords) { return ext.enlarge(extent, coords); }, ext.blank()); }; diff --git a/src/poly.js b/src/poly.js index 4ba8c2de..7c227666 100644 --- a/src/poly.js +++ b/src/poly.js @@ -1,3 +1,4 @@ +const { forEach, reduce }= require('./util'); var ext = require('./extent'), types = require('./types'); @@ -7,7 +8,7 @@ module.exports.write = function writePoints(geometries, extent, shpView, shxView shxI = 0, shxOffset = 100; - geometries.forEach(writePolyLine); + forEach(geometries, writePolyLine); function writePolyLine(coordinates, i) { @@ -15,7 +16,7 @@ module.exports.write = function writePoints(geometries, extent, shpView, shxView noParts = parts([coordinates], TYPE), contentLength = (flattened.length * 16) + 48 + (noParts - 1) * 4; - var featureExtent = flattened.reduce(function(extent, c) { + var featureExtent = reduce(flattened, function(extent, c) { return ext.enlarge(extent, c); }, ext.blank()); @@ -37,7 +38,7 @@ module.exports.write = function writePoints(geometries, extent, shpView, shxView shpView.setInt32(shpI + 48, flattened.length, true); // POINTS shpView.setInt32(shpI + 52, 0, true); // The first part - index zero - var onlyParts = coordinates.reduce(function (arr, coords) { + var onlyParts = reduce(coordinates, function (arr, coords) { if (Array.isArray(coords[0][0])) { arr = arr.concat(coords); } else { @@ -48,14 +49,14 @@ module.exports.write = function writePoints(geometries, extent, shpView, shxView for (var p = 1; p < noParts; p++) { shpView.setInt32( // set part index shpI + 52 + (p * 4), - onlyParts.reduce(function (a, b, idx) { + reduce(onlyParts, function (a, b, idx) { return idx < p ? a + b.length : a; }, 0), true ); } - flattened.forEach(function writeLine(coords, i) { + forEach(flattened, function writeLine(coords, i) { shpView.setFloat64(shpI + 56 + (i * 16) + (noParts - 1) * 4, coords[0], true); // X shpView.setFloat64(shpI + 56 + (i * 16) + (noParts - 1) * 4 + 8, coords[1], true); // Y }); @@ -75,7 +76,7 @@ module.exports.shxLength = function(geometries) { }; module.exports.extent = function(coordinates) { - return justCoords(coordinates).reduce(function(extent, c) { + return reduce(justCoords(coordinates), function(extent, c) { return ext.enlarge(extent, c); }, ext.blank()); }; @@ -83,10 +84,10 @@ module.exports.extent = function(coordinates) { function parts(geometries, TYPE) { var no = 1; if (TYPE === types.geometries.POLYGON || TYPE === types.geometries.POLYLINE) { - no = geometries.reduce(function (no, coords) { + no = reduce(geometries, function (no, coords) { no += coords.length; if (Array.isArray(coords[0][0][0])) { // multi - no += coords.reduce(function (no, rings) { + no += reduce(coords, function (no, rings) { return no + rings.length - 1; // minus outer }, 0); } @@ -100,18 +101,25 @@ module.exports.parts = parts; function totalPoints(geometries) { var sum = 0; - geometries.forEach(function(g) { sum += g.length; }); + forEach(geometries, function(g) { sum += g.length; }); return sum; } function justCoords(coords, l) { if (l === undefined) l = []; if (typeof coords[0][0] == 'object') { - return coords.reduce(function(memo, c) { - return memo.concat(justCoords(c)); - }, l); + return reduce(coords, accumulateCoords, l); } else { return coords; } } +function accumulateCoords(memo, c) { + const memoPosition = memo.length; + const coords = justCoords(c); + forEach(coords, (coord, i) => { + memo[memoPosition + i] = coord; + }) + return memo; +} + diff --git a/src/util.js b/src/util.js new file mode 100644 index 00000000..f95ad145 --- /dev/null +++ b/src/util.js @@ -0,0 +1,26 @@ +module.exports.forEach = function forEach(collection, iteratee) { + if(typeof iteratee !== 'function') { + throw Error('iteratee must be a function') + } + if(!Array.isArray(collection)) { + throw Error('collection must be an array') + } + for(let i = 0, len = collection.length; i < len; i++) { + iteratee(collection[i], i) + } +} + +module.exports.reduce = function reduce(collection, iteratee, initialAccumulator) { + if(typeof iteratee !== 'function') { + throw Error('iteratee must be a function') + } + if(!Array.isArray(collection)) { + throw Error('collection must be an array') + } + let internalAccumulator = initialAccumulator; + for(let i = 0, len = collection.length; i < len; i++) { + internalAccumulator = iteratee(internalAccumulator, collection[i], i) + } + + return internalAccumulator; +} diff --git a/src/zip.js b/src/zip.js index b8e89d85..045f8734 100644 --- a/src/zip.js +++ b/src/zip.js @@ -2,14 +2,14 @@ var write = require('./write'), geojson = require('./geojson'), prj = require('./prj'), JSZip = require('jszip'); +const { forEach } = require('./util'); module.exports = function(gj, options) { var zip = new JSZip(), layers = zip.folder(options && options.folder ? options.folder : 'layers'); - [geojson.point(gj), geojson.line(gj), geojson.polygon(gj)] - .forEach(function(l) { + forEach([geojson.point(gj), geojson.line(gj), geojson.polygon(gj)], function(l) { if (l.geometries.length && l.geometries[0].length) { write( // field definitions