diff --git a/src/mapnik_feature.cpp b/src/mapnik_feature.cpp index 5f635dda45..0c0d8e3d8d 100644 --- a/src/mapnik_feature.cpp +++ b/src/mapnik_feature.cpp @@ -76,16 +76,38 @@ Napi::Value Feature::fromJSON(Napi::CallbackInfo const& info) { Napi::Env env = info.Env(); Napi::EscapableHandleScope scope(env); + Napi::Object options = Napi::Object::New(env); if (info.Length() < 1 || !info[0].IsString()) { Napi::TypeError::New(env, "requires one argument: a string representing a GeoJSON feature").ThrowAsJavaScriptException(); return env.Undefined(); } + bool use_id_from_source = false; + if (info.Length() > 1) + { + // options object + if (!info[1].IsObject()) + { + Napi::Error::New(env, "optional second argument must be an options object").ThrowAsJavaScriptException(); + return env.Undefined(); + } + options = info[1].As(); + if (options.Has("use_id_from_source")) + { + Napi::Value param_val = options.Get("use_id_from_source"); + if (!param_val.IsBoolean()) + { + Napi::TypeError::New(env, "option 'use_id_from_source' must be a boolean").ThrowAsJavaScriptException(); + return env.Undefined(); + } + use_id_from_source = param_val.As(); + } + } std::string json = info[0].As(); try { - mapnik::feature_ptr feature(mapnik::feature_factory::create(std::make_shared(), 1)); + mapnik::feature_ptr feature(mapnik::feature_factory::create(std::make_shared(), 1, use_id_from_source)); if (!mapnik::json::from_geojson(json, *feature)) { Napi::Error::New(env, "Failed to read GeoJSON").ThrowAsJavaScriptException(); diff --git a/src/mapnik_vector_tile_json.cpp b/src/mapnik_vector_tile_json.cpp index 9cbc2a14f5..93443c5456 100644 --- a/src/mapnik_vector_tile_json.cpp +++ b/src/mapnik_vector_tile_json.cpp @@ -1003,6 +1003,7 @@ Napi::Value VectorTile::addGeoJSON(Napi::CallbackInfo const& info) bool multi_polygon_union = false; mapnik::vector_tile_impl::polygon_fill_type fill_type = mapnik::vector_tile_impl::positive_fill; bool process_all_rings = false; + bool use_id_from_source = false; if (info.Length() > 2) { @@ -1089,6 +1090,16 @@ Napi::Value VectorTile::addGeoJSON(Napi::CallbackInfo const& info) } process_all_rings = param_val.As(); } + if (options.Has("use_id_from_source")) + { + Napi::Value param_val = options.Get("use_id_from_source"); + if (!param_val.IsBoolean()) + { + Napi::TypeError::New(env, "option 'use_id_from_source' must be a boolean").ThrowAsJavaScriptException(); + return env.Undefined(); + } + use_id_from_source = param_val.As(); + } } try @@ -1099,6 +1110,7 @@ Napi::Value VectorTile::addGeoJSON(Napi::CallbackInfo const& info) mapnik::parameters p; p["type"] = "geojson"; p["inline"] = geojson_string; + p["use_id_from_source"] = use_id_from_source; mapnik::layer lyr(geojson_name, "+init=epsg:4326"); lyr.set_datasource(mapnik::datasource_cache::instance().create(p)); map.add_layer(lyr); diff --git a/test/datasource.test.js b/test/datasource.test.js index 50f4c948f1..c845e2e646 100644 --- a/test/datasource.test.js +++ b/test/datasource.test.js @@ -202,6 +202,25 @@ test('test empty geojson datasource', (assert) => { assert.end(); }); +test('test geojson datasource with id are read using "use_id_from_source" param', (assert) => { + var input = { + "id": 12345, + "type": "Feature", + "properties": { + "something": [] + }, + "geometry": { + "type": "Point", + "coordinates": [ 1, 1 ] + } + }; + var ds = new mapnik.Datasource({ type:'geojson', inline: JSON.stringify(input), use_id_from_source: true }); + var fs = ds.featureset() + var feat = fs.next(); + assert.equal(feat.id(), 12345); + assert.end(); +}); + test('test empty geojson datasource due to invalid json string', (assert) => { var input = "{ \"type\": \"FeatureCollection\", \"features\": [{ \"oofda\" } ] }"; // from string will fail to parse diff --git a/test/feature.test.js b/test/feature.test.js index 656d809d0e..14427894eb 100644 --- a/test/feature.test.js +++ b/test/feature.test.js @@ -85,6 +85,21 @@ test('should match known features', (assert) => { assert.end(); }); +test('should accept option to use_id_from_source', (assert) => { + var expected = { + id: 12345, + type: "Feature", + properties: {}, + geometry: { + type: 'Polygon', + coordinates: [[[1,1],[2,1],[2,2],[1,2],[1,1]]] + } + }; + var feature = new mapnik.Feature.fromJSON(JSON.stringify(expected), { use_id_from_source: true }); + assert.equal(expected.id, feature.id()); + assert.end(); +}); + test('should output the same geojson that it read', (assert) => { var expected = { type: "Feature", diff --git a/test/vector-tile.test.js b/test/vector-tile.test.js index ffebe9b761..db91bd271a 100644 --- a/test/vector-tile.test.js +++ b/test/vector-tile.test.js @@ -185,6 +185,35 @@ test('should fail when adding bad parameters to add geoJSON', (assert) => { assert.end(); }); +test('should accept "use_id_from_source" param when adding geojson', (assert) => { + var vtile = new mapnik.VectorTile(0,0,0); + var geojson = { + "type": "FeatureCollection", + "features": [ + { + "id": 12345, + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [ + -122, + 48 + ] + }, + "properties": { + "name": "geojson data" + } + } + ] + }; + vtile.addGeoJSON(JSON.stringify(geojson),"layer-name", { use_id_from_source: true }); + var out = JSON.parse(vtile.toGeoJSON(0)); + assert.equal(out.type,'FeatureCollection'); + assert.equal(out.features.length,1); + assert.equal(out.features[0].id, 12345); + assert.end(); +}); + test('should be able to create a vector tile from geojson', (assert) => { var vtile = new mapnik.VectorTile(0,0,0); var geojson = {