mapshaper 0.5.104 → 0.5.107
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/CHANGELOG.md +10 -0
- package/mapshaper.js +73 -10
- package/package.json +1 -1
- package/www/mapshaper-gui.js +67 -60
- package/www/mapshaper.js +73 -10
- package/www/page.css +6 -6
package/CHANGELOG.md
CHANGED
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.5.
|
|
3
|
+
var VERSION = "0.5.103";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -1737,6 +1737,16 @@
|
|
|
1737
1737
|
|
|
1738
1738
|
// Iterate over each [x,y] point in a layer
|
|
1739
1739
|
// shapes: one layer's "shapes" array
|
|
1740
|
+
function forEachPoint_(shapes, cb) {
|
|
1741
|
+
var i, n, j, m, shp;
|
|
1742
|
+
for (i=0, n=shapes.length; i<n; i++) {
|
|
1743
|
+
shp = shapes[i];
|
|
1744
|
+
for (j=0, m=shp ? shp.length : 0; j<m; j++) {
|
|
1745
|
+
cb(shp[j], i);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1740
1750
|
function forEachPoint(shapes, cb) {
|
|
1741
1751
|
var i, n, j, m, shp;
|
|
1742
1752
|
for (i=0, n=shapes.length; i<n; i++) {
|
|
@@ -1753,6 +1763,7 @@
|
|
|
1753
1763
|
getPointBounds: getPointBounds$1,
|
|
1754
1764
|
getPointFeatureBounds: getPointFeatureBounds,
|
|
1755
1765
|
getPointsInLayer: getPointsInLayer,
|
|
1766
|
+
forEachPoint_: forEachPoint_,
|
|
1756
1767
|
forEachPoint: forEachPoint
|
|
1757
1768
|
});
|
|
1758
1769
|
|
|
@@ -7813,10 +7824,24 @@
|
|
|
7813
7824
|
// a, b: two ring data objects (from getPathMetadata);
|
|
7814
7825
|
function testRingInRing(a, b, arcs) {
|
|
7815
7826
|
if (b.bounds.contains(a.bounds) === false) return false;
|
|
7816
|
-
|
|
7827
|
+
// Don't test with first point -- this may return false if a hole intersects
|
|
7828
|
+
// the containing ring at the first vertex.
|
|
7829
|
+
// Instead, use the midpoint of the first segment
|
|
7830
|
+
var p = getFirstMidpoint(a.ids[0], arcs);
|
|
7831
|
+
//// test with first point in the ring
|
|
7832
|
+
// var p = arcs.getVertex(a.ids[0], 0);
|
|
7817
7833
|
return geom.testPointInRing(p.x, p.y, b.ids, arcs) == 1;
|
|
7818
7834
|
}
|
|
7819
7835
|
|
|
7836
|
+
function getFirstMidpoint(arcId, arcs) {
|
|
7837
|
+
var p1 = arcs.getVertex(arcId, 0);
|
|
7838
|
+
var p2 = arcs.getVertex(arcId, 1);
|
|
7839
|
+
return {
|
|
7840
|
+
x: (p1.x + p2.x) / 2,
|
|
7841
|
+
y: (p1.y + p2.y) / 2
|
|
7842
|
+
};
|
|
7843
|
+
}
|
|
7844
|
+
|
|
7820
7845
|
// Bundle holes with their containing rings for Topo/GeoJSON polygon export.
|
|
7821
7846
|
// Assumes outer rings are CW and inner (hole) rings are CCW, unless
|
|
7822
7847
|
// the reverseWinding flag is set.
|
|
@@ -9525,9 +9550,6 @@
|
|
|
9525
9550
|
return rec && (rec[name] === val);
|
|
9526
9551
|
});
|
|
9527
9552
|
};
|
|
9528
|
-
obj.file_exists = function(name) {
|
|
9529
|
-
return cli.isFile(name);
|
|
9530
|
-
};
|
|
9531
9553
|
return obj;
|
|
9532
9554
|
}
|
|
9533
9555
|
|
|
@@ -9935,6 +9957,11 @@
|
|
|
9935
9957
|
ctx.$ = i >= 0 ? getFeatureById(i) : layerOnlyProxy;
|
|
9936
9958
|
ctx._ = ctx; // provide access to functions when masked by variable names
|
|
9937
9959
|
ctx.d = rec || null; // expose data properties a la d3 (also exposed as this.properties)
|
|
9960
|
+
if (opts.record_alias) {
|
|
9961
|
+
// this is used to expose source table record as "source" in -join calc=
|
|
9962
|
+
// expresions.
|
|
9963
|
+
ctx[opts.record_alias] = ctx.d;
|
|
9964
|
+
}
|
|
9938
9965
|
try {
|
|
9939
9966
|
val = func.call(ctx.$, rec, ctx);
|
|
9940
9967
|
} catch(e) {
|
|
@@ -18954,6 +18981,10 @@ ${svg}
|
|
|
18954
18981
|
.option('json-path', {
|
|
18955
18982
|
old_alias: 'json-subtree',
|
|
18956
18983
|
describe: '[JSON] path to JSON input data; separator is /'
|
|
18984
|
+
})
|
|
18985
|
+
.option('single-part', {
|
|
18986
|
+
type: 'flag',
|
|
18987
|
+
// describe: '[GeoJSON] split multi-part features into single-part features'
|
|
18957
18988
|
});
|
|
18958
18989
|
|
|
18959
18990
|
parser.command('o')
|
|
@@ -22119,6 +22150,8 @@ ${svg}
|
|
|
22119
22150
|
// TODO: improve so geometry_type option skips features instead of creating null geometries
|
|
22120
22151
|
if (geom && geom.type == 'GeometryCollection') {
|
|
22121
22152
|
GeoJSON.importComplexFeature(importer, geom, rec, opts);
|
|
22153
|
+
} else if (opts.single_part && isMultiPartGeometry(geom)) {
|
|
22154
|
+
GeoJSON.importMultiAsSingles(importer, geom, rec, opts);
|
|
22122
22155
|
} else {
|
|
22123
22156
|
GeoJSON.importSimpleFeature(importer, geom, rec, opts);
|
|
22124
22157
|
}
|
|
@@ -22160,11 +22193,27 @@ ${svg}
|
|
|
22160
22193
|
return Object.values(index);
|
|
22161
22194
|
}
|
|
22162
22195
|
|
|
22196
|
+
function isMultiPartGeometry(geom) {
|
|
22197
|
+
return geom && geom.type && geom.type.indexOf('Multi') === 0;
|
|
22198
|
+
}
|
|
22199
|
+
|
|
22163
22200
|
GeoJSON.importSimpleFeature = function(importer, geom, rec, opts) {
|
|
22164
22201
|
importer.startShape(rec);
|
|
22165
22202
|
GeoJSON.importSimpleGeometry(importer, geom, opts);
|
|
22166
22203
|
};
|
|
22167
22204
|
|
|
22205
|
+
// Split a multi-part feature into several single features
|
|
22206
|
+
GeoJSON.importMultiAsSingles = function(importer, geom, rec, opts) {
|
|
22207
|
+
geom.coordinates.forEach(function(coords, i) {
|
|
22208
|
+
var geom2 = {
|
|
22209
|
+
type: geom.type.substr(5),
|
|
22210
|
+
coordinates: coords
|
|
22211
|
+
};
|
|
22212
|
+
var rec2 = i === 0 ? rec : copyRecord(rec);
|
|
22213
|
+
GeoJSON.importSimpleFeature(importer, geom2, rec2, opts);
|
|
22214
|
+
});
|
|
22215
|
+
};
|
|
22216
|
+
|
|
22168
22217
|
GeoJSON.importSimpleGeometry = function(importer, geom, opts) {
|
|
22169
22218
|
var type = geom ? geom.type : null;
|
|
22170
22219
|
if (type === null) {
|
|
@@ -34614,19 +34663,33 @@ ${svg}
|
|
|
34614
34663
|
return o;
|
|
34615
34664
|
}
|
|
34616
34665
|
|
|
34617
|
-
function
|
|
34618
|
-
var
|
|
34666
|
+
function compileIfCommandExpression(expr, catalog, target, opts) {
|
|
34667
|
+
var ctx = {};
|
|
34668
|
+
|
|
34669
|
+
if (target && target.layer) {
|
|
34670
|
+
ctx = getLayerProxy(target.layer, target.dataset.arcs, opts);
|
|
34671
|
+
}
|
|
34672
|
+
|
|
34673
|
+
ctx.file_exists = function(name) {
|
|
34674
|
+
return cli.isFile(name);
|
|
34675
|
+
};
|
|
34676
|
+
|
|
34677
|
+
ctx.layer_exists = function(name) {
|
|
34678
|
+
var lyr = catalog.findSingleLayer(name);
|
|
34679
|
+
return !!lyr;
|
|
34680
|
+
};
|
|
34681
|
+
|
|
34619
34682
|
var exprOpts = Object.assign({returns: true}, opts);
|
|
34620
34683
|
var func = compileExpressionToFunction(expr, exprOpts);
|
|
34621
|
-
var ctx = proxy;
|
|
34622
34684
|
return function() {
|
|
34623
34685
|
try {
|
|
34624
|
-
return func.call(
|
|
34686
|
+
return func.call(ctx, {}, ctx);
|
|
34625
34687
|
} catch(e) {
|
|
34626
34688
|
// if (opts.quiet) throw e;
|
|
34627
34689
|
stop(e.name, "in expression [" + expr + "]:", e.message);
|
|
34628
34690
|
}
|
|
34629
34691
|
};
|
|
34692
|
+
|
|
34630
34693
|
}
|
|
34631
34694
|
|
|
34632
34695
|
function skipCommand(cmdName) {
|
|
@@ -34674,7 +34737,7 @@ ${svg}
|
|
|
34674
34737
|
function testLayer(catalog, opts) {
|
|
34675
34738
|
var targ = getTargetLayer(catalog, opts);
|
|
34676
34739
|
if (opts.expression) {
|
|
34677
|
-
return
|
|
34740
|
+
return compileIfCommandExpression(opts.expression, catalog, targ, opts)();
|
|
34678
34741
|
}
|
|
34679
34742
|
if (opts.empty) {
|
|
34680
34743
|
return layerIsEmpty(targ.layer);
|
package/package.json
CHANGED
package/www/mapshaper-gui.js
CHANGED
|
@@ -6442,10 +6442,13 @@
|
|
|
6442
6442
|
|
|
6443
6443
|
function CoordinatesDisplay(gui, ext, mouse) {
|
|
6444
6444
|
var readout = gui.container.findChild('.coordinate-info').hide();
|
|
6445
|
-
var enabled = false;
|
|
6446
6445
|
|
|
6447
|
-
|
|
6448
|
-
|
|
6446
|
+
function enabled() {
|
|
6447
|
+
var lyr = gui.map.getActiveLayer();
|
|
6448
|
+
return !!(lyr && lyr.layer.geometry_type);
|
|
6449
|
+
}
|
|
6450
|
+
|
|
6451
|
+
gui.model.on('update', function(e) {
|
|
6449
6452
|
readout.hide();
|
|
6450
6453
|
});
|
|
6451
6454
|
|
|
@@ -6466,7 +6469,7 @@
|
|
|
6466
6469
|
mouse.on('leave', clearCoords);
|
|
6467
6470
|
|
|
6468
6471
|
mouse.on('click', function(e) {
|
|
6469
|
-
if (!enabled) return;
|
|
6472
|
+
if (!enabled()) return;
|
|
6470
6473
|
GUI.selectElement(readout.node());
|
|
6471
6474
|
});
|
|
6472
6475
|
|
|
@@ -6474,7 +6477,7 @@
|
|
|
6474
6477
|
mouse.on('drag', onMouseChange, null, 10); // high priority so editor doesn't block propagation
|
|
6475
6478
|
|
|
6476
6479
|
function onMouseChange(e) {
|
|
6477
|
-
if (!enabled) return;
|
|
6480
|
+
if (!enabled()) return;
|
|
6478
6481
|
if (isOverMap(e)) {
|
|
6479
6482
|
displayCoords(gui.map.translatePixelCoords(e.x, e.y));
|
|
6480
6483
|
} else {
|
|
@@ -6998,6 +7001,15 @@
|
|
|
6998
7001
|
ext.zoomByPct(delta, e.x / ext.width(), e.y / ext.height());
|
|
6999
7002
|
});
|
|
7000
7003
|
|
|
7004
|
+
function fixBounds(bbox) {
|
|
7005
|
+
if (bbox[0] > bbox[2]) {
|
|
7006
|
+
swapElements(bbox, 0, 2);
|
|
7007
|
+
}
|
|
7008
|
+
if (bbox[1] > bbox[3]) {
|
|
7009
|
+
swapElements(bbox, 1, 3);
|
|
7010
|
+
}
|
|
7011
|
+
}
|
|
7012
|
+
|
|
7001
7013
|
function swapElements(arr, i, j) {
|
|
7002
7014
|
var tmp = arr[i];
|
|
7003
7015
|
arr[i] = arr[j];
|
|
@@ -7007,21 +7019,28 @@
|
|
|
7007
7019
|
function getBoxData(e) {
|
|
7008
7020
|
var pageBox = [e.pageX, e.pageY, dragStartEvt.pageX, dragStartEvt.pageY];
|
|
7009
7021
|
var mapBox = [e.x, e.y, dragStartEvt.x, dragStartEvt.y];
|
|
7010
|
-
var
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
swapElements(pageBox, 1, 3);
|
|
7017
|
-
swapElements(mapBox, 1, 3);
|
|
7018
|
-
}
|
|
7022
|
+
var displayBox = pixToCoords(mapBox);
|
|
7023
|
+
var dataBox = getBBoxCoords(gui.map.getActiveLayer(), displayBox);
|
|
7024
|
+
fixBounds(pageBox);
|
|
7025
|
+
fixBounds(mapBox);
|
|
7026
|
+
fixBounds(displayBox);
|
|
7027
|
+
fixBounds(dataBox);
|
|
7019
7028
|
return {
|
|
7020
7029
|
map_bbox: mapBox,
|
|
7021
|
-
page_bbox: pageBox
|
|
7030
|
+
page_bbox: pageBox,
|
|
7031
|
+
// round coords, for nicer 'info' display
|
|
7032
|
+
// (rounded precision should be sub-pixel)
|
|
7033
|
+
map_display_bbox: internal.getRoundedCoords(displayBox, internal.getBoundsPrecisionForDisplay(displayBox)),
|
|
7034
|
+
map_data_bbox: internal.getRoundedCoords(dataBox, internal.getBoundsPrecisionForDisplay(dataBox))
|
|
7022
7035
|
};
|
|
7023
7036
|
}
|
|
7024
7037
|
|
|
7038
|
+
function pixToCoords(bbox) {
|
|
7039
|
+
var a = ext.translatePixelCoords(bbox[0], bbox[1]);
|
|
7040
|
+
var b = ext.translatePixelCoords(bbox[2], bbox[3]);
|
|
7041
|
+
return [a[0], b[1], b[0], a[1]];
|
|
7042
|
+
}
|
|
7043
|
+
|
|
7025
7044
|
function disabled() {
|
|
7026
7045
|
return !!gui.options.disableNavigation;
|
|
7027
7046
|
}
|
|
@@ -7104,17 +7123,16 @@
|
|
|
7104
7123
|
if (!_on) return;
|
|
7105
7124
|
var b = e.page_bbox;
|
|
7106
7125
|
box.show(b[0], b[1], b[2], b[3]);
|
|
7107
|
-
updateSelection(e.
|
|
7126
|
+
updateSelection(e.map_data_bbox, true);
|
|
7108
7127
|
});
|
|
7109
7128
|
|
|
7110
7129
|
gui.on('box_drag_end', function(e) {
|
|
7111
7130
|
if (!_on) return;
|
|
7112
7131
|
box.hide();
|
|
7113
|
-
updateSelection(e.
|
|
7132
|
+
updateSelection(e.map_data_bbox);
|
|
7114
7133
|
});
|
|
7115
7134
|
|
|
7116
|
-
function updateSelection(
|
|
7117
|
-
var bbox = bboxToCoords(bboxPixels);
|
|
7135
|
+
function updateSelection(bbox, transient) {
|
|
7118
7136
|
var active = gui.model.getActiveLayer();
|
|
7119
7137
|
var ids = internal.findShapesIntersectingBBox(bbox, active.layer, active.dataset.arcs);
|
|
7120
7138
|
if (transient) {
|
|
@@ -7128,12 +7146,6 @@
|
|
|
7128
7146
|
_on = true;
|
|
7129
7147
|
}
|
|
7130
7148
|
|
|
7131
|
-
function bboxToCoords(bbox) {
|
|
7132
|
-
var a = ext.translatePixelCoords(bbox[0], bbox[1]);
|
|
7133
|
-
var b = ext.translatePixelCoords(bbox[2], bbox[3]);
|
|
7134
|
-
return [a[0], b[1], b[0], a[1]];
|
|
7135
|
-
}
|
|
7136
|
-
|
|
7137
7149
|
function turnOff() {
|
|
7138
7150
|
reset();
|
|
7139
7151
|
_on = false;
|
|
@@ -8386,24 +8398,32 @@
|
|
|
8386
8398
|
function recenter(cx, cy, scale, data) {
|
|
8387
8399
|
scale = scale ? limitScale(scale) : _scale;
|
|
8388
8400
|
if (cx == _cx && cy == _cy && scale == _scale) return;
|
|
8401
|
+
navigate(cx, cy, scale);
|
|
8402
|
+
onChange(data);
|
|
8403
|
+
}
|
|
8404
|
+
|
|
8405
|
+
function navigate(cx, cy, scale) {
|
|
8389
8406
|
if (_strictBounds) {
|
|
8390
|
-
|
|
8407
|
+
var full = fillOut(_contentBounds);
|
|
8408
|
+
var minScale = full.height() / _strictBounds.height();
|
|
8409
|
+
if (scale < minScale) {
|
|
8410
|
+
var dx = cx - _cx;
|
|
8411
|
+
cx = _cx + dx * (minScale - _scale) / (scale - _scale);
|
|
8412
|
+
scale = minScale;
|
|
8413
|
+
}
|
|
8414
|
+
var dist = full.height() / 2 / scale;
|
|
8415
|
+
var ymax = _strictBounds.ymax - dist;
|
|
8416
|
+
var ymin = _strictBounds.ymin + dist;
|
|
8417
|
+
if (cy > ymax ) {
|
|
8418
|
+
cy = ymax;
|
|
8419
|
+
}
|
|
8420
|
+
if (cy < ymin) {
|
|
8421
|
+
cy = ymin;
|
|
8422
|
+
}
|
|
8391
8423
|
}
|
|
8392
8424
|
_cx = cx;
|
|
8393
8425
|
_cy = cy;
|
|
8394
8426
|
_scale = scale;
|
|
8395
|
-
limitExtent();
|
|
8396
|
-
onChange(data);
|
|
8397
|
-
}
|
|
8398
|
-
|
|
8399
|
-
function limitExtent() {
|
|
8400
|
-
if (!_strictBounds) return;
|
|
8401
|
-
if (_scale < 1) _scale = 1;
|
|
8402
|
-
var dist = _strictBounds.height() / 2 / _scale;
|
|
8403
|
-
var ymax = _strictBounds.ymax - dist;
|
|
8404
|
-
var ymin = _strictBounds.ymin + dist;
|
|
8405
|
-
if (_cy > ymax) _cy = ymax;
|
|
8406
|
-
if (_cy < ymin) _cy = ymin;
|
|
8407
8427
|
}
|
|
8408
8428
|
|
|
8409
8429
|
function onChange(data) {
|
|
@@ -8473,7 +8493,6 @@
|
|
|
8473
8493
|
function fitIn(b, b2) {
|
|
8474
8494
|
// only fitting vertical extent
|
|
8475
8495
|
// (currently only used in basemap view to enforce Mapbox's vertical limits)
|
|
8476
|
-
|
|
8477
8496
|
if (b.height() > b2.height()) {
|
|
8478
8497
|
b.scale(b2.height() / b.height());
|
|
8479
8498
|
}
|
|
@@ -9330,7 +9349,7 @@
|
|
|
9330
9349
|
var popup = gui.container.findChild('.box-tool-options');
|
|
9331
9350
|
var coords = popup.findChild('.box-coords');
|
|
9332
9351
|
var _on = false;
|
|
9333
|
-
var
|
|
9352
|
+
var bboxData;
|
|
9334
9353
|
|
|
9335
9354
|
var infoBtn = new SimpleButton(popup.findChild('.info-btn')).on('click', function() {
|
|
9336
9355
|
if (coords.visible()) hideCoords(); else showCoords();
|
|
@@ -9357,11 +9376,11 @@
|
|
|
9357
9376
|
gui.enterMode('selection_tool');
|
|
9358
9377
|
gui.interaction.setMode('selection');
|
|
9359
9378
|
// kludge to pass bbox to the selection tool
|
|
9360
|
-
gui.dispatchEvent('box_drag_end',
|
|
9379
|
+
gui.dispatchEvent('box_drag_end', bboxData);
|
|
9361
9380
|
});
|
|
9362
9381
|
|
|
9363
9382
|
new SimpleButton(popup.findChild('.clip-btn')).on('click', function() {
|
|
9364
|
-
runCommand('-clip
|
|
9383
|
+
runCommand('-clip bbox=' + bboxData.map_data_bbox.join(','));
|
|
9365
9384
|
});
|
|
9366
9385
|
|
|
9367
9386
|
gui.addMode('box_tool', turnOn, turnOff);
|
|
@@ -9377,8 +9396,8 @@
|
|
|
9377
9396
|
// Update the visible rectangle when the map view changes
|
|
9378
9397
|
// (e.g. during zooming or panning)
|
|
9379
9398
|
ext.on('change', function() {
|
|
9380
|
-
if (!_on || !box.visible() || !
|
|
9381
|
-
var b = coordsToPix(
|
|
9399
|
+
if (!_on || !box.visible() || !bboxData) return;
|
|
9400
|
+
var b = coordsToPix(bboxData.map_display_bbox);
|
|
9382
9401
|
var pos = ext.position();
|
|
9383
9402
|
var dx = pos.pageX,
|
|
9384
9403
|
dy = pos.pageY;
|
|
@@ -9392,20 +9411,17 @@
|
|
|
9392
9411
|
|
|
9393
9412
|
gui.on('box_drag', function(e) {
|
|
9394
9413
|
var b = e.page_bbox;
|
|
9395
|
-
|
|
9396
|
-
bboxDisplayCoords = pixToCoords(bboxPixels);
|
|
9414
|
+
bboxData = e.data;
|
|
9397
9415
|
if (_on || inZoomMode()) {
|
|
9398
9416
|
box.show(b[0], b[1], b[2], b[3]);
|
|
9399
9417
|
}
|
|
9400
9418
|
});
|
|
9401
9419
|
|
|
9402
9420
|
gui.on('box_drag_end', function(e) {
|
|
9403
|
-
|
|
9404
|
-
bboxDisplayCoords = pixToCoords(bboxPixels);
|
|
9405
|
-
bboxDataCoords = getBBoxCoords(gui.map.getActiveLayer(), bboxDisplayCoords);
|
|
9421
|
+
bboxData = e.data;
|
|
9406
9422
|
if (inZoomMode()) {
|
|
9407
9423
|
box.hide();
|
|
9408
|
-
nav.zoomToBbox(
|
|
9424
|
+
nav.zoomToBbox(e.map_bbox);
|
|
9409
9425
|
} else if (_on) {
|
|
9410
9426
|
popup.show();
|
|
9411
9427
|
}
|
|
@@ -9426,7 +9442,7 @@
|
|
|
9426
9442
|
|
|
9427
9443
|
function showCoords() {
|
|
9428
9444
|
El(infoBtn.node()).addClass('selected-btn');
|
|
9429
|
-
coords.text(
|
|
9445
|
+
coords.text(bboxData.map_data_bbox.join(','));
|
|
9430
9446
|
coords.show();
|
|
9431
9447
|
GUI.selectElement(coords.node());
|
|
9432
9448
|
}
|
|
@@ -9455,15 +9471,6 @@
|
|
|
9455
9471
|
hideCoords();
|
|
9456
9472
|
}
|
|
9457
9473
|
|
|
9458
|
-
function pixToCoords(bbox) {
|
|
9459
|
-
var a = ext.translatePixelCoords(bbox[0], bbox[1]);
|
|
9460
|
-
var b = ext.translatePixelCoords(bbox[2], bbox[3]);
|
|
9461
|
-
var bbox2 = [a[0], b[1], b[0], a[1]];
|
|
9462
|
-
// round coords, for nicer 'info' display
|
|
9463
|
-
// (rounded precision should be sub-pixel)
|
|
9464
|
-
return internal.getRoundedCoords(bbox2, internal.getBoundsPrecisionForDisplay(bbox2));
|
|
9465
|
-
}
|
|
9466
|
-
|
|
9467
9474
|
function coordsToPix(bbox) {
|
|
9468
9475
|
var a = ext.translateCoords(bbox[0], bbox[1]);
|
|
9469
9476
|
var b = ext.translateCoords(bbox[2], bbox[3]);
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.5.
|
|
3
|
+
var VERSION = "0.5.103";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -1737,6 +1737,16 @@
|
|
|
1737
1737
|
|
|
1738
1738
|
// Iterate over each [x,y] point in a layer
|
|
1739
1739
|
// shapes: one layer's "shapes" array
|
|
1740
|
+
function forEachPoint_(shapes, cb) {
|
|
1741
|
+
var i, n, j, m, shp;
|
|
1742
|
+
for (i=0, n=shapes.length; i<n; i++) {
|
|
1743
|
+
shp = shapes[i];
|
|
1744
|
+
for (j=0, m=shp ? shp.length : 0; j<m; j++) {
|
|
1745
|
+
cb(shp[j], i);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1740
1750
|
function forEachPoint(shapes, cb) {
|
|
1741
1751
|
var i, n, j, m, shp;
|
|
1742
1752
|
for (i=0, n=shapes.length; i<n; i++) {
|
|
@@ -1753,6 +1763,7 @@
|
|
|
1753
1763
|
getPointBounds: getPointBounds$1,
|
|
1754
1764
|
getPointFeatureBounds: getPointFeatureBounds,
|
|
1755
1765
|
getPointsInLayer: getPointsInLayer,
|
|
1766
|
+
forEachPoint_: forEachPoint_,
|
|
1756
1767
|
forEachPoint: forEachPoint
|
|
1757
1768
|
});
|
|
1758
1769
|
|
|
@@ -7813,10 +7824,24 @@
|
|
|
7813
7824
|
// a, b: two ring data objects (from getPathMetadata);
|
|
7814
7825
|
function testRingInRing(a, b, arcs) {
|
|
7815
7826
|
if (b.bounds.contains(a.bounds) === false) return false;
|
|
7816
|
-
|
|
7827
|
+
// Don't test with first point -- this may return false if a hole intersects
|
|
7828
|
+
// the containing ring at the first vertex.
|
|
7829
|
+
// Instead, use the midpoint of the first segment
|
|
7830
|
+
var p = getFirstMidpoint(a.ids[0], arcs);
|
|
7831
|
+
//// test with first point in the ring
|
|
7832
|
+
// var p = arcs.getVertex(a.ids[0], 0);
|
|
7817
7833
|
return geom.testPointInRing(p.x, p.y, b.ids, arcs) == 1;
|
|
7818
7834
|
}
|
|
7819
7835
|
|
|
7836
|
+
function getFirstMidpoint(arcId, arcs) {
|
|
7837
|
+
var p1 = arcs.getVertex(arcId, 0);
|
|
7838
|
+
var p2 = arcs.getVertex(arcId, 1);
|
|
7839
|
+
return {
|
|
7840
|
+
x: (p1.x + p2.x) / 2,
|
|
7841
|
+
y: (p1.y + p2.y) / 2
|
|
7842
|
+
};
|
|
7843
|
+
}
|
|
7844
|
+
|
|
7820
7845
|
// Bundle holes with their containing rings for Topo/GeoJSON polygon export.
|
|
7821
7846
|
// Assumes outer rings are CW and inner (hole) rings are CCW, unless
|
|
7822
7847
|
// the reverseWinding flag is set.
|
|
@@ -9525,9 +9550,6 @@
|
|
|
9525
9550
|
return rec && (rec[name] === val);
|
|
9526
9551
|
});
|
|
9527
9552
|
};
|
|
9528
|
-
obj.file_exists = function(name) {
|
|
9529
|
-
return cli.isFile(name);
|
|
9530
|
-
};
|
|
9531
9553
|
return obj;
|
|
9532
9554
|
}
|
|
9533
9555
|
|
|
@@ -9935,6 +9957,11 @@
|
|
|
9935
9957
|
ctx.$ = i >= 0 ? getFeatureById(i) : layerOnlyProxy;
|
|
9936
9958
|
ctx._ = ctx; // provide access to functions when masked by variable names
|
|
9937
9959
|
ctx.d = rec || null; // expose data properties a la d3 (also exposed as this.properties)
|
|
9960
|
+
if (opts.record_alias) {
|
|
9961
|
+
// this is used to expose source table record as "source" in -join calc=
|
|
9962
|
+
// expresions.
|
|
9963
|
+
ctx[opts.record_alias] = ctx.d;
|
|
9964
|
+
}
|
|
9938
9965
|
try {
|
|
9939
9966
|
val = func.call(ctx.$, rec, ctx);
|
|
9940
9967
|
} catch(e) {
|
|
@@ -18954,6 +18981,10 @@ ${svg}
|
|
|
18954
18981
|
.option('json-path', {
|
|
18955
18982
|
old_alias: 'json-subtree',
|
|
18956
18983
|
describe: '[JSON] path to JSON input data; separator is /'
|
|
18984
|
+
})
|
|
18985
|
+
.option('single-part', {
|
|
18986
|
+
type: 'flag',
|
|
18987
|
+
// describe: '[GeoJSON] split multi-part features into single-part features'
|
|
18957
18988
|
});
|
|
18958
18989
|
|
|
18959
18990
|
parser.command('o')
|
|
@@ -22119,6 +22150,8 @@ ${svg}
|
|
|
22119
22150
|
// TODO: improve so geometry_type option skips features instead of creating null geometries
|
|
22120
22151
|
if (geom && geom.type == 'GeometryCollection') {
|
|
22121
22152
|
GeoJSON.importComplexFeature(importer, geom, rec, opts);
|
|
22153
|
+
} else if (opts.single_part && isMultiPartGeometry(geom)) {
|
|
22154
|
+
GeoJSON.importMultiAsSingles(importer, geom, rec, opts);
|
|
22122
22155
|
} else {
|
|
22123
22156
|
GeoJSON.importSimpleFeature(importer, geom, rec, opts);
|
|
22124
22157
|
}
|
|
@@ -22160,11 +22193,27 @@ ${svg}
|
|
|
22160
22193
|
return Object.values(index);
|
|
22161
22194
|
}
|
|
22162
22195
|
|
|
22196
|
+
function isMultiPartGeometry(geom) {
|
|
22197
|
+
return geom && geom.type && geom.type.indexOf('Multi') === 0;
|
|
22198
|
+
}
|
|
22199
|
+
|
|
22163
22200
|
GeoJSON.importSimpleFeature = function(importer, geom, rec, opts) {
|
|
22164
22201
|
importer.startShape(rec);
|
|
22165
22202
|
GeoJSON.importSimpleGeometry(importer, geom, opts);
|
|
22166
22203
|
};
|
|
22167
22204
|
|
|
22205
|
+
// Split a multi-part feature into several single features
|
|
22206
|
+
GeoJSON.importMultiAsSingles = function(importer, geom, rec, opts) {
|
|
22207
|
+
geom.coordinates.forEach(function(coords, i) {
|
|
22208
|
+
var geom2 = {
|
|
22209
|
+
type: geom.type.substr(5),
|
|
22210
|
+
coordinates: coords
|
|
22211
|
+
};
|
|
22212
|
+
var rec2 = i === 0 ? rec : copyRecord(rec);
|
|
22213
|
+
GeoJSON.importSimpleFeature(importer, geom2, rec2, opts);
|
|
22214
|
+
});
|
|
22215
|
+
};
|
|
22216
|
+
|
|
22168
22217
|
GeoJSON.importSimpleGeometry = function(importer, geom, opts) {
|
|
22169
22218
|
var type = geom ? geom.type : null;
|
|
22170
22219
|
if (type === null) {
|
|
@@ -34614,19 +34663,33 @@ ${svg}
|
|
|
34614
34663
|
return o;
|
|
34615
34664
|
}
|
|
34616
34665
|
|
|
34617
|
-
function
|
|
34618
|
-
var
|
|
34666
|
+
function compileIfCommandExpression(expr, catalog, target, opts) {
|
|
34667
|
+
var ctx = {};
|
|
34668
|
+
|
|
34669
|
+
if (target && target.layer) {
|
|
34670
|
+
ctx = getLayerProxy(target.layer, target.dataset.arcs, opts);
|
|
34671
|
+
}
|
|
34672
|
+
|
|
34673
|
+
ctx.file_exists = function(name) {
|
|
34674
|
+
return cli.isFile(name);
|
|
34675
|
+
};
|
|
34676
|
+
|
|
34677
|
+
ctx.layer_exists = function(name) {
|
|
34678
|
+
var lyr = catalog.findSingleLayer(name);
|
|
34679
|
+
return !!lyr;
|
|
34680
|
+
};
|
|
34681
|
+
|
|
34619
34682
|
var exprOpts = Object.assign({returns: true}, opts);
|
|
34620
34683
|
var func = compileExpressionToFunction(expr, exprOpts);
|
|
34621
|
-
var ctx = proxy;
|
|
34622
34684
|
return function() {
|
|
34623
34685
|
try {
|
|
34624
|
-
return func.call(
|
|
34686
|
+
return func.call(ctx, {}, ctx);
|
|
34625
34687
|
} catch(e) {
|
|
34626
34688
|
// if (opts.quiet) throw e;
|
|
34627
34689
|
stop(e.name, "in expression [" + expr + "]:", e.message);
|
|
34628
34690
|
}
|
|
34629
34691
|
};
|
|
34692
|
+
|
|
34630
34693
|
}
|
|
34631
34694
|
|
|
34632
34695
|
function skipCommand(cmdName) {
|
|
@@ -34674,7 +34737,7 @@ ${svg}
|
|
|
34674
34737
|
function testLayer(catalog, opts) {
|
|
34675
34738
|
var targ = getTargetLayer(catalog, opts);
|
|
34676
34739
|
if (opts.expression) {
|
|
34677
|
-
return
|
|
34740
|
+
return compileIfCommandExpression(opts.expression, catalog, targ, opts)();
|
|
34678
34741
|
}
|
|
34679
34742
|
if (opts.empty) {
|
|
34680
34743
|
return layerIsEmpty(targ.layer);
|
package/www/page.css
CHANGED
|
@@ -210,7 +210,7 @@ body {
|
|
|
210
210
|
max-height: 160px;
|
|
211
211
|
overflow: hidden;
|
|
212
212
|
overflow-y: auto;
|
|
213
|
-
margin-right: -
|
|
213
|
+
margin-right: -3px;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
.export-layer-list > div {
|
|
@@ -420,8 +420,8 @@ body.dragover #import-options-drop-area .drop-area {
|
|
|
420
420
|
background: rgba(255, 255, 255, 0.4);
|
|
421
421
|
border: 1px solid #999;
|
|
422
422
|
padding: 0 3px;
|
|
423
|
-
height:
|
|
424
|
-
font-size:
|
|
423
|
+
height: 18px;
|
|
424
|
+
font-size: 13px;
|
|
425
425
|
}
|
|
426
426
|
|
|
427
427
|
#mshp-not-supported {
|
|
@@ -436,10 +436,10 @@ body.dragover #import-options-drop-area .drop-area {
|
|
|
436
436
|
overflow-y: auto;
|
|
437
437
|
}
|
|
438
438
|
|
|
439
|
-
.dropped-file-list p {
|
|
439
|
+
#import-options .dropped-file-list p {
|
|
440
440
|
line-height: 1;
|
|
441
441
|
margin-bottom: 5px;
|
|
442
|
-
font-size:
|
|
442
|
+
font-size: 14px;
|
|
443
443
|
font-weight: bold;
|
|
444
444
|
}
|
|
445
445
|
|
|
@@ -484,7 +484,7 @@ body.dragover #import-options-drop-area .drop-area {
|
|
|
484
484
|
}
|
|
485
485
|
|
|
486
486
|
.option-menu {
|
|
487
|
-
padding: 0 0
|
|
487
|
+
padding: 0 0 9px 0;
|
|
488
488
|
}
|
|
489
489
|
|
|
490
490
|
.option-menu input {
|