mapshaper 0.6.45 → 0.6.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 +89 -18
- package/package.json +1 -1
- package/www/index.html +6 -6
- package/www/mapshaper-gui.js +141 -36
- package/www/mapshaper.js +89 -18
- package/www/page.css +16 -8
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.46";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -1813,6 +1813,23 @@
|
|
|
1813
1813
|
return [xmin, ymin, xmax, ymax];
|
|
1814
1814
|
}
|
|
1815
1815
|
|
|
1816
|
+
|
|
1817
|
+
function findArcIdFromVertexId(i, ii) {
|
|
1818
|
+
// binary search
|
|
1819
|
+
// possible optimization: use interpolation to find a better partition value.
|
|
1820
|
+
var lower = 0, upper = ii.length - 1;
|
|
1821
|
+
var middle;
|
|
1822
|
+
while (lower < upper) {
|
|
1823
|
+
middle = Math.ceil((lower + upper) / 2);
|
|
1824
|
+
if (i < ii[middle]) {
|
|
1825
|
+
upper = middle - 1;
|
|
1826
|
+
} else {
|
|
1827
|
+
lower = middle;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
return lower; // assumes dataset is not empty
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1816
1833
|
function deleteVertex(arcs, i) {
|
|
1817
1834
|
var data = arcs.getVertexData();
|
|
1818
1835
|
var nn = data.nn;
|
|
@@ -1939,6 +1956,7 @@
|
|
|
1939
1956
|
__proto__: null,
|
|
1940
1957
|
absArcId: absArcId,
|
|
1941
1958
|
calcArcBounds: calcArcBounds,
|
|
1959
|
+
findArcIdFromVertexId: findArcIdFromVertexId,
|
|
1942
1960
|
deleteVertex: deleteVertex,
|
|
1943
1961
|
insertVertex: insertVertex,
|
|
1944
1962
|
countFilteredVertices: countFilteredVertices,
|
|
@@ -3405,7 +3423,7 @@
|
|
|
3405
3423
|
var item;
|
|
3406
3424
|
for (var i=0; i<arr.length; i++) {
|
|
3407
3425
|
item = arr[i];
|
|
3408
|
-
if (item
|
|
3426
|
+
if (Array.isArray(item)) {
|
|
3409
3427
|
forEachArcId(item, cb);
|
|
3410
3428
|
} else if (utils.isInteger(item)) {
|
|
3411
3429
|
var val = cb(item);
|
|
@@ -6953,6 +6971,15 @@
|
|
|
6953
6971
|
utils.defaults(destInfo, srcInfo);
|
|
6954
6972
|
}
|
|
6955
6973
|
|
|
6974
|
+
function copyDatasetInfo(info) {
|
|
6975
|
+
// not a deep copy... objects like info.crs are read-only, so copy-by-reference
|
|
6976
|
+
// should be ok
|
|
6977
|
+
var info2 = Object.assign({}, info);
|
|
6978
|
+
if (Array.isArray(info.input_files)) {
|
|
6979
|
+
info2.input_files = info.input_files.concat();
|
|
6980
|
+
}
|
|
6981
|
+
return info2;
|
|
6982
|
+
}
|
|
6956
6983
|
|
|
6957
6984
|
function splitApartLayers(dataset, layers) {
|
|
6958
6985
|
var datasets = [];
|
|
@@ -7119,6 +7146,7 @@
|
|
|
7119
7146
|
__proto__: null,
|
|
7120
7147
|
splitDataset: splitDataset,
|
|
7121
7148
|
mergeDatasetInfo: mergeDatasetInfo,
|
|
7149
|
+
copyDatasetInfo: copyDatasetInfo,
|
|
7122
7150
|
splitApartLayers: splitApartLayers,
|
|
7123
7151
|
copyDataset: copyDataset,
|
|
7124
7152
|
copyDatasetForExport: copyDatasetForExport,
|
|
@@ -15481,6 +15509,17 @@
|
|
|
15481
15509
|
|
|
15482
15510
|
// Keep track of whether positive or negative integer ids are 'used' or not.
|
|
15483
15511
|
|
|
15512
|
+
|
|
15513
|
+
function SimpleIdTestIndex(n) {
|
|
15514
|
+
var index = new Uint8Array(n);
|
|
15515
|
+
this.setId = function(id) {
|
|
15516
|
+
index[id] = 1;
|
|
15517
|
+
};
|
|
15518
|
+
this.hasId = function(id) {
|
|
15519
|
+
return index[id] === 1;
|
|
15520
|
+
};
|
|
15521
|
+
}
|
|
15522
|
+
|
|
15484
15523
|
function IdTestIndex(n) {
|
|
15485
15524
|
var index = new Uint8Array(n);
|
|
15486
15525
|
var setList = [];
|
|
@@ -15743,15 +15782,30 @@
|
|
|
15743
15782
|
getHoleDivider: getHoleDivider
|
|
15744
15783
|
});
|
|
15745
15784
|
|
|
15746
|
-
// Convert an array of intersections into an ArcCollection (for display)
|
|
15747
|
-
//
|
|
15748
|
-
|
|
15749
15785
|
function getIntersectionPoints(intersections) {
|
|
15750
15786
|
return intersections.map(function(obj) {
|
|
15751
15787
|
return [obj.x, obj.y];
|
|
15752
15788
|
});
|
|
15753
15789
|
}
|
|
15754
15790
|
|
|
15791
|
+
function getIntersectionLayer(intersections, lyr, arcs) {
|
|
15792
|
+
// return {geometry_type: 'point', shapes: [getIntersectionPoints(XX)]};
|
|
15793
|
+
var ii = arcs.getVertexData().ii;
|
|
15794
|
+
var index = new SimpleIdTestIndex(arcs.size());
|
|
15795
|
+
forEachArcId(lyr.shapes, arcId => {
|
|
15796
|
+
index.setId(absArcId(arcId));
|
|
15797
|
+
});
|
|
15798
|
+
var points = [];
|
|
15799
|
+
intersections.forEach(obj => {
|
|
15800
|
+
var arc1 = findArcIdFromVertexId(obj.a[0], ii);
|
|
15801
|
+
var arc2 = findArcIdFromVertexId(obj.b[0], ii);
|
|
15802
|
+
if (index.hasId(arc1) && index.hasId(arc2)) {
|
|
15803
|
+
points.push([obj.x, obj.y]);
|
|
15804
|
+
}
|
|
15805
|
+
});
|
|
15806
|
+
return {geometry_type: 'point', shapes: [points]};
|
|
15807
|
+
}
|
|
15808
|
+
|
|
15755
15809
|
// Identify intersecting segments in an ArcCollection
|
|
15756
15810
|
//
|
|
15757
15811
|
// To find all intersections:
|
|
@@ -15999,6 +16053,7 @@
|
|
|
15999
16053
|
var SegmentIntersection = /*#__PURE__*/Object.freeze({
|
|
16000
16054
|
__proto__: null,
|
|
16001
16055
|
getIntersectionPoints: getIntersectionPoints,
|
|
16056
|
+
getIntersectionLayer: getIntersectionLayer,
|
|
16002
16057
|
findSegmentIntersections: findSegmentIntersections,
|
|
16003
16058
|
sortIntersections: sortIntersections,
|
|
16004
16059
|
dedupIntersections: dedupIntersections,
|
|
@@ -33396,7 +33451,7 @@ ${svg}
|
|
|
33396
33451
|
if (n != values.length) {
|
|
33397
33452
|
stop('Mismatch in number of categories and number of values');
|
|
33398
33453
|
}
|
|
33399
|
-
return values;
|
|
33454
|
+
return parseValues(values); // convert numerical strings to numbers
|
|
33400
33455
|
}
|
|
33401
33456
|
|
|
33402
33457
|
function getIndexes(n) {
|
|
@@ -33564,7 +33619,7 @@ ${svg}
|
|
|
33564
33619
|
if (opts.index_field) {
|
|
33565
33620
|
dataField = opts.index_field;
|
|
33566
33621
|
fieldType = getColumnType(opts.field, records);
|
|
33567
|
-
|
|
33622
|
+
} else if (opts.field) {
|
|
33568
33623
|
dataField = opts.field;
|
|
33569
33624
|
fieldType = getColumnType(opts.field, records);
|
|
33570
33625
|
}
|
|
@@ -33596,6 +33651,9 @@ ${svg}
|
|
|
33596
33651
|
if ((!opts.categories || opts.categories.includes('*')) && dataField) {
|
|
33597
33652
|
opts.categories = getUniqFieldValues(records, dataField);
|
|
33598
33653
|
}
|
|
33654
|
+
if (opts.categories && fieldType == 'number') {
|
|
33655
|
+
opts.categories = opts.categories.map(str => +str);
|
|
33656
|
+
}
|
|
33599
33657
|
}
|
|
33600
33658
|
|
|
33601
33659
|
if (opts.classes) {
|
|
@@ -34740,34 +34798,48 @@ ${svg}
|
|
|
34740
34798
|
}
|
|
34741
34799
|
|
|
34742
34800
|
function getFeatureEditor(lyr, dataset) {
|
|
34743
|
-
var changed = false;
|
|
34744
34801
|
var api = {};
|
|
34745
34802
|
// need to copy attribute to avoid circular references if geojson is assigned
|
|
34746
34803
|
// to a data property.
|
|
34747
34804
|
var copy = copyLayer(lyr);
|
|
34748
34805
|
var features = exportLayerAsGeoJSON(copy, dataset, {}, true);
|
|
34806
|
+
var features2 = [];
|
|
34749
34807
|
|
|
34750
34808
|
api.get = function(i) {
|
|
34809
|
+
if (i > 0) features[i-1] = null; // garbage-collect old features
|
|
34751
34810
|
return features[i];
|
|
34752
34811
|
};
|
|
34753
34812
|
|
|
34754
34813
|
api.set = function(feat, i) {
|
|
34755
|
-
|
|
34814
|
+
var arr;
|
|
34815
|
+
|
|
34756
34816
|
if (utils.isString(feat)) {
|
|
34757
34817
|
feat = JSON.parse(feat);
|
|
34758
34818
|
}
|
|
34759
|
-
|
|
34819
|
+
|
|
34820
|
+
if (!feat) return;
|
|
34821
|
+
|
|
34822
|
+
if (feat.type == 'GeometryCollection') {
|
|
34823
|
+
arr = feat.geometries.map(geom => GeoJSON.toFeature(geom));
|
|
34824
|
+
} else if (feat.type == 'FeatureCollection') {
|
|
34825
|
+
arr = feat.features;
|
|
34826
|
+
} else {
|
|
34827
|
+
feat = GeoJSON.toFeature(feat);
|
|
34828
|
+
}
|
|
34829
|
+
|
|
34830
|
+
if (arr) {
|
|
34831
|
+
features2 = features2.concat(arr);
|
|
34832
|
+
} else {
|
|
34833
|
+
features2.push(feat);
|
|
34834
|
+
}
|
|
34760
34835
|
};
|
|
34761
34836
|
|
|
34762
34837
|
api.done = function() {
|
|
34763
|
-
if (
|
|
34764
|
-
// TODO: validate number of features, etc.
|
|
34838
|
+
if (features2.length === 0) return; // read-only expression
|
|
34765
34839
|
var geojson = {
|
|
34766
34840
|
type: 'FeatureCollection',
|
|
34767
|
-
features:
|
|
34841
|
+
features: features2
|
|
34768
34842
|
};
|
|
34769
|
-
|
|
34770
|
-
// console.log(JSON.stringify(geojson, null, 2))
|
|
34771
34843
|
return importGeoJSON(geojson);
|
|
34772
34844
|
};
|
|
34773
34845
|
return api;
|
|
@@ -40530,9 +40602,8 @@ ${svg}
|
|
|
40530
40602
|
cmd.polygonGrid = function(targetLayers, targetDataset, opts) {
|
|
40531
40603
|
requireProjectedDataset(targetDataset);
|
|
40532
40604
|
var params = getGridParams(targetLayers, targetDataset, opts);
|
|
40533
|
-
var gridDataset = makeGridDataset(params);
|
|
40534
|
-
|
|
40535
|
-
gridDataset.info = targetDataset.info; // copy CRS to grid dataset // TODO: improve
|
|
40605
|
+
var gridDataset = makeGridDataset(params); // grid is a new dataset
|
|
40606
|
+
gridDataset.info = copyDatasetInfo(targetDataset.info);
|
|
40536
40607
|
setOutputLayerName(gridDataset.layers[0], null, 'grid', opts);
|
|
40537
40608
|
if (opts.debug) gridDataset.layers.push(cmd.pointGrid2(targetLayers, targetDataset, opts));
|
|
40538
40609
|
return gridDataset;
|
package/package.json
CHANGED
package/www/index.html
CHANGED
|
@@ -156,7 +156,7 @@
|
|
|
156
156
|
<div class="export-formats option-menu">
|
|
157
157
|
</div>
|
|
158
158
|
|
|
159
|
-
<div style="height:
|
|
159
|
+
<div style="height:11px"></div>
|
|
160
160
|
|
|
161
161
|
<div class="option-menu"><input type="text" class="text-input advanced-options" placeholder="command line options" />
|
|
162
162
|
<a href="https://github.com/mbloch/mapshaper/wiki/Command-Reference#-o-output" target="_mapshaper_output_docs">
|
|
@@ -164,15 +164,15 @@
|
|
|
164
164
|
<div class="tip">Enter options from the command line interface for
|
|
165
165
|
the -o command. Examples: bbox no-quantization
|
|
166
166
|
precision=0.001. Click to see all options.</div></div></div></a>
|
|
167
|
-
|
|
167
|
+
|
|
168
168
|
|
|
169
169
|
<!-- <div class="option-menu">
|
|
170
170
|
<input id="ofile-name" class="text-input" type="text" placeholder="output file name" />
|
|
171
171
|
</div> -->
|
|
172
|
-
|
|
173
|
-
<div
|
|
174
|
-
|
|
175
|
-
<
|
|
172
|
+
<div><span id="save-preference" style="display: none;"><input type="checkbox"/>choose output directory</span></div>
|
|
173
|
+
<div><span id="save-to-clipboard" style="display: inline-block;"><input type="checkbox"/>save to clipboard</span></div>
|
|
174
|
+
</div>
|
|
175
|
+
<div id="export-btn" class="btn dialog-btn" style="margin-top: 4px;">Export</div>
|
|
176
176
|
|
|
177
177
|
</div>
|
|
178
178
|
</div>
|
package/www/mapshaper-gui.js
CHANGED
|
@@ -3504,6 +3504,7 @@
|
|
|
3504
3504
|
// keeping a reference to current arcs and intersections, so intersections
|
|
3505
3505
|
// don't need to be recalculated when 'repair' button is pressed.
|
|
3506
3506
|
_currArcs,
|
|
3507
|
+
_currLayer,
|
|
3507
3508
|
_currXX;
|
|
3508
3509
|
|
|
3509
3510
|
gui.on('simplify_drag_start', hide);
|
|
@@ -3524,8 +3525,8 @@
|
|
|
3524
3525
|
});
|
|
3525
3526
|
|
|
3526
3527
|
repairBtn.on('click', function() {
|
|
3527
|
-
|
|
3528
|
-
showIntersections(
|
|
3528
|
+
_currXX = internal.repairIntersections(_currArcs, _currXX);
|
|
3529
|
+
showIntersections();
|
|
3529
3530
|
repairBtn.addClass('disabled');
|
|
3530
3531
|
model.updated({repair: true});
|
|
3531
3532
|
gui.session.simplificationRepair();
|
|
@@ -3573,13 +3574,17 @@
|
|
|
3573
3574
|
showBtn = false;
|
|
3574
3575
|
}
|
|
3575
3576
|
el.show();
|
|
3576
|
-
|
|
3577
|
+
_currLayer = e.layer;
|
|
3578
|
+
_currArcs = arcs;
|
|
3579
|
+
_currXX = XX;
|
|
3580
|
+
showIntersections();
|
|
3577
3581
|
repairBtn.classed('disabled', !showBtn);
|
|
3578
3582
|
}
|
|
3579
3583
|
|
|
3580
3584
|
function reset() {
|
|
3581
3585
|
_currArcs = null;
|
|
3582
3586
|
_currXX = null;
|
|
3587
|
+
_currLayer = null;
|
|
3583
3588
|
hide();
|
|
3584
3589
|
}
|
|
3585
3590
|
|
|
@@ -3590,13 +3595,11 @@
|
|
|
3590
3595
|
reset();
|
|
3591
3596
|
}
|
|
3592
3597
|
|
|
3593
|
-
function showIntersections(
|
|
3594
|
-
var n =
|
|
3595
|
-
_currXX = XX;
|
|
3596
|
-
_currArcs = arcs;
|
|
3598
|
+
function showIntersections() {
|
|
3599
|
+
var n = _currXX.length, pointLyr;
|
|
3597
3600
|
if (n > 0) {
|
|
3598
3601
|
// console.log("first intersection:", internal.getIntersectionDebugData(XX[0], arcs));
|
|
3599
|
-
pointLyr =
|
|
3602
|
+
pointLyr = internal.getIntersectionLayer(_currXX, _currLayer, _currArcs);
|
|
3600
3603
|
map.setIntersectionLayer(pointLyr, {layers:[pointLyr]});
|
|
3601
3604
|
readout.html(utils$1.format('<span class="icon"></span>%s line intersection%s <img class="close-btn" src="images/close.png">', n, utils$1.pluralSuffix(n)));
|
|
3602
3605
|
readout.findChild('.close-btn').on('click', dismiss);
|
|
@@ -3672,11 +3675,12 @@
|
|
|
3672
3675
|
return;
|
|
3673
3676
|
}
|
|
3674
3677
|
|
|
3675
|
-
new SimpleButton(menu.findChild('
|
|
3678
|
+
new SimpleButton(menu.findChild('#export-btn').addClass('default-btn')).on('click', onExportClick);
|
|
3676
3679
|
gui.addMode('export', turnOn, turnOff, exportBtn);
|
|
3677
3680
|
gui.keyboard.onMenuSubmit(menu, onExportClick);
|
|
3681
|
+
var savePreferenceCheckbox;
|
|
3678
3682
|
if (window.showSaveFilePicker) {
|
|
3679
|
-
menu.findChild('#save-preference')
|
|
3683
|
+
savePreferenceCheckbox = menu.findChild('#save-preference')
|
|
3680
3684
|
.css('display', 'inline-block')
|
|
3681
3685
|
.findChild('input')
|
|
3682
3686
|
.on('change', function() {
|
|
@@ -3684,11 +3688,44 @@
|
|
|
3684
3688
|
})
|
|
3685
3689
|
.attr('checked', GUI.getSavedValue('choose-save-dir') || null);
|
|
3686
3690
|
}
|
|
3691
|
+
var clipboardCheckbox = menu.findChild('#save-to-clipboard')
|
|
3692
|
+
.findChild('input')
|
|
3693
|
+
.on('change', function() {
|
|
3694
|
+
updateExportCheckboxes();
|
|
3695
|
+
});
|
|
3696
|
+
|
|
3697
|
+
function setDisabled(inputEl, flag) {
|
|
3698
|
+
if (!inputEl) return;
|
|
3699
|
+
inputEl.node().disabled = !!flag;
|
|
3700
|
+
inputEl.parent().css({color: flag ? '#bbb' : 'black'});
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3703
|
+
function checkboxOn(inputEl) {
|
|
3704
|
+
if (!inputEl) return false;
|
|
3705
|
+
return inputEl.node().checked && !inputEl.node().disabled;
|
|
3706
|
+
}
|
|
3707
|
+
|
|
3708
|
+
function updateExportCheckboxes() {
|
|
3709
|
+
// disable cliboard if not usable
|
|
3710
|
+
var canUseClipboard = clipboardIsAvailable();
|
|
3711
|
+
setDisabled(clipboardCheckbox, !canUseClipboard);
|
|
3712
|
+
|
|
3713
|
+
// disable save to directory checkbox if clipboard is selected
|
|
3714
|
+
setDisabled(savePreferenceCheckbox, checkboxOn(clipboardCheckbox));
|
|
3715
|
+
}
|
|
3716
|
+
|
|
3717
|
+
function clipboardIsAvailable() {
|
|
3718
|
+
var layers = getSelectedLayerEntries();
|
|
3719
|
+
var fmt = getSelectedFormat();
|
|
3720
|
+
return layers.length == 1 && ['json', 'geojson', 'dsv', 'topojson'].includes(fmt);
|
|
3721
|
+
}
|
|
3722
|
+
|
|
3687
3723
|
|
|
3688
3724
|
function turnOn() {
|
|
3689
3725
|
layersArr = initLayerMenu();
|
|
3690
3726
|
// initZipOption();
|
|
3691
3727
|
initFormatMenu();
|
|
3728
|
+
updateExportCheckboxes();
|
|
3692
3729
|
menu.show();
|
|
3693
3730
|
}
|
|
3694
3731
|
|
|
@@ -3697,22 +3734,25 @@
|
|
|
3697
3734
|
menu.hide();
|
|
3698
3735
|
}
|
|
3699
3736
|
|
|
3700
|
-
function
|
|
3701
|
-
|
|
3737
|
+
function getSelectedLayerEntries() {
|
|
3738
|
+
return layersArr.reduce(function(memo, o) {
|
|
3702
3739
|
return o.checkbox.checked ? memo.concat(o.target) : memo;
|
|
3703
3740
|
}, []);
|
|
3704
|
-
|
|
3741
|
+
}
|
|
3742
|
+
|
|
3743
|
+
function getExportTargets() {
|
|
3744
|
+
return internal.groupLayersByDataset(getSelectedLayerEntries());
|
|
3705
3745
|
}
|
|
3706
3746
|
|
|
3707
3747
|
function onExportClick() {
|
|
3708
|
-
var
|
|
3709
|
-
if (
|
|
3748
|
+
var targets = getExportTargets();
|
|
3749
|
+
if (targets.length === 0) {
|
|
3710
3750
|
return gui.alert('No layers were selected');
|
|
3711
3751
|
}
|
|
3712
3752
|
gui.clearMode();
|
|
3713
3753
|
gui.showProgressMessage('Exporting');
|
|
3714
3754
|
setTimeout(function() {
|
|
3715
|
-
exportMenuSelection(
|
|
3755
|
+
exportMenuSelection(targets).catch(function(err) {
|
|
3716
3756
|
if (utils$1.isString(err)) {
|
|
3717
3757
|
gui.alert(err);
|
|
3718
3758
|
} else {
|
|
@@ -3742,12 +3782,22 @@
|
|
|
3742
3782
|
}
|
|
3743
3783
|
|
|
3744
3784
|
// done: function(string|Error|null)
|
|
3745
|
-
async function exportMenuSelection(
|
|
3785
|
+
async function exportMenuSelection(targets) {
|
|
3746
3786
|
var opts = getExportOpts();
|
|
3747
3787
|
// note: command line "target" option gets ignored
|
|
3748
|
-
var files = await internal.exportTargetLayers(
|
|
3788
|
+
var files = await internal.exportTargetLayers(targets, opts);
|
|
3749
3789
|
gui.session.layersExported(getTargetLayerIds(), getExportOptsAsString());
|
|
3750
|
-
|
|
3790
|
+
if (files.length == 1 && checkboxOn(clipboardCheckbox)) {
|
|
3791
|
+
await saveFileContentToClipboard(files[0].content);
|
|
3792
|
+
} else {
|
|
3793
|
+
await utils$1.promisify(internal.writeFiles)(files, opts);
|
|
3794
|
+
}
|
|
3795
|
+
|
|
3796
|
+
}
|
|
3797
|
+
|
|
3798
|
+
async function saveFileContentToClipboard(content) {
|
|
3799
|
+
var str = utils$1.isString(content) ? content : content.toString();
|
|
3800
|
+
await navigator.clipboard.writeText(str);
|
|
3751
3801
|
}
|
|
3752
3802
|
|
|
3753
3803
|
function initLayerItem(o, i) {
|
|
@@ -3833,6 +3883,7 @@
|
|
|
3833
3883
|
}
|
|
3834
3884
|
|
|
3835
3885
|
function updateToggleBtn() {
|
|
3886
|
+
updateExportCheckboxes(); // checkbox visibility is affected by number of export layers
|
|
3836
3887
|
if (!toggleBtn) return;
|
|
3837
3888
|
var state = getSelectionState();
|
|
3838
3889
|
// style of intermediate checkbox state doesn't look right in Chrome --
|
|
@@ -3853,30 +3904,49 @@
|
|
|
3853
3904
|
return 'some';
|
|
3854
3905
|
}
|
|
3855
3906
|
|
|
3856
|
-
function getInputFormats() {
|
|
3857
|
-
return model.getDatasets().reduce(function(memo, d) {
|
|
3858
|
-
var fmts = d.info && d.info.input_formats || [];
|
|
3859
|
-
return memo.concat(fmts);
|
|
3860
|
-
}, []);
|
|
3861
|
-
}
|
|
3862
|
-
|
|
3863
3907
|
function getDefaultExportFormat() {
|
|
3864
3908
|
var dataset = model.getActiveLayer().dataset;
|
|
3865
|
-
|
|
3866
|
-
dataset.info.input_formats[0]
|
|
3909
|
+
var inputFmt = dataset.info && dataset.info.input_formats &&
|
|
3910
|
+
dataset.info.input_formats[0];
|
|
3911
|
+
return getExportFormats().includes(inputFmt) ? inputFmt : 'geojson';
|
|
3912
|
+
}
|
|
3913
|
+
|
|
3914
|
+
function getExportFormats() {
|
|
3915
|
+
// return ['shapefile', 'geojson', 'topojson', 'json', 'dsv', 'kml', 'svg', internal.PACKAGE_EXT];
|
|
3916
|
+
return ['shapefile', 'json', 'geojson', 'dsv', 'topojson', 'kml', internal.PACKAGE_EXT, 'svg'];
|
|
3867
3917
|
}
|
|
3868
3918
|
|
|
3869
3919
|
function initFormatMenu() {
|
|
3870
|
-
var
|
|
3871
|
-
var formats = utils
|
|
3920
|
+
var formats = getExportFormats();
|
|
3921
|
+
// var formats = utils.uniq(getExportFormats().concat(getInputFormats()));
|
|
3872
3922
|
var items = formats.map(function(fmt) {
|
|
3873
|
-
return utils$1.format('<
|
|
3874
|
-
' class="radio">%s</label></
|
|
3923
|
+
return utils$1.format('<td><label><input type="radio" name="format" value="%s"' +
|
|
3924
|
+
' class="radio">%s</label></td>', fmt, internal.getFormatName(fmt));
|
|
3875
3925
|
});
|
|
3876
|
-
|
|
3926
|
+
var table = '<table>';
|
|
3927
|
+
for (var i=0; i<items.length; i+=2) {
|
|
3928
|
+
table += '<tr>' + items[i] + items[i+1] + '<tr>';
|
|
3929
|
+
}
|
|
3930
|
+
table += '</table>';
|
|
3931
|
+
|
|
3932
|
+
// menu.findChild('.export-formats').html(items.join('\n'));
|
|
3933
|
+
menu.findChild('.export-formats').html(table);
|
|
3877
3934
|
menu.findChild('.export-formats input[value="' + getDefaultExportFormat() + '"]').node().checked = true;
|
|
3935
|
+
// update save-as settings when value changes
|
|
3936
|
+
menu.findChildren('input[type="radio"]').forEach(el => {
|
|
3937
|
+
el.on('change', updateExportCheckboxes);
|
|
3938
|
+
});
|
|
3878
3939
|
}
|
|
3879
3940
|
|
|
3941
|
+
|
|
3942
|
+
// function getInputFormats() {
|
|
3943
|
+
// return model.getDatasets().reduce(function(memo, d) {
|
|
3944
|
+
// var fmts = d.info && d.info.input_formats || [];
|
|
3945
|
+
// return memo.concat(fmts);
|
|
3946
|
+
// }, []);
|
|
3947
|
+
// }
|
|
3948
|
+
|
|
3949
|
+
|
|
3880
3950
|
function initZipOption() {
|
|
3881
3951
|
var html = `<label><input type="checkbox">Save to .zip file</label>`;
|
|
3882
3952
|
menu.findChild('.export-zip-option').html(html);
|
|
@@ -6303,6 +6373,23 @@
|
|
|
6303
6373
|
return [xmin, ymin, xmax, ymax];
|
|
6304
6374
|
}
|
|
6305
6375
|
|
|
6376
|
+
|
|
6377
|
+
function findArcIdFromVertexId(i, ii) {
|
|
6378
|
+
// binary search
|
|
6379
|
+
// possible optimization: use interpolation to find a better partition value.
|
|
6380
|
+
var lower = 0, upper = ii.length - 1;
|
|
6381
|
+
var middle;
|
|
6382
|
+
while (lower < upper) {
|
|
6383
|
+
middle = Math.ceil((lower + upper) / 2);
|
|
6384
|
+
if (i < ii[middle]) {
|
|
6385
|
+
upper = middle - 1;
|
|
6386
|
+
} else {
|
|
6387
|
+
lower = middle;
|
|
6388
|
+
}
|
|
6389
|
+
}
|
|
6390
|
+
return lower; // assumes dataset is not empty
|
|
6391
|
+
}
|
|
6392
|
+
|
|
6306
6393
|
function deleteVertex(arcs, i) {
|
|
6307
6394
|
var data = arcs.getVertexData();
|
|
6308
6395
|
var nn = data.nn;
|
|
@@ -8177,8 +8264,8 @@
|
|
|
8177
8264
|
var popup = showPopupAlert('', 'Add field');
|
|
8178
8265
|
var el = popup.container();
|
|
8179
8266
|
el.addClass('option-menu');
|
|
8180
|
-
var html = `<input type="text" class="field-name text-input" placeholder="field name"
|
|
8181
|
-
<input type="text" class="field-value text-input" placeholder="value"><
|
|
8267
|
+
var html = `<div><input type="text" class="field-name text-input" placeholder="field name"></div>
|
|
8268
|
+
<div><input type="text" class="field-value text-input" placeholder="value"><div>
|
|
8182
8269
|
<div tabindex="0" class="btn dialog-btn">Apply</div> <span class="inline-checkbox"><input type="checkbox" class="all" />assign value to all records</span>`;
|
|
8183
8270
|
el.html(html);
|
|
8184
8271
|
|
|
@@ -11495,6 +11582,9 @@
|
|
|
11495
11582
|
new SessionSnapshots(gui);
|
|
11496
11583
|
}
|
|
11497
11584
|
|
|
11585
|
+
var msgCount = 0;
|
|
11586
|
+
var clearMsg;
|
|
11587
|
+
|
|
11498
11588
|
initModeRules(gui);
|
|
11499
11589
|
|
|
11500
11590
|
gui.showProgressMessage = function(msg) {
|
|
@@ -11503,10 +11593,25 @@
|
|
|
11503
11593
|
.appendTo('body');
|
|
11504
11594
|
}
|
|
11505
11595
|
El('<div>').text(msg).appendTo(gui.progressMessage.empty().show());
|
|
11596
|
+
clearMsg = getClearFunction(msgCount);
|
|
11506
11597
|
};
|
|
11507
11598
|
|
|
11599
|
+
function getClearFunction(count) {
|
|
11600
|
+
var time = Date.now();
|
|
11601
|
+
// wait at least [min] milliseconds before closing
|
|
11602
|
+
var min = 400;
|
|
11603
|
+
msgCount = ++count;
|
|
11604
|
+
return function() {
|
|
11605
|
+
setTimeout(function() {
|
|
11606
|
+
if (count != msgCount) return;
|
|
11607
|
+
if (gui.progressMessage) gui.progressMessage.hide();
|
|
11608
|
+
}, Math.max(min - (Date.now() - time), 0));
|
|
11609
|
+
};
|
|
11610
|
+
}
|
|
11611
|
+
|
|
11508
11612
|
gui.clearProgressMessage = function() {
|
|
11509
|
-
|
|
11613
|
+
clearMsg();
|
|
11614
|
+
// if (gui.progressMessage) gui.progressMessage.hide();
|
|
11510
11615
|
};
|
|
11511
11616
|
|
|
11512
11617
|
gui.consoleIsOpen = function() {
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.6.
|
|
3
|
+
var VERSION = "0.6.46";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -1813,6 +1813,23 @@
|
|
|
1813
1813
|
return [xmin, ymin, xmax, ymax];
|
|
1814
1814
|
}
|
|
1815
1815
|
|
|
1816
|
+
|
|
1817
|
+
function findArcIdFromVertexId(i, ii) {
|
|
1818
|
+
// binary search
|
|
1819
|
+
// possible optimization: use interpolation to find a better partition value.
|
|
1820
|
+
var lower = 0, upper = ii.length - 1;
|
|
1821
|
+
var middle;
|
|
1822
|
+
while (lower < upper) {
|
|
1823
|
+
middle = Math.ceil((lower + upper) / 2);
|
|
1824
|
+
if (i < ii[middle]) {
|
|
1825
|
+
upper = middle - 1;
|
|
1826
|
+
} else {
|
|
1827
|
+
lower = middle;
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
return lower; // assumes dataset is not empty
|
|
1831
|
+
}
|
|
1832
|
+
|
|
1816
1833
|
function deleteVertex(arcs, i) {
|
|
1817
1834
|
var data = arcs.getVertexData();
|
|
1818
1835
|
var nn = data.nn;
|
|
@@ -1939,6 +1956,7 @@
|
|
|
1939
1956
|
__proto__: null,
|
|
1940
1957
|
absArcId: absArcId,
|
|
1941
1958
|
calcArcBounds: calcArcBounds,
|
|
1959
|
+
findArcIdFromVertexId: findArcIdFromVertexId,
|
|
1942
1960
|
deleteVertex: deleteVertex,
|
|
1943
1961
|
insertVertex: insertVertex,
|
|
1944
1962
|
countFilteredVertices: countFilteredVertices,
|
|
@@ -3405,7 +3423,7 @@
|
|
|
3405
3423
|
var item;
|
|
3406
3424
|
for (var i=0; i<arr.length; i++) {
|
|
3407
3425
|
item = arr[i];
|
|
3408
|
-
if (item
|
|
3426
|
+
if (Array.isArray(item)) {
|
|
3409
3427
|
forEachArcId(item, cb);
|
|
3410
3428
|
} else if (utils.isInteger(item)) {
|
|
3411
3429
|
var val = cb(item);
|
|
@@ -6953,6 +6971,15 @@
|
|
|
6953
6971
|
utils.defaults(destInfo, srcInfo);
|
|
6954
6972
|
}
|
|
6955
6973
|
|
|
6974
|
+
function copyDatasetInfo(info) {
|
|
6975
|
+
// not a deep copy... objects like info.crs are read-only, so copy-by-reference
|
|
6976
|
+
// should be ok
|
|
6977
|
+
var info2 = Object.assign({}, info);
|
|
6978
|
+
if (Array.isArray(info.input_files)) {
|
|
6979
|
+
info2.input_files = info.input_files.concat();
|
|
6980
|
+
}
|
|
6981
|
+
return info2;
|
|
6982
|
+
}
|
|
6956
6983
|
|
|
6957
6984
|
function splitApartLayers(dataset, layers) {
|
|
6958
6985
|
var datasets = [];
|
|
@@ -7119,6 +7146,7 @@
|
|
|
7119
7146
|
__proto__: null,
|
|
7120
7147
|
splitDataset: splitDataset,
|
|
7121
7148
|
mergeDatasetInfo: mergeDatasetInfo,
|
|
7149
|
+
copyDatasetInfo: copyDatasetInfo,
|
|
7122
7150
|
splitApartLayers: splitApartLayers,
|
|
7123
7151
|
copyDataset: copyDataset,
|
|
7124
7152
|
copyDatasetForExport: copyDatasetForExport,
|
|
@@ -15481,6 +15509,17 @@
|
|
|
15481
15509
|
|
|
15482
15510
|
// Keep track of whether positive or negative integer ids are 'used' or not.
|
|
15483
15511
|
|
|
15512
|
+
|
|
15513
|
+
function SimpleIdTestIndex(n) {
|
|
15514
|
+
var index = new Uint8Array(n);
|
|
15515
|
+
this.setId = function(id) {
|
|
15516
|
+
index[id] = 1;
|
|
15517
|
+
};
|
|
15518
|
+
this.hasId = function(id) {
|
|
15519
|
+
return index[id] === 1;
|
|
15520
|
+
};
|
|
15521
|
+
}
|
|
15522
|
+
|
|
15484
15523
|
function IdTestIndex(n) {
|
|
15485
15524
|
var index = new Uint8Array(n);
|
|
15486
15525
|
var setList = [];
|
|
@@ -15743,15 +15782,30 @@
|
|
|
15743
15782
|
getHoleDivider: getHoleDivider
|
|
15744
15783
|
});
|
|
15745
15784
|
|
|
15746
|
-
// Convert an array of intersections into an ArcCollection (for display)
|
|
15747
|
-
//
|
|
15748
|
-
|
|
15749
15785
|
function getIntersectionPoints(intersections) {
|
|
15750
15786
|
return intersections.map(function(obj) {
|
|
15751
15787
|
return [obj.x, obj.y];
|
|
15752
15788
|
});
|
|
15753
15789
|
}
|
|
15754
15790
|
|
|
15791
|
+
function getIntersectionLayer(intersections, lyr, arcs) {
|
|
15792
|
+
// return {geometry_type: 'point', shapes: [getIntersectionPoints(XX)]};
|
|
15793
|
+
var ii = arcs.getVertexData().ii;
|
|
15794
|
+
var index = new SimpleIdTestIndex(arcs.size());
|
|
15795
|
+
forEachArcId(lyr.shapes, arcId => {
|
|
15796
|
+
index.setId(absArcId(arcId));
|
|
15797
|
+
});
|
|
15798
|
+
var points = [];
|
|
15799
|
+
intersections.forEach(obj => {
|
|
15800
|
+
var arc1 = findArcIdFromVertexId(obj.a[0], ii);
|
|
15801
|
+
var arc2 = findArcIdFromVertexId(obj.b[0], ii);
|
|
15802
|
+
if (index.hasId(arc1) && index.hasId(arc2)) {
|
|
15803
|
+
points.push([obj.x, obj.y]);
|
|
15804
|
+
}
|
|
15805
|
+
});
|
|
15806
|
+
return {geometry_type: 'point', shapes: [points]};
|
|
15807
|
+
}
|
|
15808
|
+
|
|
15755
15809
|
// Identify intersecting segments in an ArcCollection
|
|
15756
15810
|
//
|
|
15757
15811
|
// To find all intersections:
|
|
@@ -15999,6 +16053,7 @@
|
|
|
15999
16053
|
var SegmentIntersection = /*#__PURE__*/Object.freeze({
|
|
16000
16054
|
__proto__: null,
|
|
16001
16055
|
getIntersectionPoints: getIntersectionPoints,
|
|
16056
|
+
getIntersectionLayer: getIntersectionLayer,
|
|
16002
16057
|
findSegmentIntersections: findSegmentIntersections,
|
|
16003
16058
|
sortIntersections: sortIntersections,
|
|
16004
16059
|
dedupIntersections: dedupIntersections,
|
|
@@ -33396,7 +33451,7 @@ ${svg}
|
|
|
33396
33451
|
if (n != values.length) {
|
|
33397
33452
|
stop('Mismatch in number of categories and number of values');
|
|
33398
33453
|
}
|
|
33399
|
-
return values;
|
|
33454
|
+
return parseValues(values); // convert numerical strings to numbers
|
|
33400
33455
|
}
|
|
33401
33456
|
|
|
33402
33457
|
function getIndexes(n) {
|
|
@@ -33564,7 +33619,7 @@ ${svg}
|
|
|
33564
33619
|
if (opts.index_field) {
|
|
33565
33620
|
dataField = opts.index_field;
|
|
33566
33621
|
fieldType = getColumnType(opts.field, records);
|
|
33567
|
-
|
|
33622
|
+
} else if (opts.field) {
|
|
33568
33623
|
dataField = opts.field;
|
|
33569
33624
|
fieldType = getColumnType(opts.field, records);
|
|
33570
33625
|
}
|
|
@@ -33596,6 +33651,9 @@ ${svg}
|
|
|
33596
33651
|
if ((!opts.categories || opts.categories.includes('*')) && dataField) {
|
|
33597
33652
|
opts.categories = getUniqFieldValues(records, dataField);
|
|
33598
33653
|
}
|
|
33654
|
+
if (opts.categories && fieldType == 'number') {
|
|
33655
|
+
opts.categories = opts.categories.map(str => +str);
|
|
33656
|
+
}
|
|
33599
33657
|
}
|
|
33600
33658
|
|
|
33601
33659
|
if (opts.classes) {
|
|
@@ -34740,34 +34798,48 @@ ${svg}
|
|
|
34740
34798
|
}
|
|
34741
34799
|
|
|
34742
34800
|
function getFeatureEditor(lyr, dataset) {
|
|
34743
|
-
var changed = false;
|
|
34744
34801
|
var api = {};
|
|
34745
34802
|
// need to copy attribute to avoid circular references if geojson is assigned
|
|
34746
34803
|
// to a data property.
|
|
34747
34804
|
var copy = copyLayer(lyr);
|
|
34748
34805
|
var features = exportLayerAsGeoJSON(copy, dataset, {}, true);
|
|
34806
|
+
var features2 = [];
|
|
34749
34807
|
|
|
34750
34808
|
api.get = function(i) {
|
|
34809
|
+
if (i > 0) features[i-1] = null; // garbage-collect old features
|
|
34751
34810
|
return features[i];
|
|
34752
34811
|
};
|
|
34753
34812
|
|
|
34754
34813
|
api.set = function(feat, i) {
|
|
34755
|
-
|
|
34814
|
+
var arr;
|
|
34815
|
+
|
|
34756
34816
|
if (utils.isString(feat)) {
|
|
34757
34817
|
feat = JSON.parse(feat);
|
|
34758
34818
|
}
|
|
34759
|
-
|
|
34819
|
+
|
|
34820
|
+
if (!feat) return;
|
|
34821
|
+
|
|
34822
|
+
if (feat.type == 'GeometryCollection') {
|
|
34823
|
+
arr = feat.geometries.map(geom => GeoJSON.toFeature(geom));
|
|
34824
|
+
} else if (feat.type == 'FeatureCollection') {
|
|
34825
|
+
arr = feat.features;
|
|
34826
|
+
} else {
|
|
34827
|
+
feat = GeoJSON.toFeature(feat);
|
|
34828
|
+
}
|
|
34829
|
+
|
|
34830
|
+
if (arr) {
|
|
34831
|
+
features2 = features2.concat(arr);
|
|
34832
|
+
} else {
|
|
34833
|
+
features2.push(feat);
|
|
34834
|
+
}
|
|
34760
34835
|
};
|
|
34761
34836
|
|
|
34762
34837
|
api.done = function() {
|
|
34763
|
-
if (
|
|
34764
|
-
// TODO: validate number of features, etc.
|
|
34838
|
+
if (features2.length === 0) return; // read-only expression
|
|
34765
34839
|
var geojson = {
|
|
34766
34840
|
type: 'FeatureCollection',
|
|
34767
|
-
features:
|
|
34841
|
+
features: features2
|
|
34768
34842
|
};
|
|
34769
|
-
|
|
34770
|
-
// console.log(JSON.stringify(geojson, null, 2))
|
|
34771
34843
|
return importGeoJSON(geojson);
|
|
34772
34844
|
};
|
|
34773
34845
|
return api;
|
|
@@ -40530,9 +40602,8 @@ ${svg}
|
|
|
40530
40602
|
cmd.polygonGrid = function(targetLayers, targetDataset, opts) {
|
|
40531
40603
|
requireProjectedDataset(targetDataset);
|
|
40532
40604
|
var params = getGridParams(targetLayers, targetDataset, opts);
|
|
40533
|
-
var gridDataset = makeGridDataset(params);
|
|
40534
|
-
|
|
40535
|
-
gridDataset.info = targetDataset.info; // copy CRS to grid dataset // TODO: improve
|
|
40605
|
+
var gridDataset = makeGridDataset(params); // grid is a new dataset
|
|
40606
|
+
gridDataset.info = copyDatasetInfo(targetDataset.info);
|
|
40536
40607
|
setOutputLayerName(gridDataset.layers[0], null, 'grid', opts);
|
|
40537
40608
|
if (opts.debug) gridDataset.layers.push(cmd.pointGrid2(targetLayers, targetDataset, opts));
|
|
40538
40609
|
return gridDataset;
|
package/www/page.css
CHANGED
|
@@ -90,7 +90,7 @@ body {
|
|
|
90
90
|
.dialog-btn {
|
|
91
91
|
display: inline-block;
|
|
92
92
|
margin-bottom: 1px;
|
|
93
|
-
margin-top:
|
|
93
|
+
margin-top: 3px;
|
|
94
94
|
font-size: 13px;
|
|
95
95
|
color: white;
|
|
96
96
|
min-width: 28px;
|
|
@@ -232,6 +232,13 @@ body {
|
|
|
232
232
|
padding: 4px 6px 5px 6px;
|
|
233
233
|
}
|
|
234
234
|
|
|
235
|
+
.export-options table {
|
|
236
|
+
margin: 0;
|
|
237
|
+
border-collapse: collapse;
|
|
238
|
+
border-spacing: 0;
|
|
239
|
+
width: 100%;
|
|
240
|
+
}
|
|
241
|
+
|
|
235
242
|
.export-layer-list {
|
|
236
243
|
max-height: 160px;
|
|
237
244
|
overflow: hidden;
|
|
@@ -274,7 +281,7 @@ body {
|
|
|
274
281
|
.alert-title {
|
|
275
282
|
line-height: 1.1;
|
|
276
283
|
font-weight: bold;
|
|
277
|
-
margin-bottom:
|
|
284
|
+
margin-bottom: 7px;
|
|
278
285
|
}
|
|
279
286
|
|
|
280
287
|
div.alert-title, div.error-message {
|
|
@@ -461,6 +468,7 @@ body.dragover #import-options-drop-area .drop-area {
|
|
|
461
468
|
margin: 0 0 5px 0;
|
|
462
469
|
}
|
|
463
470
|
|
|
471
|
+
|
|
464
472
|
#mshp-not-supported {
|
|
465
473
|
display: none;
|
|
466
474
|
z-index: 100;
|
|
@@ -549,10 +557,12 @@ body.dragover #import-options-drop-area .drop-area {
|
|
|
549
557
|
font-size: 90%;
|
|
550
558
|
}
|
|
551
559
|
|
|
560
|
+
|
|
561
|
+
|
|
552
562
|
/*.option-menu input[type="radio"],
|
|
553
563
|
.option-menu input[type="checkbox"] */
|
|
554
|
-
|
|
555
|
-
|
|
564
|
+
input[type="radio"],
|
|
565
|
+
input[type="checkbox"]
|
|
556
566
|
{
|
|
557
567
|
position: relative;
|
|
558
568
|
top: 1px;
|
|
@@ -1126,7 +1136,7 @@ img.close-btn:hover,
|
|
|
1126
1136
|
|
|
1127
1137
|
.basemap-styles > div {
|
|
1128
1138
|
display: inline-block;
|
|
1129
|
-
margin-bottom:
|
|
1139
|
+
margin-bottom: 6px;
|
|
1130
1140
|
}
|
|
1131
1141
|
|
|
1132
1142
|
.basemap-styles > div:nth-child(even) {
|
|
@@ -1234,9 +1244,7 @@ div.basemap-style-btn.active img {
|
|
|
1234
1244
|
}
|
|
1235
1245
|
|
|
1236
1246
|
.inline-checkbox {
|
|
1237
|
-
|
|
1238
|
-
top: 1px;
|
|
1239
|
-
left: 5px;
|
|
1247
|
+
margin-left: 5px;
|
|
1240
1248
|
}
|
|
1241
1249
|
|
|
1242
1250
|
#save-preference {
|