mapshaper 0.7.5 → 0.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mapshaper.js +548 -50
- package/package.json +1 -1
- package/www/index.html +7 -11
- package/www/mapshaper-gui.js +2 -1
- package/www/mapshaper.js +548 -50
- package/www/page.css +88 -3
package/mapshaper.js
CHANGED
|
@@ -4629,6 +4629,32 @@
|
|
|
4629
4629
|
return inputs && inputs[0] || '';
|
|
4630
4630
|
}
|
|
4631
4631
|
|
|
4632
|
+
// Return layers in @dataset that were *not* selected by the current target
|
|
4633
|
+
// set but still match a command-specific geometry predicate.
|
|
4634
|
+
//
|
|
4635
|
+
// Used for command side-effect messaging, e.g.:
|
|
4636
|
+
// - -proj (shared dataset reprojection)
|
|
4637
|
+
// - -simplify (shared arc simplification)
|
|
4638
|
+
//
|
|
4639
|
+
// @targetLayers should be the layer selection that triggered the command.
|
|
4640
|
+
// If all layers are targeted (or target selection is missing), returns [].
|
|
4641
|
+
// @filterFn optional predicate (lyr -> bool) for command-specific relevance.
|
|
4642
|
+
function getImplicitlyTargetedLayers(dataset, targetLayers, filterFn) {
|
|
4643
|
+
if (!targetLayers || targetLayers.length === 0 || targetLayers.length >= dataset.layers.length) {
|
|
4644
|
+
return [];
|
|
4645
|
+
}
|
|
4646
|
+
var targeted = new Set(targetLayers);
|
|
4647
|
+
return dataset.layers.filter(function(lyr) {
|
|
4648
|
+
return !targeted.has(lyr) && (!filterFn || filterFn(lyr));
|
|
4649
|
+
});
|
|
4650
|
+
}
|
|
4651
|
+
|
|
4652
|
+
function getImplicitlyTargetedLayerNames(dataset, targetLayers, filterFn) {
|
|
4653
|
+
return getImplicitlyTargetedLayers(dataset, targetLayers, filterFn).map(function(lyr) {
|
|
4654
|
+
return lyr.name || '[unnamed]';
|
|
4655
|
+
});
|
|
4656
|
+
}
|
|
4657
|
+
|
|
4632
4658
|
// Divide a collection of features with mixed types into layers of a single type
|
|
4633
4659
|
// (Used for importing TopoJSON and GeoJSON features)
|
|
4634
4660
|
function divideFeaturesByType(shapes, properties, types) {
|
|
@@ -4769,6 +4795,8 @@
|
|
|
4769
4795
|
filterPathLayerByArcIds: filterPathLayerByArcIds,
|
|
4770
4796
|
getArcPresenceTest2: getArcPresenceTest2,
|
|
4771
4797
|
getFeatureCount: getFeatureCount,
|
|
4798
|
+
getImplicitlyTargetedLayerNames: getImplicitlyTargetedLayerNames,
|
|
4799
|
+
getImplicitlyTargetedLayers: getImplicitlyTargetedLayers,
|
|
4772
4800
|
getLayerBounds: getLayerBounds,
|
|
4773
4801
|
getLayerDataTable: getLayerDataTable,
|
|
4774
4802
|
getLayerSourceFile: getLayerSourceFile,
|
|
@@ -18415,7 +18443,7 @@
|
|
|
18415
18443
|
function exportSVG(dataset, opts) {
|
|
18416
18444
|
var namespace = 'xmlns="http://www.w3.org/2000/svg"';
|
|
18417
18445
|
var defs = [];
|
|
18418
|
-
var frame, svg, layers;
|
|
18446
|
+
var frame, svg, layers, metadataJSON;
|
|
18419
18447
|
var style = '';
|
|
18420
18448
|
|
|
18421
18449
|
// kludge for map keys
|
|
@@ -18439,6 +18467,9 @@
|
|
|
18439
18467
|
frame = getFrameData(dataset, opts);
|
|
18440
18468
|
fitDatasetToFrame(dataset, frame);
|
|
18441
18469
|
setCoordinatePrecision(dataset, opts.precision || 0.01);
|
|
18470
|
+
if (opts.metadata) {
|
|
18471
|
+
metadataJSON = JSON.stringify(getGeospatialMetadata(dataset, frame));
|
|
18472
|
+
}
|
|
18442
18473
|
|
|
18443
18474
|
// error if one or more svg_data fields are not present in any layers
|
|
18444
18475
|
if (opts.svg_data) validateSvgDataFields(dataset.layers, opts.svg_data);
|
|
@@ -18458,6 +18489,10 @@
|
|
|
18458
18489
|
return stringify(obj);
|
|
18459
18490
|
}).join('\n');
|
|
18460
18491
|
|
|
18492
|
+
if (metadataJSON) {
|
|
18493
|
+
svg = getMetadataBlock(metadataJSON, [0, 0, frame.width, frame.height]) + svg;
|
|
18494
|
+
}
|
|
18495
|
+
|
|
18461
18496
|
if (defs.length > 0) {
|
|
18462
18497
|
svg = '<defs>\n' + utils.pluck(defs, 'svg').join('') + '</defs>\n' + svg;
|
|
18463
18498
|
}
|
|
@@ -18485,6 +18520,57 @@ ${svg}
|
|
|
18485
18520
|
}];
|
|
18486
18521
|
}
|
|
18487
18522
|
|
|
18523
|
+
function getMetadataBlock(metadataJSON, viewBox) {
|
|
18524
|
+
var x = 0;
|
|
18525
|
+
var y = 0;
|
|
18526
|
+
var width = viewBox && viewBox[2] || 0;
|
|
18527
|
+
var height = viewBox && viewBox[3] || 0;
|
|
18528
|
+
return '<metadata>' + metadataJSON + '</metadata>\n' +
|
|
18529
|
+
'<g id="mapshaper-metadata">\n' +
|
|
18530
|
+
'<rect x="' + x + '" y="' + y + '" width="' + width + '" height="' + height + '" opacity="0"/>\n' +
|
|
18531
|
+
'<text opacity="0" font-size="0.1">' + metadataJSON + '</text>\n' +
|
|
18532
|
+
'</g>\n';
|
|
18533
|
+
}
|
|
18534
|
+
|
|
18535
|
+
function getGeospatialMetadata(dataset, frame) {
|
|
18536
|
+
return {
|
|
18537
|
+
crs: getSVGMetadataCRS(dataset),
|
|
18538
|
+
bbox: frame.bbox || null
|
|
18539
|
+
};
|
|
18540
|
+
}
|
|
18541
|
+
|
|
18542
|
+
function getSVGMetadataCRS(dataset) {
|
|
18543
|
+
var crs = getDatasetCRS(dataset);
|
|
18544
|
+
var info = getDatasetCrsInfo(dataset);
|
|
18545
|
+
var proj4 = null;
|
|
18546
|
+
if (crs) {
|
|
18547
|
+
proj4 = crsToProj4(crs);
|
|
18548
|
+
}
|
|
18549
|
+
if (proj4) return proj4;
|
|
18550
|
+
return getAuthorityCodeString(info) || null;
|
|
18551
|
+
}
|
|
18552
|
+
|
|
18553
|
+
function getAuthorityCodeString(info) {
|
|
18554
|
+
var authority = null;
|
|
18555
|
+
if (info && info.crs_string) {
|
|
18556
|
+
authority = parseAuthorityCodeString(info.crs_string);
|
|
18557
|
+
}
|
|
18558
|
+
if (!authority && info && info.wkt1) {
|
|
18559
|
+
authority = parseAuthorityCodeFromWkt(info.wkt1);
|
|
18560
|
+
}
|
|
18561
|
+
if (!authority && info && info.geopackage_crs) {
|
|
18562
|
+
authority = parseGeoPackageAuthority(info.geopackage_crs);
|
|
18563
|
+
}
|
|
18564
|
+
return authority ? authority.authority + ':' + authority.code : null;
|
|
18565
|
+
}
|
|
18566
|
+
|
|
18567
|
+
function parseGeoPackageAuthority(o) {
|
|
18568
|
+
if (!o) return null;
|
|
18569
|
+
var authority = o.organization || o.authority || null;
|
|
18570
|
+
var code = o.organization_coordsys_id || o.code || null;
|
|
18571
|
+
return authority && code != null ? {authority: String(authority).toUpperCase(), code: String(code)} : null;
|
|
18572
|
+
}
|
|
18573
|
+
|
|
18488
18574
|
function exportFurnitureLayerForSVG(lyr, frame, opts) {
|
|
18489
18575
|
var layerObj = getEmptyLayerForSVG(lyr, opts);
|
|
18490
18576
|
layerObj.children = renderFurnitureLayer(lyr, frame);
|
|
@@ -19446,7 +19532,9 @@ ${svg}
|
|
|
19446
19532
|
|
|
19447
19533
|
function exportDbfFile(lyr, dataset, opts) {
|
|
19448
19534
|
var data = lyr.data,
|
|
19449
|
-
buf
|
|
19535
|
+
buf,
|
|
19536
|
+
files,
|
|
19537
|
+
encoding;
|
|
19450
19538
|
// create empty data table if missing a table or table is being cut out
|
|
19451
19539
|
if (!data || opts.cut_table || opts.drop_table) {
|
|
19452
19540
|
data = new DataTable(lyr.shapes ? lyr.shapes.length : 0);
|
|
@@ -19460,14 +19548,34 @@ ${svg}
|
|
|
19460
19548
|
} else {
|
|
19461
19549
|
buf = Dbf.exportRecords(data.getRecords(), opts.encoding, opts.field_order);
|
|
19462
19550
|
}
|
|
19551
|
+
encoding = getDbfExportEncoding(data, opts);
|
|
19463
19552
|
if (utils.isInteger(opts.ldid)) {
|
|
19464
19553
|
new Uint8Array(buf)[29] = opts.ldid; // set language driver id
|
|
19465
19554
|
}
|
|
19466
|
-
|
|
19467
|
-
return [{
|
|
19555
|
+
files = [{
|
|
19468
19556
|
content: buf,
|
|
19469
19557
|
filename: lyr.name + '.dbf'
|
|
19470
19558
|
}];
|
|
19559
|
+
if (opts.export_cpg && encoding) {
|
|
19560
|
+
files.push({
|
|
19561
|
+
content: formatCpgEncoding(encoding),
|
|
19562
|
+
filename: lyr.name + '.cpg'
|
|
19563
|
+
});
|
|
19564
|
+
}
|
|
19565
|
+
return files;
|
|
19566
|
+
}
|
|
19567
|
+
|
|
19568
|
+
function getDbfExportEncoding(data, opts) {
|
|
19569
|
+
if (data && data.getDbfEncoding) {
|
|
19570
|
+
return data.getDbfEncoding(opts);
|
|
19571
|
+
}
|
|
19572
|
+
return opts.encoding || 'utf8';
|
|
19573
|
+
}
|
|
19574
|
+
|
|
19575
|
+
function formatCpgEncoding(encoding) {
|
|
19576
|
+
// Canonical spelling for the default.
|
|
19577
|
+
if (/^utf-?8$/i.test(String(encoding))) return 'UTF-8';
|
|
19578
|
+
return String(encoding);
|
|
19471
19579
|
}
|
|
19472
19580
|
|
|
19473
19581
|
var decoder;
|
|
@@ -22232,8 +22340,9 @@ ${svg}
|
|
|
22232
22340
|
function exportShapefile(dataset, opts) {
|
|
22233
22341
|
return dataset.layers.reduce(function(files, lyr) {
|
|
22234
22342
|
var prj = exportPrjFile(lyr, dataset);
|
|
22343
|
+
var dbfOpts = utils.defaults({export_cpg: true}, opts);
|
|
22235
22344
|
files = files.concat(exportShpAndShxFiles(lyr, dataset));
|
|
22236
|
-
files = files.concat(exportDbfFile(lyr, dataset,
|
|
22345
|
+
files = files.concat(exportDbfFile(lyr, dataset, dbfOpts));
|
|
22237
22346
|
if (prj) files.push(prj);
|
|
22238
22347
|
return files;
|
|
22239
22348
|
}, []);
|
|
@@ -27966,6 +28075,10 @@ ${svg}
|
|
|
27966
28075
|
old_alias: 'json-subtree',
|
|
27967
28076
|
describe: '[JSON] path to JSON input data; separator is /'
|
|
27968
28077
|
})
|
|
28078
|
+
.option('ndjson', {
|
|
28079
|
+
type: 'flag',
|
|
28080
|
+
describe: '[JSON/GeoJSON] input is newline-delimited JSON objects'
|
|
28081
|
+
})
|
|
27969
28082
|
.option('single-part', {
|
|
27970
28083
|
type: 'flag',
|
|
27971
28084
|
// describe: '[GeoJSON] split multi-part features into single-part features'
|
|
@@ -28058,10 +28171,6 @@ ${svg}
|
|
|
28058
28171
|
describe: '[TopoJSON] export coordinates without quantization',
|
|
28059
28172
|
type: 'flag'
|
|
28060
28173
|
})
|
|
28061
|
-
.option('metadata', {
|
|
28062
|
-
// describe: '[TopoJSON] Add a metadata object containing CRS information',
|
|
28063
|
-
type: 'flag'
|
|
28064
|
-
})
|
|
28065
28174
|
.option('no-point-quantization', {
|
|
28066
28175
|
// describe: '[TopoJSON] export point coordinates without quantization',
|
|
28067
28176
|
type: 'flag'
|
|
@@ -28104,6 +28213,10 @@ ${svg}
|
|
|
28104
28213
|
describe: '[GeoJSON/JSON] output newline-delimited features or records',
|
|
28105
28214
|
type: 'flag'
|
|
28106
28215
|
})
|
|
28216
|
+
.option('metadata', {
|
|
28217
|
+
describe: '[SVG/TopoJSON] include metadata in output',
|
|
28218
|
+
type: 'flag'
|
|
28219
|
+
})
|
|
28107
28220
|
.option('width', {
|
|
28108
28221
|
describe: '[SVG/TopoJSON] pixel width of output (SVG default is 800)',
|
|
28109
28222
|
type: 'number'
|
|
@@ -28166,10 +28279,7 @@ ${svg}
|
|
|
28166
28279
|
.option('final', {
|
|
28167
28280
|
type: 'flag' // for testing
|
|
28168
28281
|
})
|
|
28169
|
-
|
|
28170
|
-
// describe: '[TopoJSON] add a metadata object',
|
|
28171
|
-
type: 'flag'
|
|
28172
|
-
});
|
|
28282
|
+
;
|
|
28173
28283
|
|
|
28174
28284
|
parser.section('Editing commands');
|
|
28175
28285
|
|
|
@@ -30251,6 +30361,7 @@ ${svg}
|
|
|
30251
30361
|
};
|
|
30252
30362
|
|
|
30253
30363
|
this.getFields = getFieldNames;
|
|
30364
|
+
this.getEncoding = getEncoding;
|
|
30254
30365
|
|
|
30255
30366
|
// TODO: switch to streaming output under Node.js
|
|
30256
30367
|
this.getBuffer = function() {
|
|
@@ -30570,6 +30681,19 @@ ${svg}
|
|
|
30570
30681
|
return Dbf.exportRecords(getTable().getRecords(), opts.encoding, opts.field_order);
|
|
30571
30682
|
};
|
|
30572
30683
|
|
|
30684
|
+
// Return the text encoding that exportAsDbf() will use for the current
|
|
30685
|
+
// options. If we're exporting the untouched original DBF bytes, use the
|
|
30686
|
+
// reader's detected/declared encoding; otherwise we regenerate with either
|
|
30687
|
+
// opts.encoding or the writer default (utf8).
|
|
30688
|
+
this.getDbfEncoding = function(optsArg) {
|
|
30689
|
+
var opts = optsArg || {};
|
|
30690
|
+
var useOriginal = !!reader && !altered && !opts.field_order && !opts.encoding;
|
|
30691
|
+
if (useOriginal) {
|
|
30692
|
+
return reader.getEncoding();
|
|
30693
|
+
}
|
|
30694
|
+
return opts.encoding || 'utf8';
|
|
30695
|
+
};
|
|
30696
|
+
|
|
30573
30697
|
this.getReadOnlyRecordAt = function(i) {
|
|
30574
30698
|
return reader ? reader.readRow(i) : table.getReadOnlyRecordAt(i);
|
|
30575
30699
|
};
|
|
@@ -31409,7 +31533,7 @@ ${svg}
|
|
|
31409
31533
|
(srcCollection.features || srcCollection.geometries || []).forEach(importer.parseObject);
|
|
31410
31534
|
dataset = importer.done();
|
|
31411
31535
|
importCRS(dataset, srcObj); // TODO: remove this
|
|
31412
|
-
warnIfProjectedCoords(dataset, srcObj);
|
|
31536
|
+
warnIfProjectedCoords(dataset, srcObj, opts);
|
|
31413
31537
|
return dataset;
|
|
31414
31538
|
}
|
|
31415
31539
|
|
|
@@ -31417,12 +31541,13 @@ ${svg}
|
|
|
31417
31541
|
// `crs` member). If the imported file makes no CRS claim but its coordinates
|
|
31418
31542
|
// are clearly outside lat-long range, warn the user: silent fallthrough here
|
|
31419
31543
|
// usually surfaces later as cryptic -proj errors or grossly wrong output.
|
|
31420
|
-
function warnIfProjectedCoords(dataset, jsonObj) {
|
|
31544
|
+
function warnIfProjectedCoords(dataset, jsonObj, opts) {
|
|
31545
|
+
if (!opts.warn_projected_coords) return;
|
|
31421
31546
|
if (jsonObj && jsonObj.crs) return; // user has explicitly declared a CRS
|
|
31422
31547
|
var bounds = getRoughDatasetBounds(dataset);
|
|
31423
31548
|
if (!bounds || !bounds.hasBounds()) return;
|
|
31424
31549
|
if (probablyDecimalDegreeBounds(bounds)) return;
|
|
31425
|
-
warn('Imported GeoJSON has coordinates outside the lat-long range
|
|
31550
|
+
warn('Imported GeoJSON has coordinates outside the lat-long range -- ' +
|
|
31426
31551
|
' importing as projected geometry with unknown CRS. Commands ' +
|
|
31427
31552
|
'like -proj that require a CRS will not work until you set a source ' +
|
|
31428
31553
|
'CRS, e.g. -proj init=EPSG:3857.');
|
|
@@ -32413,7 +32538,13 @@ ${svg}
|
|
|
32413
32538
|
var str = readFirstChars(reader, 1000);
|
|
32414
32539
|
var type = identifyJSONString(str, opts);
|
|
32415
32540
|
var dataset, retn;
|
|
32416
|
-
if (
|
|
32541
|
+
if (opts.ndjson) {
|
|
32542
|
+
// NDJSON can represent either newline-delimited GeoJSON features/geometries
|
|
32543
|
+
// or plain JSON records. Defer type detection until after line parsing.
|
|
32544
|
+
retn = {
|
|
32545
|
+
content: reader.toString('utf8')
|
|
32546
|
+
};
|
|
32547
|
+
} else if (type == 'geojson') { // consider only for larger files
|
|
32417
32548
|
dataset = importGeoJSONFile(reader, opts);
|
|
32418
32549
|
retn = {
|
|
32419
32550
|
dataset: dataset,
|
|
@@ -32465,6 +32596,12 @@ ${svg}
|
|
|
32465
32596
|
}
|
|
32466
32597
|
|
|
32467
32598
|
if (content) {
|
|
32599
|
+
if (opts.ndjson) {
|
|
32600
|
+
var nd = importNDJSON(content, opts);
|
|
32601
|
+
retn.dataset = nd.dataset;
|
|
32602
|
+
retn.format = nd.format;
|
|
32603
|
+
return retn;
|
|
32604
|
+
}
|
|
32468
32605
|
if (utils.isString(content)) {
|
|
32469
32606
|
try {
|
|
32470
32607
|
content = JSON.parse(content); // ~3sec for 100MB string
|
|
@@ -32485,7 +32622,7 @@ ${svg}
|
|
|
32485
32622
|
if (fmt == 'topojson') {
|
|
32486
32623
|
retn.dataset = importTopoJSON(content, opts);
|
|
32487
32624
|
} else if (fmt == 'geojson') {
|
|
32488
|
-
retn.dataset = importGeoJSON(content, opts);
|
|
32625
|
+
retn.dataset = importGeoJSON(content, getGeoJSONImportOpts(opts));
|
|
32489
32626
|
} else if (fmt == 'json') {
|
|
32490
32627
|
retn.dataset = importJSONTable(content);
|
|
32491
32628
|
} else {
|
|
@@ -32497,6 +32634,60 @@ ${svg}
|
|
|
32497
32634
|
return retn;
|
|
32498
32635
|
}
|
|
32499
32636
|
|
|
32637
|
+
function getGeoJSONImportOpts(opts) {
|
|
32638
|
+
return Object.assign({}, opts, {
|
|
32639
|
+
warn_projected_coords: true
|
|
32640
|
+
});
|
|
32641
|
+
}
|
|
32642
|
+
|
|
32643
|
+
function importNDJSON(content, opts) {
|
|
32644
|
+
var lines = utils.isString(content) ? utils.splitLines(content) : [];
|
|
32645
|
+
var objects = [];
|
|
32646
|
+
var firstGeo = null;
|
|
32647
|
+
for (var i = 0; i < lines.length; i++) {
|
|
32648
|
+
var raw = lines[i].trim();
|
|
32649
|
+
if (!raw) continue;
|
|
32650
|
+
var obj;
|
|
32651
|
+
try {
|
|
32652
|
+
obj = JSON.parse(raw);
|
|
32653
|
+
} catch (e) {
|
|
32654
|
+
stop$1('NDJSON parsing error on line ' + (i + 1) + ': ' + e.message);
|
|
32655
|
+
}
|
|
32656
|
+
objects.push(obj);
|
|
32657
|
+
if (firstGeo === null) {
|
|
32658
|
+
firstGeo = isGeoJSONObject(obj);
|
|
32659
|
+
} else if (firstGeo !== isGeoJSONObject(obj)) {
|
|
32660
|
+
stop$1('NDJSON input mixes GeoJSON and non-GeoJSON objects');
|
|
32661
|
+
}
|
|
32662
|
+
}
|
|
32663
|
+
if (objects.length === 0) {
|
|
32664
|
+
stop$1('NDJSON input does not contain any JSON objects');
|
|
32665
|
+
}
|
|
32666
|
+
if (!firstGeo) {
|
|
32667
|
+
return {dataset: importJSONTable(objects), format: 'json'};
|
|
32668
|
+
}
|
|
32669
|
+
var parser = new GeoJSONParser(getGeoJSONImportOpts(opts));
|
|
32670
|
+
objects.forEach(function(obj) {
|
|
32671
|
+
if (obj && obj.type == 'FeatureCollection') {
|
|
32672
|
+
(obj.features || []).forEach(parser.parseObject);
|
|
32673
|
+
} else if (obj && obj.type == 'GeometryCollection') {
|
|
32674
|
+
(obj.geometries || []).forEach(parser.parseObject);
|
|
32675
|
+
} else {
|
|
32676
|
+
parser.parseObject(obj);
|
|
32677
|
+
}
|
|
32678
|
+
});
|
|
32679
|
+
return {dataset: parser.done(), format: 'geojson'};
|
|
32680
|
+
}
|
|
32681
|
+
|
|
32682
|
+
function isGeoJSONObject(obj) {
|
|
32683
|
+
if (!obj || typeof obj != 'object') return false;
|
|
32684
|
+
var type = obj.type;
|
|
32685
|
+
return type == 'Feature' || type == 'FeatureCollection' ||
|
|
32686
|
+
type == 'GeometryCollection' || type == 'Point' || type == 'MultiPoint' ||
|
|
32687
|
+
type == 'LineString' || type == 'MultiLineString' ||
|
|
32688
|
+
type == 'Polygon' || type == 'MultiPolygon';
|
|
32689
|
+
}
|
|
32690
|
+
|
|
32500
32691
|
// path: path from top-level to the target object
|
|
32501
32692
|
function selectFromObject(o, path) {
|
|
32502
32693
|
var arrayRxp = /(.*)\[([0-9]+)\]$/; // array bracket notation w/ index
|
|
@@ -33087,6 +33278,7 @@ ${svg}
|
|
|
33087
33278
|
var Parser = typeof DOMParser == 'undefined' ? require$1('@xmldom/xmldom').DOMParser : DOMParser;
|
|
33088
33279
|
var doc = new Parser().parseFromString(str, 'text/xml');
|
|
33089
33280
|
var root = doc && doc.documentElement;
|
|
33281
|
+
var geometadata = parseSVGGeometadata(root, str);
|
|
33090
33282
|
var groups = getTopLevelLayerGroups(root);
|
|
33091
33283
|
var layerData = [];
|
|
33092
33284
|
var datasets = [];
|
|
@@ -33103,7 +33295,11 @@ ${svg}
|
|
|
33103
33295
|
});
|
|
33104
33296
|
});
|
|
33105
33297
|
|
|
33106
|
-
|
|
33298
|
+
if (geometadata && geometadata.bbox && geometadata.viewBox) {
|
|
33299
|
+
remapCoordinatesFromSVGToMap(layerData, geometadata.viewBox, geometadata.bbox);
|
|
33300
|
+
} else {
|
|
33301
|
+
flipYCoordinates(layerData);
|
|
33302
|
+
}
|
|
33107
33303
|
|
|
33108
33304
|
layerData.forEach(function(layer) {
|
|
33109
33305
|
datasets.push(importLayerFeatures(layer.name, layer.features, opts));
|
|
@@ -33113,9 +33309,237 @@ ${svg}
|
|
|
33113
33309
|
return {layers: [], info: {}};
|
|
33114
33310
|
}
|
|
33115
33311
|
if (datasets.length === 1) {
|
|
33116
|
-
return datasets[0];
|
|
33312
|
+
return applySVGGeometadata(datasets[0], geometadata);
|
|
33117
33313
|
}
|
|
33118
|
-
return mergeDatasets(datasets);
|
|
33314
|
+
return applySVGGeometadata(mergeDatasets(datasets), geometadata);
|
|
33315
|
+
}
|
|
33316
|
+
|
|
33317
|
+
function applySVGGeometadata(dataset, geometadata) {
|
|
33318
|
+
if (geometadata && geometadata.crs) {
|
|
33319
|
+
setDatasetCrsInfo(dataset, getCrsInfo(geometadata.crs));
|
|
33320
|
+
}
|
|
33321
|
+
return dataset;
|
|
33322
|
+
}
|
|
33323
|
+
|
|
33324
|
+
function parseSVGGeometadata(root, svgText) {
|
|
33325
|
+
var json = findMetadataJSONString(root, svgText);
|
|
33326
|
+
var obj;
|
|
33327
|
+
var metadataViewport = getMetadataViewportRect(root);
|
|
33328
|
+
if (!json) return null;
|
|
33329
|
+
obj = parseMetadataJSONObject(json);
|
|
33330
|
+
if (!obj) return null;
|
|
33331
|
+
return {
|
|
33332
|
+
crs: normalizeMetadataCRS(obj.crs),
|
|
33333
|
+
bbox: normalizeMetadataBBox(obj.bbox),
|
|
33334
|
+
viewBox: metadataViewport || parseSVGViewBox(root && root.getAttribute && root.getAttribute('viewBox'))
|
|
33335
|
+
};
|
|
33336
|
+
}
|
|
33337
|
+
|
|
33338
|
+
function findMetadataJSONString(root, svgText) {
|
|
33339
|
+
var text = getMetadataTagText(root) || getHiddenMetadataText(root);
|
|
33340
|
+
if (!text && svgText) {
|
|
33341
|
+
text = extractHiddenMetadataFromSource(svgText);
|
|
33342
|
+
}
|
|
33343
|
+
return normalizeMetadataJSONText(text);
|
|
33344
|
+
}
|
|
33345
|
+
|
|
33346
|
+
function getMetadataTagText(root) {
|
|
33347
|
+
var nodes = getElementChildren(root);
|
|
33348
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
33349
|
+
if (getTagName(nodes[i]) == 'metadata') {
|
|
33350
|
+
return nodes[i].textContent || '';
|
|
33351
|
+
}
|
|
33352
|
+
}
|
|
33353
|
+
return null;
|
|
33354
|
+
}
|
|
33355
|
+
|
|
33356
|
+
function getHiddenMetadataText(root) {
|
|
33357
|
+
var node = getMetadataGroupNode(root);
|
|
33358
|
+
if (node) {
|
|
33359
|
+
return node.textContent || '';
|
|
33360
|
+
}
|
|
33361
|
+
return null;
|
|
33362
|
+
}
|
|
33363
|
+
|
|
33364
|
+
function getMetadataGroupNode(root) {
|
|
33365
|
+
var nodes = getElementChildren(root);
|
|
33366
|
+
var i, node;
|
|
33367
|
+
for (i = 0; i < nodes.length; i++) {
|
|
33368
|
+
node = nodes[i];
|
|
33369
|
+
if (getTagName(node) == 'g' && node.getAttribute && node.getAttribute('id') == 'mapshaper-metadata') {
|
|
33370
|
+
return node;
|
|
33371
|
+
}
|
|
33372
|
+
}
|
|
33373
|
+
return null;
|
|
33374
|
+
}
|
|
33375
|
+
|
|
33376
|
+
function getMetadataViewportRect(root) {
|
|
33377
|
+
var node = getMetadataGroupNode(root);
|
|
33378
|
+
var children, i, rect;
|
|
33379
|
+
if (!node) return null;
|
|
33380
|
+
children = getElementChildren(node);
|
|
33381
|
+
for (i = 0; i < children.length; i++) {
|
|
33382
|
+
if (getTagName(children[i]) == 'rect') {
|
|
33383
|
+
rect = parseMetadataRectNode(children[i]);
|
|
33384
|
+
if (rect) return rect;
|
|
33385
|
+
}
|
|
33386
|
+
}
|
|
33387
|
+
return null;
|
|
33388
|
+
}
|
|
33389
|
+
|
|
33390
|
+
function parseMetadataRectNode(node) {
|
|
33391
|
+
var x = parseNumber(node.getAttribute('x')) || 0;
|
|
33392
|
+
var y = parseNumber(node.getAttribute('y')) || 0;
|
|
33393
|
+
var width = parseNumber(node.getAttribute('width'));
|
|
33394
|
+
var height = parseNumber(node.getAttribute('height'));
|
|
33395
|
+
var pts, i, p;
|
|
33396
|
+
var xmin = Infinity, ymin = Infinity, xmax = -Infinity, ymax = -Infinity;
|
|
33397
|
+
if (!isFiniteNumber(width) || !isFiniteNumber(height) || width === 0 || height === 0) {
|
|
33398
|
+
return null;
|
|
33399
|
+
}
|
|
33400
|
+
pts = [
|
|
33401
|
+
[x, y],
|
|
33402
|
+
[x + width, y],
|
|
33403
|
+
[x, y + height],
|
|
33404
|
+
[x + width, y + height]
|
|
33405
|
+
];
|
|
33406
|
+
for (i = 0; i < pts.length; i++) {
|
|
33407
|
+
p = applyNodeTransformChain(node, pts[i]);
|
|
33408
|
+
xmin = Math.min(xmin, p[0]);
|
|
33409
|
+
ymin = Math.min(ymin, p[1]);
|
|
33410
|
+
xmax = Math.max(xmax, p[0]);
|
|
33411
|
+
ymax = Math.max(ymax, p[1]);
|
|
33412
|
+
}
|
|
33413
|
+
if (!isFiniteNumber(xmin) || !isFiniteNumber(ymin) || !isFiniteNumber(xmax) || !isFiniteNumber(ymax)) {
|
|
33414
|
+
return null;
|
|
33415
|
+
}
|
|
33416
|
+
return [xmin, ymin, xmax - xmin, ymax - ymin];
|
|
33417
|
+
}
|
|
33418
|
+
|
|
33419
|
+
function applyNodeTransformChain(node, point) {
|
|
33420
|
+
var chain = [];
|
|
33421
|
+
var p = [point[0], point[1]];
|
|
33422
|
+
var i;
|
|
33423
|
+
while (node && node.nodeType == 1) {
|
|
33424
|
+
chain.unshift(node);
|
|
33425
|
+
node = node.parentNode;
|
|
33426
|
+
}
|
|
33427
|
+
for (i = 0; i < chain.length; i++) {
|
|
33428
|
+
p = applyTransformString(chain[i].getAttribute && chain[i].getAttribute('transform'), p);
|
|
33429
|
+
}
|
|
33430
|
+
return p;
|
|
33431
|
+
}
|
|
33432
|
+
|
|
33433
|
+
function applyTransformString(str, point) {
|
|
33434
|
+
var re = /([a-z]+)\s*\(([^)]*)\)/ig;
|
|
33435
|
+
var m = null;
|
|
33436
|
+
var p = [point[0], point[1]];
|
|
33437
|
+
while ((m = re.exec(String(str || '')))) {
|
|
33438
|
+
p = applyTransformCommand(m[1].toLowerCase(), parseTransformNumbers(m[2]), p);
|
|
33439
|
+
}
|
|
33440
|
+
return p;
|
|
33441
|
+
}
|
|
33442
|
+
|
|
33443
|
+
function parseTransformNumbers(str) {
|
|
33444
|
+
return String(str || '')
|
|
33445
|
+
.trim()
|
|
33446
|
+
.split(/[\s,]+/)
|
|
33447
|
+
.filter(Boolean)
|
|
33448
|
+
.map(Number)
|
|
33449
|
+
.filter(function(v) { return isFiniteNumber(v); });
|
|
33450
|
+
}
|
|
33451
|
+
|
|
33452
|
+
function applyTransformCommand(cmd, nums, point) {
|
|
33453
|
+
var x = point[0], y = point[1];
|
|
33454
|
+
var sx, sy;
|
|
33455
|
+
if (cmd == 'translate') {
|
|
33456
|
+
return [x + (nums[0] || 0), y + (nums.length > 1 ? nums[1] : 0)];
|
|
33457
|
+
}
|
|
33458
|
+
if (cmd == 'scale') {
|
|
33459
|
+
sx = nums.length > 0 ? nums[0] : 1;
|
|
33460
|
+
sy = nums.length > 1 ? nums[1] : sx;
|
|
33461
|
+
return [x * sx, y * sy];
|
|
33462
|
+
}
|
|
33463
|
+
if (cmd == 'matrix' && nums.length >= 6) {
|
|
33464
|
+
return [
|
|
33465
|
+
nums[0] * x + nums[2] * y + nums[4],
|
|
33466
|
+
nums[1] * x + nums[3] * y + nums[5]
|
|
33467
|
+
];
|
|
33468
|
+
}
|
|
33469
|
+
return point;
|
|
33470
|
+
}
|
|
33471
|
+
|
|
33472
|
+
function extractHiddenMetadataFromSource(str) {
|
|
33473
|
+
var m = String(str || '').match(/<g[^>]*\bid\s*=\s*["']mapshaper-metadata["'][^>]*>([\s\S]*?)<\/g>/i);
|
|
33474
|
+
if (!m) return null;
|
|
33475
|
+
return stripMarkupTags(m[1]);
|
|
33476
|
+
}
|
|
33477
|
+
|
|
33478
|
+
function stripMarkupTags(str) {
|
|
33479
|
+
return String(str || '').replace(/<[^>]*>/g, '');
|
|
33480
|
+
}
|
|
33481
|
+
|
|
33482
|
+
function normalizeMetadataJSONText(str) {
|
|
33483
|
+
if (!str) return null;
|
|
33484
|
+
return decodeHTMLEntities(stripMarkupTags(String(str))).trim();
|
|
33485
|
+
}
|
|
33486
|
+
|
|
33487
|
+
function decodeHTMLEntities(str) {
|
|
33488
|
+
return String(str || '')
|
|
33489
|
+
.replace(/"|"/gi, '"')
|
|
33490
|
+
.replace(/'|'/gi, "'")
|
|
33491
|
+
.replace(/&|&/gi, '&')
|
|
33492
|
+
.replace(/<|</gi, '<')
|
|
33493
|
+
.replace(/>|>/gi, '>')
|
|
33494
|
+
.replace(/"/g, '"')
|
|
33495
|
+
.replace(/'/g, "'")
|
|
33496
|
+
.replace(/&/g, '&')
|
|
33497
|
+
.replace(/</g, '<')
|
|
33498
|
+
.replace(/>/g, '>');
|
|
33499
|
+
}
|
|
33500
|
+
|
|
33501
|
+
function parseMetadataJSONObject(text) {
|
|
33502
|
+
try {
|
|
33503
|
+
return JSON.parse(text);
|
|
33504
|
+
} catch (e) {
|
|
33505
|
+
return null;
|
|
33506
|
+
}
|
|
33507
|
+
}
|
|
33508
|
+
|
|
33509
|
+
function normalizeMetadataCRS(crs) {
|
|
33510
|
+
return typeof crs == 'string' && crs.trim() ? crs.trim() : null;
|
|
33511
|
+
}
|
|
33512
|
+
|
|
33513
|
+
function normalizeMetadataBBox(bbox) {
|
|
33514
|
+
if (!Array.isArray(bbox) || bbox.length != 4) return null;
|
|
33515
|
+
var out = bbox.map(function(v) { return Number(v); });
|
|
33516
|
+
return out.every(isFiniteNumber) ? out : null;
|
|
33517
|
+
}
|
|
33518
|
+
|
|
33519
|
+
function parseSVGViewBox(str) {
|
|
33520
|
+
var parts = String(str || '').trim().split(/[\s,]+/).map(Number);
|
|
33521
|
+
if (parts.length != 4 || !parts.every(isFiniteNumber) || parts[2] === 0 || parts[3] === 0) {
|
|
33522
|
+
return null;
|
|
33523
|
+
}
|
|
33524
|
+
return parts;
|
|
33525
|
+
}
|
|
33526
|
+
|
|
33527
|
+
function remapCoordinatesFromSVGToMap(layerData, viewBox, bbox) {
|
|
33528
|
+
var vx = viewBox[0], vy = viewBox[1], vw = viewBox[2], vh = viewBox[3];
|
|
33529
|
+
var minX = bbox[0], minY = bbox[1], maxX = bbox[2], maxY = bbox[3];
|
|
33530
|
+
var scaleX = (maxX - minX) / vw;
|
|
33531
|
+
var scaleY = (maxY - minY) / vh;
|
|
33532
|
+
|
|
33533
|
+
layerData.forEach(function(layer) {
|
|
33534
|
+
layer.features.forEach(function(feature) {
|
|
33535
|
+
forEachGeometryCoordinate(feature && feature.geometry, function(coord) {
|
|
33536
|
+
var sx = coord[0];
|
|
33537
|
+
var sy = coord[1];
|
|
33538
|
+
coord[0] = minX + (sx - vx) * scaleX;
|
|
33539
|
+
coord[1] = maxY - (sy - vy) * scaleY;
|
|
33540
|
+
});
|
|
33541
|
+
});
|
|
33542
|
+
});
|
|
33119
33543
|
}
|
|
33120
33544
|
|
|
33121
33545
|
function importLayerFeatures(layerName, features, opts) {
|
|
@@ -33143,6 +33567,7 @@ ${svg}
|
|
|
33143
33567
|
childNodes.forEach(function(node) {
|
|
33144
33568
|
var tag = getTagName(node);
|
|
33145
33569
|
if (tag == 'defs') return;
|
|
33570
|
+
if (tag == 'g' && node.getAttribute && node.getAttribute('id') == 'mapshaper-metadata') return;
|
|
33146
33571
|
if (tag == 'g') {
|
|
33147
33572
|
groups.push({
|
|
33148
33573
|
node: node,
|
|
@@ -41193,7 +41618,7 @@ ${svg}
|
|
|
41193
41618
|
// @type: 'clip' or 'erase'
|
|
41194
41619
|
function clipLayers(targetLayers, clipSrc, targetDataset, type, opts) {
|
|
41195
41620
|
profileStart('clipLayers');
|
|
41196
|
-
opts = opts || {
|
|
41621
|
+
opts = opts || {no_cleanup: true}; // TODO: update testing functions
|
|
41197
41622
|
var usingPathClip = utils.some(targetLayers, layerHasPaths);
|
|
41198
41623
|
var mergedDataset, clipLyr, nodes, result;
|
|
41199
41624
|
var clipDataset = normalizeOverlaySource(clipSrc, targetDataset, opts);
|
|
@@ -43429,20 +43854,24 @@ ${svg}
|
|
|
43429
43854
|
}
|
|
43430
43855
|
}
|
|
43431
43856
|
|
|
43432
|
-
|
|
43433
|
-
|
|
43434
|
-
|
|
43435
|
-
|
|
43436
|
-
|
|
43437
|
-
|
|
43438
|
-
|
|
43439
|
-
|
|
43440
|
-
|
|
43441
|
-
|
|
43442
|
-
|
|
43443
|
-
|
|
43444
|
-
|
|
43445
|
-
|
|
43857
|
+
// Opt-in summary logging. Some commands (e.g. -divide) reuse this join
|
|
43858
|
+
// helper internally and don't want user-facing join diagnostics.
|
|
43859
|
+
if (opts.show_join_message) {
|
|
43860
|
+
printJoinMessage({
|
|
43861
|
+
matches: matchCount,
|
|
43862
|
+
n: n,
|
|
43863
|
+
joins: countJoins(joinCounts),
|
|
43864
|
+
m: srcRecords.length,
|
|
43865
|
+
skipped: skipCount,
|
|
43866
|
+
collisions: collisionCount,
|
|
43867
|
+
collisionFields: collisionFields,
|
|
43868
|
+
destKey: destKey,
|
|
43869
|
+
srcKey: srcKey,
|
|
43870
|
+
unmatchedTargetKeys: takeSampleKeys(unmatchedTargetKeys),
|
|
43871
|
+
unusedSourceKeys: takeSampleKeys(unusedSourceKeys),
|
|
43872
|
+
opts: opts
|
|
43873
|
+
});
|
|
43874
|
+
}
|
|
43446
43875
|
|
|
43447
43876
|
if (opts.unjoined) {
|
|
43448
43877
|
retn.unjoined = {
|
|
@@ -46804,7 +47233,7 @@ ${svg}
|
|
|
46804
47233
|
// Works for lcc, aea, tmerc, etc.
|
|
46805
47234
|
// TODO: add more projections
|
|
46806
47235
|
//
|
|
46807
|
-
function expandProjDefn(str, dataset) {
|
|
47236
|
+
function expandProjDefn(str, dataset, targetLayers) {
|
|
46808
47237
|
var mproj = require$1('mproj');
|
|
46809
47238
|
var proj4, params, bbox, isConic2SP, isCentered, decimals;
|
|
46810
47239
|
if (str in mproj.internal.pj_list === false) {
|
|
@@ -46815,7 +47244,7 @@ ${svg}
|
|
|
46815
47244
|
isCentered = ['tmerc', 'etmerc'].includes(str);
|
|
46816
47245
|
proj4 = '+proj=' + str;
|
|
46817
47246
|
if (isConic2SP || isCentered) {
|
|
46818
|
-
bbox = getBBox(dataset); // TODO: support projected datasets
|
|
47247
|
+
bbox = getBBox(dataset, targetLayers); // TODO: support projected datasets
|
|
46819
47248
|
decimals = getBoundsPrecisionForDisplay(bbox);
|
|
46820
47249
|
params = isCentered ? getCenterParams(bbox, decimals) : getConicParams(bbox, decimals);
|
|
46821
47250
|
proj4 += ' ' + params;
|
|
@@ -46824,11 +47253,16 @@ ${svg}
|
|
|
46824
47253
|
return proj4;
|
|
46825
47254
|
}
|
|
46826
47255
|
|
|
46827
|
-
function getBBox(dataset) {
|
|
47256
|
+
function getBBox(dataset, targetLayers) {
|
|
47257
|
+
var source = targetLayers && targetLayers.length > 0 ? {
|
|
47258
|
+
arcs: dataset.arcs,
|
|
47259
|
+
layers: targetLayers,
|
|
47260
|
+
info: dataset.info
|
|
47261
|
+
} : dataset;
|
|
46828
47262
|
if (!isLatLngCRS(getDatasetCRS(dataset))) {
|
|
46829
47263
|
stop$1('Expected unprojected data');
|
|
46830
47264
|
}
|
|
46831
|
-
return getDatasetBounds(
|
|
47265
|
+
return getDatasetBounds(source).toArray();
|
|
46832
47266
|
}
|
|
46833
47267
|
|
|
46834
47268
|
// See: Savric & Jenny, "Automating the selection of standard parallels for conic map projections"
|
|
@@ -46854,8 +47288,9 @@ ${svg}
|
|
|
46854
47288
|
getConicParams: getConicParams
|
|
46855
47289
|
});
|
|
46856
47290
|
|
|
46857
|
-
cmd.proj = function(dataset, catalog, opts) {
|
|
47291
|
+
cmd.proj = function(dataset, catalog, opts, targetLayers) {
|
|
46858
47292
|
var srcInfo, destInfo, destStr;
|
|
47293
|
+
var implicitlyProjectedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasGeometry);
|
|
46859
47294
|
if (opts.init) {
|
|
46860
47295
|
srcInfo = fetchCrsInfo(opts.init, catalog);
|
|
46861
47296
|
if (!srcInfo.crs) stop$1("Unknown projection source:", opts.init);
|
|
@@ -46864,11 +47299,17 @@ ${svg}
|
|
|
46864
47299
|
if (opts.match) {
|
|
46865
47300
|
destInfo = fetchCrsInfo(opts.match, catalog);
|
|
46866
47301
|
} else if (opts.crs) {
|
|
46867
|
-
destStr = expandProjDefn(opts.crs, dataset);
|
|
47302
|
+
destStr = expandProjDefn(opts.crs, dataset, targetLayers);
|
|
46868
47303
|
destInfo = getCrsInfo(destStr);
|
|
46869
47304
|
}
|
|
46870
47305
|
if (destInfo) {
|
|
46871
|
-
projCmd(dataset, destInfo, opts);
|
|
47306
|
+
var didProject = projCmd(dataset, destInfo, opts);
|
|
47307
|
+
if (didProject && implicitlyProjectedNames.length > 0) {
|
|
47308
|
+
message(
|
|
47309
|
+
'Also projected non-target layer' + utils.pluralSuffix(implicitlyProjectedNames.length) +
|
|
47310
|
+
' from the same dataset: ' + implicitlyProjectedNames.join(', ')
|
|
47311
|
+
);
|
|
47312
|
+
}
|
|
46872
47313
|
}
|
|
46873
47314
|
};
|
|
46874
47315
|
|
|
@@ -46886,7 +47327,7 @@ ${svg}
|
|
|
46886
47327
|
if (!datasetHasGeometry(dataset)) {
|
|
46887
47328
|
// still set the crs of datasets that are missing geometry
|
|
46888
47329
|
setDatasetCrsInfo(dataset, destInfo);
|
|
46889
|
-
return;
|
|
47330
|
+
return false;
|
|
46890
47331
|
}
|
|
46891
47332
|
|
|
46892
47333
|
var srcInfo = getDatasetCrsInfo(dataset);
|
|
@@ -46896,7 +47337,7 @@ ${svg}
|
|
|
46896
47337
|
|
|
46897
47338
|
if (crsAreEqual(srcInfo.crs, destInfo.crs)) {
|
|
46898
47339
|
message("Source and destination CRS are the same");
|
|
46899
|
-
return;
|
|
47340
|
+
return false;
|
|
46900
47341
|
}
|
|
46901
47342
|
|
|
46902
47343
|
if (dataset.arcs) {
|
|
@@ -46922,9 +47363,9 @@ ${svg}
|
|
|
46922
47363
|
// replace original layers with modified layers
|
|
46923
47364
|
utils.extend(lyr, target.layers[i]);
|
|
46924
47365
|
});
|
|
47366
|
+
return true;
|
|
46925
47367
|
}
|
|
46926
47368
|
|
|
46927
|
-
|
|
46928
47369
|
// name: a layer identifier, .prj file or projection defn
|
|
46929
47370
|
// Converts layer ids and .prj files to CRS defn
|
|
46930
47371
|
// Returns projection defn
|
|
@@ -48059,17 +48500,62 @@ ${svg}
|
|
|
48059
48500
|
});
|
|
48060
48501
|
}
|
|
48061
48502
|
|
|
48503
|
+
function parseWKTPoint(val) {
|
|
48504
|
+
if (!utils.isString(val)) return null;
|
|
48505
|
+
// Support 2D POINT WKT, case-insensitive, with optional Z/M tokens.
|
|
48506
|
+
// Examples:
|
|
48507
|
+
// POINT (1 2)
|
|
48508
|
+
// point(1 2)
|
|
48509
|
+
// POINT Z (1 2 3)
|
|
48510
|
+
// POINT M (1 2 3)
|
|
48511
|
+
// POINT ZM (1 2 3 4)
|
|
48512
|
+
var m = /^\s*POINT(?:\s+Z(?:M)?|\s+M)?\s*\(\s*([^\s,]+)\s+([^\s,]+)(?:\s+[^)]*)?\)\s*$/i.exec(val);
|
|
48513
|
+
if (!m) return null;
|
|
48514
|
+
var x = coordinateFromValue(m[1]);
|
|
48515
|
+
var y = coordinateFromValue(m[2]);
|
|
48516
|
+
if (isNaN(x) || isNaN(y)) return null;
|
|
48517
|
+
return [x, y];
|
|
48518
|
+
}
|
|
48519
|
+
|
|
48520
|
+
function findWKTField(records, fields) {
|
|
48521
|
+
var sampleSize = Math.min(records.length, 50);
|
|
48522
|
+
return utils.find(fields, function(name) {
|
|
48523
|
+
var seen = 0;
|
|
48524
|
+
var matches = 0;
|
|
48525
|
+
for (var i = 0; i < sampleSize; i++) {
|
|
48526
|
+
var rec = records[i];
|
|
48527
|
+
if (!rec) continue;
|
|
48528
|
+
var val = rec[name];
|
|
48529
|
+
if (!utils.isString(val) || val.trim() === '') continue;
|
|
48530
|
+
seen++;
|
|
48531
|
+
if (parseWKTPoint(val)) matches++;
|
|
48532
|
+
}
|
|
48533
|
+
// Require at least one non-empty sample and majority parseable as POINT.
|
|
48534
|
+
return seen > 0 && matches / seen >= 0.6;
|
|
48535
|
+
});
|
|
48536
|
+
}
|
|
48537
|
+
|
|
48062
48538
|
function pointsFromDataTableAuto(data) {
|
|
48063
48539
|
var fields = data ? data.getFields() : [];
|
|
48540
|
+
var records = data ? data.getRecords() : [];
|
|
48064
48541
|
var opts = {
|
|
48065
48542
|
x: findXField(fields),
|
|
48066
48543
|
y: findYField(fields)
|
|
48067
48544
|
};
|
|
48545
|
+
if (!opts.x || !opts.y) {
|
|
48546
|
+
opts.wkt = findWKTField(records, fields);
|
|
48547
|
+
}
|
|
48068
48548
|
return pointsFromDataTable(data, opts);
|
|
48069
48549
|
}
|
|
48070
48550
|
|
|
48071
48551
|
function pointsFromDataTable(data, opts) {
|
|
48072
48552
|
if (!data) stop$1("Layer is missing a data table");
|
|
48553
|
+
if (opts.wkt && data.fieldExists(opts.wkt)) {
|
|
48554
|
+
return data.getRecords().map(function(rec) {
|
|
48555
|
+
var p = parseWKTPoint(rec[opts.wkt]);
|
|
48556
|
+
return p ? [p] : null;
|
|
48557
|
+
});
|
|
48558
|
+
}
|
|
48073
48559
|
if (!opts.x || !opts.y || !data.fieldExists(opts.x) || !data.fieldExists(opts.y)) {
|
|
48074
48560
|
stop$1("Missing x,y data fields");
|
|
48075
48561
|
}
|
|
@@ -48087,8 +48573,10 @@ ${svg}
|
|
|
48087
48573
|
var Points = /*#__PURE__*/Object.freeze({
|
|
48088
48574
|
__proto__: null,
|
|
48089
48575
|
coordinateFromValue: coordinateFromValue,
|
|
48576
|
+
findWKTField: findWKTField,
|
|
48090
48577
|
findXField: findXField,
|
|
48091
48578
|
findYField: findYField,
|
|
48579
|
+
parseWKTPoint: parseWKTPoint,
|
|
48092
48580
|
pointsFromPolygons: pointsFromPolygons
|
|
48093
48581
|
});
|
|
48094
48582
|
|
|
@@ -48477,6 +48965,9 @@ ${svg}
|
|
|
48477
48965
|
}
|
|
48478
48966
|
|
|
48479
48967
|
cmd.join = function(targetLyr, targetDataset, src, opts) {
|
|
48968
|
+
// Opt in to the post-join summary emitted by joinTableToLayer().
|
|
48969
|
+
// Other commands can reuse the helper without showing this message.
|
|
48970
|
+
opts = Object.assign({}, opts, {show_join_message: true});
|
|
48480
48971
|
var srcType, targetType, retn;
|
|
48481
48972
|
if (!src || !src.dataset) {
|
|
48482
48973
|
stop$1("Missing a joinable data source");
|
|
@@ -51094,8 +51585,9 @@ ${svg}
|
|
|
51094
51585
|
replaceInArray: replaceInArray
|
|
51095
51586
|
});
|
|
51096
51587
|
|
|
51097
|
-
cmd.simplify = function(dataset, opts) {
|
|
51588
|
+
cmd.simplify = function(dataset, opts, targetLayers) {
|
|
51098
51589
|
var arcs = dataset.arcs;
|
|
51590
|
+
var implicitlySimplifiedNames = getImplicitlyTargetedLayerNames(dataset, targetLayers, layerHasPaths);
|
|
51099
51591
|
if (!arcs || arcs.size() === 0) return; // removed in v0.4.125: stop("Missing path data");
|
|
51100
51592
|
opts = getStandardSimplifyOpts(dataset, opts); // standardize options
|
|
51101
51593
|
simplifyPaths(arcs, opts);
|
|
@@ -51114,6 +51606,12 @@ ${svg}
|
|
|
51114
51606
|
}
|
|
51115
51607
|
|
|
51116
51608
|
finalizeSimplification(dataset, opts);
|
|
51609
|
+
if (implicitlySimplifiedNames.length > 0) {
|
|
51610
|
+
message(
|
|
51611
|
+
'Also simplified non-target layer' + utils.pluralSuffix(implicitlySimplifiedNames.length) +
|
|
51612
|
+
' from the same dataset: ' + implicitlySimplifiedNames.join(', ')
|
|
51613
|
+
);
|
|
51614
|
+
}
|
|
51117
51615
|
};
|
|
51118
51616
|
|
|
51119
51617
|
function finalizeSimplification(dataset, opts) {
|
|
@@ -52807,7 +53305,7 @@ ${svg}
|
|
|
52807
53305
|
await initProjLibrary(opts);
|
|
52808
53306
|
job.resumeCommand();
|
|
52809
53307
|
targets.forEach(function(targ) {
|
|
52810
|
-
cmd.proj(targ.dataset, job.catalog, opts);
|
|
53308
|
+
cmd.proj(targ.dataset, job.catalog, opts, targ.layers);
|
|
52811
53309
|
});
|
|
52812
53310
|
|
|
52813
53311
|
} else if (name == 'rectangle') {
|
|
@@ -52850,7 +53348,7 @@ ${svg}
|
|
|
52850
53348
|
if (opts.variable) {
|
|
52851
53349
|
cmd.variableSimplify(targetLayers, targetDataset, opts);
|
|
52852
53350
|
} else {
|
|
52853
|
-
cmd.simplify(targetDataset, opts);
|
|
53351
|
+
cmd.simplify(targetDataset, opts, targetLayers);
|
|
52854
53352
|
}
|
|
52855
53353
|
|
|
52856
53354
|
} else if (name == 'slice') {
|
|
@@ -52976,7 +53474,7 @@ ${svg}
|
|
|
52976
53474
|
});
|
|
52977
53475
|
}
|
|
52978
53476
|
|
|
52979
|
-
var version = "0.7.
|
|
53477
|
+
var version = "0.7.7";
|
|
52980
53478
|
|
|
52981
53479
|
// Parse command line args into commands and run them
|
|
52982
53480
|
// Function takes an optional Node-style callback. A Promise is returned if no callback is given.
|