mapshaper 0.7.45 → 0.7.46
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 +777 -367
- package/package.json +1 -1
- package/www/mapshaper-gui.js +147 -104
- package/www/mapshaper.js +777 -367
- package/www/page.css +33 -3
package/package.json
CHANGED
package/www/mapshaper-gui.js
CHANGED
|
@@ -2638,36 +2638,6 @@
|
|
|
2638
2638
|
});
|
|
2639
2639
|
}
|
|
2640
2640
|
|
|
2641
|
-
// Call @iter on each member of an array (similar to Array#reduce(iter))
|
|
2642
|
-
// iter: function(memo, item, callback)
|
|
2643
|
-
// Call @done when all members have been processed or if an error occurs
|
|
2644
|
-
// done: function(err, memo)
|
|
2645
|
-
// @memo: Initial value
|
|
2646
|
-
//
|
|
2647
|
-
function reduceAsync(arr, memo, iter, done) {
|
|
2648
|
-
var call = typeof setImmediate == 'undefined' ? setTimeout : setImmediate;
|
|
2649
|
-
var i=0;
|
|
2650
|
-
next(null, memo);
|
|
2651
|
-
|
|
2652
|
-
function next(err, memo) {
|
|
2653
|
-
// Detach next operation from call stack to prevent overflow
|
|
2654
|
-
// Don't use setTimeout(, 0) if setImmediate is available
|
|
2655
|
-
// (setTimeout() can introduce a long delay if previous operation was slow,
|
|
2656
|
-
// as of Node 0.10.32 -- a bug?)
|
|
2657
|
-
if (err) {
|
|
2658
|
-
return done(err, null);
|
|
2659
|
-
}
|
|
2660
|
-
call(function() {
|
|
2661
|
-
if (i < arr.length === false) {
|
|
2662
|
-
done(null, memo);
|
|
2663
|
-
} else {
|
|
2664
|
-
iter(memo, arr[i++], next);
|
|
2665
|
-
}
|
|
2666
|
-
}, 0);
|
|
2667
|
-
}
|
|
2668
|
-
}
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
2641
|
// Append elements of @src array to @dest array
|
|
2672
2642
|
function merge(dest, src) {
|
|
2673
2643
|
if (!isArray(dest) || !isArray(src)) {
|
|
@@ -3522,7 +3492,7 @@
|
|
|
3522
3492
|
parseIntlNumber, parseNumber, parseString, pickOne, pluck,
|
|
3523
3493
|
pluralSuffix, promisify,
|
|
3524
3494
|
quicksort, quicksortPartition,
|
|
3525
|
-
range,
|
|
3495
|
+
range, regexEscape, reorderArray: reorderArray$1, repeat, repeatString,
|
|
3526
3496
|
replaceArray, rpad, rtrim,
|
|
3527
3497
|
shuffle, some, sortArrayIndex, sortOn, splitLines, sum,
|
|
3528
3498
|
toArray, toBuffer, trim, trimQuotes,
|
|
@@ -7465,6 +7435,11 @@
|
|
|
7465
7435
|
}
|
|
7466
7436
|
|
|
7467
7437
|
async function importFiles(fileData, importOpts) {
|
|
7438
|
+
var commandFiles = extractCommandFiles(fileData);
|
|
7439
|
+
commandFiles.forEach(registerCommandFile);
|
|
7440
|
+
fileData = fileData.filter(function(file) {
|
|
7441
|
+
return commandFiles.indexOf(file) == -1;
|
|
7442
|
+
});
|
|
7468
7443
|
var groups = groupFilesForImport(fileData, importOpts);
|
|
7469
7444
|
var optStr = GUI.formatCommandOptions(importOpts);
|
|
7470
7445
|
fileData = null;
|
|
@@ -7493,6 +7468,31 @@
|
|
|
7493
7468
|
}
|
|
7494
7469
|
}
|
|
7495
7470
|
|
|
7471
|
+
function extractCommandFiles(files) {
|
|
7472
|
+
return files.filter(function(file) {
|
|
7473
|
+
if (!internal.isPotentialCommandFile(file.name)) return false;
|
|
7474
|
+
file.commandFileContent = decodeCommandFileContent(file.content);
|
|
7475
|
+
return internal.stringLooksLikeCommandFile(file.commandFileContent);
|
|
7476
|
+
});
|
|
7477
|
+
}
|
|
7478
|
+
|
|
7479
|
+
function decodeCommandFileContent(content) {
|
|
7480
|
+
if (utils$1.isString(content)) return content;
|
|
7481
|
+
return internal.decodeString(new Uint8Array(content), 'utf8');
|
|
7482
|
+
}
|
|
7483
|
+
|
|
7484
|
+
function registerCommandFile(file) {
|
|
7485
|
+
var replaced = gui.commandFiles.add(file.name, file.commandFileContent);
|
|
7486
|
+
var command = '-run ' + internal.formatOptionValue(file.name);
|
|
7487
|
+
if (!gui.notify) return;
|
|
7488
|
+
gui.notify({
|
|
7489
|
+
severity: 'info',
|
|
7490
|
+
title: replaced ? 'Command file replaced' : 'Command file loaded',
|
|
7491
|
+
body: 'Run ' + command + ' in the console.',
|
|
7492
|
+
dedupKey: 'command-file:' + file.name
|
|
7493
|
+
});
|
|
7494
|
+
}
|
|
7495
|
+
|
|
7496
7496
|
// Surface a passive warning if a .shp file came in without its .dbf or .prj
|
|
7497
7497
|
// sibling. Both files are technically optional, but their absence has very
|
|
7498
7498
|
// different consequences (no attribute data, no projection metadata) and
|
|
@@ -7517,7 +7517,6 @@
|
|
|
7517
7517
|
}
|
|
7518
7518
|
|
|
7519
7519
|
async function importDataset(group, importOpts) {
|
|
7520
|
-
var dataset;
|
|
7521
7520
|
var datasets;
|
|
7522
7521
|
var imported = false;
|
|
7523
7522
|
if (group.gpkg) {
|
|
@@ -7529,12 +7528,7 @@
|
|
|
7529
7528
|
if (group.geotiff) {
|
|
7530
7529
|
await loadGeoTIFFLib();
|
|
7531
7530
|
}
|
|
7532
|
-
|
|
7533
|
-
dataset = await internal.importContentAsync(group, importOpts);
|
|
7534
|
-
} else {
|
|
7535
|
-
dataset = internal.importContent(group, importOpts);
|
|
7536
|
-
}
|
|
7537
|
-
datasets = Array.isArray(dataset) ? dataset : [dataset];
|
|
7531
|
+
datasets = await internal.importDatasetsFromContent(group, importOpts);
|
|
7538
7532
|
for (var d of datasets) {
|
|
7539
7533
|
if (datasetIsEmpty(d)) continue;
|
|
7540
7534
|
if (group.layername) {
|
|
@@ -7788,37 +7782,31 @@
|
|
|
7788
7782
|
return items.filter(Boolean);
|
|
7789
7783
|
}
|
|
7790
7784
|
|
|
7791
|
-
function downloadFiles(paths) {
|
|
7785
|
+
async function downloadFiles(paths) {
|
|
7792
7786
|
var items = prepFilesForDownload(paths);
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
throw Error();
|
|
7810
|
-
}
|
|
7811
|
-
return resp.blob();
|
|
7812
|
-
}).then(blob => {
|
|
7813
|
-
if (blob) {
|
|
7814
|
-
blob.name = item.basename;
|
|
7815
|
-
memo.push(blob);
|
|
7787
|
+
var files = [];
|
|
7788
|
+
for (var item of items) {
|
|
7789
|
+
try {
|
|
7790
|
+
var resp = await fetch(item.url);
|
|
7791
|
+
if (resp.status != 200) {
|
|
7792
|
+
// e.g. 404 because a URL listed in the GUI query string does not exist
|
|
7793
|
+
throw Error();
|
|
7794
|
+
}
|
|
7795
|
+
var blob = await resp.blob();
|
|
7796
|
+
if (blob) {
|
|
7797
|
+
blob.name = item.basename;
|
|
7798
|
+
files.push(blob);
|
|
7799
|
+
}
|
|
7800
|
+
} catch (e) {
|
|
7801
|
+
gui.alert("Error loading " + item.name + ". Possible causes include: wrong URL, no network connection, server not configured for cross-domain sharing (CORS).");
|
|
7802
|
+
return;
|
|
7816
7803
|
}
|
|
7817
|
-
}
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7804
|
+
}
|
|
7805
|
+
if (!files.length) {
|
|
7806
|
+
gui.clearMode();
|
|
7807
|
+
} else {
|
|
7808
|
+
receiveFiles(files);
|
|
7809
|
+
}
|
|
7822
7810
|
}
|
|
7823
7811
|
|
|
7824
7812
|
function wait(ms) {
|
|
@@ -8182,12 +8170,12 @@
|
|
|
8182
8170
|
|
|
8183
8171
|
internal.replaceImportFile(function(src, opts) {
|
|
8184
8172
|
var dataset = find(src);
|
|
8185
|
-
//
|
|
8186
|
-
//
|
|
8187
|
-
//
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
|
|
8173
|
+
// Browser-side file references resolve to loaded data. Return a full copy
|
|
8174
|
+
// so a command that imports and edits the match cannot mutate the original
|
|
8175
|
+
// dataset through shared layers, tables, arcs or metadata.
|
|
8176
|
+
var copy = internal.copyDataset(dataset);
|
|
8177
|
+
copy.info = internal.copyDatasetInfo(dataset.info || {});
|
|
8178
|
+
return copy;
|
|
8191
8179
|
});
|
|
8192
8180
|
}
|
|
8193
8181
|
|
|
@@ -9599,10 +9587,11 @@
|
|
|
9599
9587
|
|
|
9600
9588
|
// get active layer field names and other layer names
|
|
9601
9589
|
function getCompletionWords() {
|
|
9602
|
-
var
|
|
9603
|
-
var
|
|
9604
|
-
var
|
|
9605
|
-
|
|
9590
|
+
var active = model.getActiveLayer();
|
|
9591
|
+
var lyr = active && active.layer;
|
|
9592
|
+
var fieldNames = lyr && lyr.data ? lyr.data.getFields() : [];
|
|
9593
|
+
var lyrNames = lyr ? findOtherLayerNames(lyr) : [];
|
|
9594
|
+
return fieldNames.concat(lyrNames, gui.commandFiles.getNames());
|
|
9606
9595
|
}
|
|
9607
9596
|
|
|
9608
9597
|
function findOtherLayerNames(lyr) {
|
|
@@ -9746,6 +9735,7 @@
|
|
|
9746
9735
|
// don't add info commands to console history
|
|
9747
9736
|
// (for one thing, they interfere with target resetting)
|
|
9748
9737
|
commands = internal.runAndRemoveInfoCommands(commands);
|
|
9738
|
+
prepareRunCommands(commands);
|
|
9749
9739
|
} catch (e) {
|
|
9750
9740
|
return done(e, {});
|
|
9751
9741
|
}
|
|
@@ -9758,6 +9748,24 @@
|
|
|
9758
9748
|
});
|
|
9759
9749
|
}
|
|
9760
9750
|
|
|
9751
|
+
function prepareRunCommands(commands) {
|
|
9752
|
+
var cache = gui.commandFiles.getInputCache();
|
|
9753
|
+
commands.forEach(function(cmd) {
|
|
9754
|
+
if (cmd.name != 'run') return;
|
|
9755
|
+
cmd.options.input = cache;
|
|
9756
|
+
cmd.options.validate_commands = validateBrowserRunCommands;
|
|
9757
|
+
});
|
|
9758
|
+
}
|
|
9759
|
+
|
|
9760
|
+
function validateBrowserRunCommands(commands) {
|
|
9761
|
+
commands.forEach(function(cmd) {
|
|
9762
|
+
if (['include', 'require', 'external'].includes(cmd.name)) {
|
|
9763
|
+
internal.stop('The ' + cmd.name +
|
|
9764
|
+
' command cannot be run from a command file in the web console.');
|
|
9765
|
+
}
|
|
9766
|
+
});
|
|
9767
|
+
}
|
|
9768
|
+
|
|
9761
9769
|
function applyParsedCommands(commands, commandString, done) {
|
|
9762
9770
|
var active = model.getActiveLayer(),
|
|
9763
9771
|
prevArcs = active?.dataset.arcs,
|
|
@@ -9807,6 +9815,14 @@
|
|
|
9807
9815
|
if (sameTable) {
|
|
9808
9816
|
flags.same_table = true;
|
|
9809
9817
|
}
|
|
9818
|
+
// A -run command can contain any number of nested commands. The outer
|
|
9819
|
+
// command name does not describe which display caches or controls the
|
|
9820
|
+
// nested commands changed, so refresh conservatively.
|
|
9821
|
+
if (flags.run) {
|
|
9822
|
+
flags.arc_count = true;
|
|
9823
|
+
flags.select = true;
|
|
9824
|
+
flags.same_table = false;
|
|
9825
|
+
}
|
|
9810
9826
|
if (active && active?.layer == active2?.layer) {
|
|
9811
9827
|
// this can get set after some commands that don't set a new target
|
|
9812
9828
|
// (e.g. -dissolve)
|
|
@@ -22674,6 +22690,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
22674
22690
|
var content = El('div').addClass('ruler-popup-content').appendTo(popup);
|
|
22675
22691
|
var closeBtn = El('button').addClass('label-style-close ruler-close-btn').appendTo(popup).text('×');
|
|
22676
22692
|
var wgs84 = internal.parseCrsString('wgs84');
|
|
22693
|
+
var geographicDistance = internal.getGeodesicDistanceFunction(wgs84);
|
|
22677
22694
|
var _on = false;
|
|
22678
22695
|
var startPoint = null;
|
|
22679
22696
|
var pointerPoint = null;
|
|
@@ -22870,9 +22887,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
22870
22887
|
|
|
22871
22888
|
measurement = getMeasurement(path);
|
|
22872
22889
|
drawRulerLines(path, measurement);
|
|
22873
|
-
drawRulerPointMarkers(measurement.
|
|
22890
|
+
drawRulerPointMarkers(measurement.geographicMeters !== null);
|
|
22874
22891
|
if (placed) {
|
|
22875
|
-
drawMarker(endMarker, endPoint, measurement.
|
|
22892
|
+
drawMarker(endMarker, endPoint, measurement.geographicMeters !== null);
|
|
22876
22893
|
} else {
|
|
22877
22894
|
hideMarker(endMarker);
|
|
22878
22895
|
}
|
|
@@ -22888,20 +22905,33 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
22888
22905
|
}
|
|
22889
22906
|
|
|
22890
22907
|
function drawRulerLines(path, measurement) {
|
|
22891
|
-
if (measurement.
|
|
22908
|
+
if (measurement.geographicMeters !== null) {
|
|
22892
22909
|
drawPath(geodesicPath, getGeodesicPathPixels(path));
|
|
22893
22910
|
clearSvgPath(directPath);
|
|
22894
|
-
} else {
|
|
22911
|
+
} else if (measurement.projectedMeters !== null) {
|
|
22895
22912
|
drawPath(directPath, path.map(function(point) { return point.display; }));
|
|
22896
|
-
|
|
22913
|
+
clearSvgPath(geodesicPath);
|
|
22914
|
+
} else {
|
|
22915
|
+
clearSvgPath(directPath);
|
|
22916
|
+
clearSvgPath(geodesicPath);
|
|
22897
22917
|
}
|
|
22898
22918
|
}
|
|
22899
22919
|
|
|
22900
22920
|
function showPopup(measurement) {
|
|
22901
22921
|
content.empty();
|
|
22902
|
-
measurement.
|
|
22903
|
-
El('div').
|
|
22904
|
-
|
|
22922
|
+
if (measurement.geographicMeters !== null) {
|
|
22923
|
+
El('div').addClass('ruler-geographic-distance').appendTo(content)
|
|
22924
|
+
.text('Geographic distance: ' + measurement.distanceLabel);
|
|
22925
|
+
El('div').addClass('ruler-distance-method').appendTo(content)
|
|
22926
|
+
.text('Shortest surface path (WGS84 ellipsoid)');
|
|
22927
|
+
} else if (measurement.projectedMeters !== null) {
|
|
22928
|
+
El('div').addClass('ruler-projected-distance').appendTo(content)
|
|
22929
|
+
.text('Projected distance: ' + measurement.distanceLabel);
|
|
22930
|
+
El('div').addClass('ruler-distance-method').appendTo(content)
|
|
22931
|
+
.text('Geographic distance not available');
|
|
22932
|
+
} else {
|
|
22933
|
+
El('div').appendTo(content).text('Distance unavailable');
|
|
22934
|
+
}
|
|
22905
22935
|
if (placed) {
|
|
22906
22936
|
closeBtn.show();
|
|
22907
22937
|
} else {
|
|
@@ -23077,23 +23107,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
23077
23107
|
function getMeasurement(path) {
|
|
23078
23108
|
var isLatLng = internal.isLatLngCRS(path[0].sourceCRS);
|
|
23079
23109
|
var projectedMeters = isLatLng ? null : getProjectedPathDistanceMeters(path);
|
|
23080
|
-
var
|
|
23081
|
-
var
|
|
23082
|
-
var
|
|
23083
|
-
|
|
23084
|
-
if (projectedMeters !== null) {
|
|
23085
|
-
labels.push('Projected: ' + getDistanceDisplay(projectedMeters, unit).label);
|
|
23086
|
-
if (greatCircleMeters !== null) {
|
|
23087
|
-
labels.push('Great circle: ' + getDistanceDisplay(greatCircleMeters, unit).label);
|
|
23088
|
-
}
|
|
23089
|
-
} else if (greatCircleMeters !== null) {
|
|
23090
|
-
labels.push('Great circle: ' + getDistanceDisplay(greatCircleMeters, unit).label);
|
|
23091
|
-
}
|
|
23110
|
+
var geographicMeters = getGeographicPathDistanceMeters(path);
|
|
23111
|
+
var displayedMeters = geographicMeters !== null ? geographicMeters : projectedMeters;
|
|
23112
|
+
var unit = getDistanceUnit(displayedMeters || 0);
|
|
23092
23113
|
return {
|
|
23093
|
-
isLatLng,
|
|
23094
23114
|
projectedMeters,
|
|
23095
|
-
|
|
23096
|
-
|
|
23115
|
+
geographicMeters,
|
|
23116
|
+
distanceLabel: displayedMeters === null ? null : getDistanceDisplay(displayedMeters, unit).label
|
|
23097
23117
|
};
|
|
23098
23118
|
}
|
|
23099
23119
|
|
|
@@ -23107,13 +23127,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
23107
23127
|
return geom.distance2D(a.data[0], a.data[1], b.data[0], b.data[1]) * toMeter;
|
|
23108
23128
|
}
|
|
23109
23129
|
|
|
23110
|
-
function
|
|
23111
|
-
return sumPathDistance(path,
|
|
23130
|
+
function getGeographicPathDistanceMeters(path) {
|
|
23131
|
+
return sumPathDistance(path, getGeographicDistanceMeters);
|
|
23112
23132
|
}
|
|
23113
23133
|
|
|
23114
|
-
function
|
|
23134
|
+
function getGeographicDistanceMeters(a, b) {
|
|
23115
23135
|
if (!a.lngLat || !b.lngLat) return null;
|
|
23116
|
-
return
|
|
23136
|
+
return geographicDistance(a.lngLat[0], a.lngLat[1], b.lngLat[0], b.lngLat[1]);
|
|
23117
23137
|
}
|
|
23118
23138
|
|
|
23119
23139
|
function sumPathDistance(path, calcSegmentDistance) {
|
|
@@ -24684,6 +24704,28 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
24684
24704
|
};
|
|
24685
24705
|
}
|
|
24686
24706
|
|
|
24707
|
+
function CommandFileStore() {
|
|
24708
|
+
var files = Object.create(null);
|
|
24709
|
+
|
|
24710
|
+
this.add = function(name, content) {
|
|
24711
|
+
var replaced = Object.prototype.hasOwnProperty.call(files, name);
|
|
24712
|
+
files[name] = content;
|
|
24713
|
+
return replaced;
|
|
24714
|
+
};
|
|
24715
|
+
|
|
24716
|
+
this.getNames = function() {
|
|
24717
|
+
return Object.keys(files);
|
|
24718
|
+
};
|
|
24719
|
+
|
|
24720
|
+
this.getInputCache = function() {
|
|
24721
|
+
var cache = Object.create(null);
|
|
24722
|
+
Object.keys(files).forEach(function(name) {
|
|
24723
|
+
cache[name] = files[name];
|
|
24724
|
+
});
|
|
24725
|
+
return cache;
|
|
24726
|
+
};
|
|
24727
|
+
}
|
|
24728
|
+
|
|
24687
24729
|
// import { ProjectOptions } from './gui-project-control';
|
|
24688
24730
|
|
|
24689
24731
|
|
|
@@ -24702,6 +24744,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
24702
24744
|
gui.options = opts;
|
|
24703
24745
|
gui.container = El(container);
|
|
24704
24746
|
gui.model = new Model(gui);
|
|
24747
|
+
gui.commandFiles = new CommandFileStore();
|
|
24705
24748
|
gui.keyboard = new KeyboardEvents(gui);
|
|
24706
24749
|
gui.buttons = new SidebarButtons(gui);
|
|
24707
24750
|
gui.display = new DisplayOptions(gui);
|