├── .gitignore ├── .travis.yml ├── CODEOWNERS ├── LICENSE.txt ├── README.md ├── fixtures └── featureCollection.geojson ├── geojson-merge ├── index.js ├── package.json └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.8" 4 | - "0.10" 5 | before_install: 6 | - npm install -g npm@~1.4.6 7 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @mapbox/maps -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | 2 | ISC License 3 | 4 | Copyright (c) 2017, Mapbox 5 | 6 | Permission to use, copy, modify, and/or distribute this software for any 7 | purpose with or without fee is hereby granted, provided that the above 8 | copyright notice and this permission notice appear in all copies. 9 | 10 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # geojson-merge 2 | 3 | [![build status](https://secure.travis-ci.org/mapbox/geojson-merge.png)](http://travis-ci.org/mapbox/geojson-merge) 4 | 5 | Merge multiple [GeoJSON](http://geojson.org/) files into one FeatureCollection. 6 | 7 | ## install 8 | 9 | ```bash 10 | $ npm install --save @mapbox/geojson-merge 11 | ``` 12 | 13 | ## API 14 | 15 | 16 | 17 | ### merge 18 | 19 | Merge a series of GeoJSON objects into one FeatureCollection containing all 20 | features in all files. The objects can be any valid GeoJSON root object, 21 | including FeatureCollection, Feature, and Geometry types. 22 | 23 | **Parameters** 24 | 25 | - `inputs` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)>** a list of GeoJSON objects of any type 26 | 27 | **Examples** 28 | 29 | ```javascript 30 | var geojsonMerge = require('@mapbox/geojson-merge'); 31 | 32 | var mergedGeoJSON = geojsonMerge.merge([ 33 | { type: 'Point', coordinates: [0, 1] }, 34 | { type: 'Feature', geometry: { type: 'Point', coordinates: [0, 1] }, properties: {} } 35 | ]); 36 | 37 | console.log(JSON.stringify(mergedGeoJSON)); 38 | ``` 39 | 40 | Returns **[Object](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object)** a geojson FeatureCollection. 41 | 42 | ### mergeFeatureCollectionStream 43 | 44 | Merge GeoJSON files containing GeoJSON FeatureCollections 45 | into a single stream of a FeatureCollection as a JSON string. 46 | 47 | This is more limited than merge - it only supports FeatureCollections 48 | as input - but more performant, since it can operate on GeoJSON files 49 | larger than what you can keep in memory at one time. 50 | 51 | **Parameters** 52 | 53 | - `inputs` **[Array](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array)<[string](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String)>** a list of filenames of GeoJSON files 54 | 55 | **Examples** 56 | 57 | ```javascript 58 | var geojsonMerge = require('@mapbox/geojson-merge'); 59 | 60 | var mergedStream = geojsonMerge.mergeFeatureCollectionStream([ 61 | 'features.geojson', 62 | 'otherFeatures.geojson']) 63 | 64 | mergedStream.pipe(process.stdout); 65 | ``` 66 | 67 | Returns **[Stream](https://nodejs.org/api/stream.html)** output: a stringified JSON of a FeatureCollection. 68 | 69 | ## cli 70 | 71 | Options: 72 | 73 | > `-s` or `--stream` to use the high-performance streaming mode. This allows 74 | > you to combine very large GeoJSON files. Streaming mode requires every 75 | > GeoJSON file to contain a FeatureCollection at the top level. 76 | 77 | ```bash 78 | $ npm install -g @mapbox/geojson-merge 79 | $ geojson-merge file.geojson otherfile.geojson > combined.geojson 80 | ``` 81 | 82 | ## geojson-merge (for dummies) 83 | 84 | ### Windows Instructions: 85 | 86 | 1. Start the `node.js` application 87 | 2. Open `cmd.exe` 88 | 3. Browse to a folder where you'd like `geojson-merge` installed 89 | 4. In `cmd.exe` type the install string from above 90 | 5. Wait patiently, it could take a moment to start 91 | 6. Use `cd node_modules` to change directory to the `node_modules` folder 92 | 7. For simplicity sake, move your .geojson files into this `node_modules` directory 93 | 8. Run this command to merge your files: 94 | 95 | ```bash 96 | $ node geojson-merge file1.geojson file2.geojson > merged.geojson 97 | ``` 98 | 99 | **Merging multiple files in a folder** 100 | 101 | ```bash 102 | $ geojson-merge folder/*.geojson > combined.geojson 103 | ``` 104 | -------------------------------------------------------------------------------- /fixtures/featureCollection.geojson: -------------------------------------------------------------------------------- 1 | { 2 | "type": "FeatureCollection", 3 | "features": [ 4 | { 5 | "type": "Feature", 6 | "properties": {}, 7 | "geometry": { 8 | "type": "Polygon", 9 | "coordinates": [ 10 | [ 11 | [ 12 | 13.7109375, 13 | 47.100044694025215 14 | ], 15 | [ 16 | 13.7109375, 17 | 48.151428143221224 18 | ], 19 | [ 20 | 15.710449218749998, 21 | 48.151428143221224 22 | ], 23 | [ 24 | 15.710449218749998, 25 | 47.100044694025215 26 | ], 27 | [ 28 | 13.7109375, 29 | 47.100044694025215 30 | ] 31 | ] 32 | ] 33 | } 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /geojson-merge: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var geojsonMerge = require('./'), 3 | stream = geojsonMerge.mergeFeatureCollectionStream, 4 | merge = geojsonMerge.merge, 5 | fs = require('fs'), 6 | argv = require('minimist')(process.argv.slice(2)); 7 | 8 | if (!argv._.length || argv.help) { 9 | console.log('usage: geojson-merge [-s] FILE FILE2 FILE3'); 10 | console.log('\n --stream (or -s): use streaming mode for large files'); 11 | return; 12 | } 13 | 14 | if (argv.s || argv.stream) { 15 | stream(argv._).pipe(process.stdout) 16 | } else { 17 | process.stdout.write(JSON.stringify(merge(argv._.map(function(n) { 18 | return JSON.parse(fs.readFileSync(n)); 19 | })), null, 2)); 20 | } 21 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var normalize = require('@mapbox/geojson-normalize'); 2 | var geojsonStream = require('geojson-stream'); 3 | var fs = require('fs'); 4 | 5 | /** 6 | * Merge a series of GeoJSON objects into one FeatureCollection containing all 7 | * features in all files. The objects can be any valid GeoJSON root object, 8 | * including FeatureCollection, Feature, and Geometry types. 9 | * 10 | * @param {Array} inputs a list of GeoJSON objects of any type 11 | * @return {Object} a geojson FeatureCollection. 12 | * @example 13 | * var geojsonMerge = require('@mapbox/geojson-merge'); 14 | * 15 | * var mergedGeoJSON = geojsonMerge.merge([ 16 | * { type: 'Point', coordinates: [0, 1] }, 17 | * { type: 'Feature', geometry: { type: 'Point', coordinates: [0, 1] }, properties: {} } 18 | * ]); 19 | * 20 | * console.log(JSON.stringify(mergedGeoJSON)); 21 | */ 22 | function merge (inputs) { 23 | var output = { 24 | type: 'FeatureCollection', 25 | features: [] 26 | }; 27 | for (var i = 0; i < inputs.length; i++) { 28 | var normalized = normalize(inputs[i]); 29 | for (var j = 0; j < normalized.features.length; j++) { 30 | output.features.push(normalized.features[j]); 31 | } 32 | } 33 | return output; 34 | } 35 | 36 | /** 37 | * Merge GeoJSON files containing GeoJSON FeatureCollections 38 | * into a single stream of a FeatureCollection as a JSON string. 39 | * 40 | * This is more limited than merge - it only supports FeatureCollections 41 | * as input - but more performant, since it can operate on GeoJSON files 42 | * larger than what you can keep in memory at one time. 43 | * @param {Array} inputs a list of filenames of GeoJSON files 44 | * @returns {Stream} output: a stringified JSON of a FeatureCollection. 45 | * @example 46 | * var geojsonMerge = require('@mapbox/geojson-merge'); 47 | * 48 | * var mergedStream = geojsonMerge.mergeFeatureCollectionStream([ 49 | * 'features.geojson', 50 | * 'otherFeatures.geojson']) 51 | * 52 | * mergedStream.pipe(process.stdout); 53 | */ 54 | function mergeFeatureCollectionStream (inputs) { 55 | var out = geojsonStream.stringify(); 56 | inputs.forEach(function(file) { 57 | fs.createReadStream(file) 58 | .pipe(geojsonStream.parse()) 59 | .pipe(out); 60 | }); 61 | return out; 62 | } 63 | 64 | module.exports.merge = merge; 65 | module.exports.mergeFeatureCollectionStream = mergeFeatureCollectionStream; 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mapbox/geojson-merge", 3 | "version": "1.1.1", 4 | "description": "merge multiple geojson files", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tape test.js", 8 | "doc": "documentation readme -s API" 9 | }, 10 | "bin": { 11 | "geojson-merge": "geojson-merge" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git@github.com:mapbox/geojson-merge.git" 16 | }, 17 | "keywords": [ 18 | "geojson", 19 | "merge", 20 | "featurecollection" 21 | ], 22 | "author": "Tom MacWright", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/mapbox/geojson-merge/issues" 26 | }, 27 | "homepage": "https://github.com/mapbox/geojson-merge", 28 | "dependencies": { 29 | "@mapbox/geojson-normalize": "^0.0.1", 30 | "geojson-fixtures": "~0.1.0", 31 | "geojson-stream": "0.0.1", 32 | "minimist": "^1.2.0", 33 | "stream-concat": "0.1.0", 34 | "tape": "^4.9.0" 35 | }, 36 | "devDependencies": { 37 | "concat-stream": "^1.6.0", 38 | "cz-conventional-changelog": "1.2.0", 39 | "documentation": "^4.0.0-beta.18" 40 | }, 41 | "config": { 42 | "commitizen": { 43 | "path": "./node_modules/cz-conventional-changelog" 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /test.js: -------------------------------------------------------------------------------- 1 | var geojsonMerge = require('./'), 2 | test = require('tape'), 3 | fixtures = require('geojson-fixtures') 4 | concat = require('concat-stream'); 5 | 6 | 7 | test('merge', function(t) { 8 | t.equal(geojsonMerge.merge([fixtures.geometry.point, fixtures.feature.one]).features.length, 2); 9 | t.end(); 10 | }); 11 | 12 | test('streaming merge', function (t) { 13 | var stream = geojsonMerge.mergeFeatureCollectionStream(['fixtures/featureCollection.geojson', 'fixtures/featureCollection.geojson'], { stream: true }); 14 | t.equal(typeof stream, 'object'); 15 | t.equal(typeof stream.pipe,'function'); 16 | stream.pipe(concat(function (combined) { 17 | t.equal(JSON.parse(combined).features.length, 2); 18 | t.end(); 19 | })); 20 | }); 21 | --------------------------------------------------------------------------------