mapshaper 0.5.106 → 0.5.109
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 +7 -0
- package/mapshaper.js +52 -11
- package/package.json +1 -1
- package/www/mapshaper-gui.js +22 -14
- package/www/mapshaper.js +52 -11
- 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.109";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -7813,10 +7813,24 @@
|
|
|
7813
7813
|
// a, b: two ring data objects (from getPathMetadata);
|
|
7814
7814
|
function testRingInRing(a, b, arcs) {
|
|
7815
7815
|
if (b.bounds.contains(a.bounds) === false) return false;
|
|
7816
|
-
|
|
7816
|
+
// Don't test with first point -- this may return false if a hole intersects
|
|
7817
|
+
// the containing ring at the first vertex.
|
|
7818
|
+
// Instead, use the midpoint of the first segment
|
|
7819
|
+
var p = getFirstMidpoint(a.ids[0], arcs);
|
|
7820
|
+
//// test with first point in the ring
|
|
7821
|
+
// var p = arcs.getVertex(a.ids[0], 0);
|
|
7817
7822
|
return geom.testPointInRing(p.x, p.y, b.ids, arcs) == 1;
|
|
7818
7823
|
}
|
|
7819
7824
|
|
|
7825
|
+
function getFirstMidpoint(arcId, arcs) {
|
|
7826
|
+
var p1 = arcs.getVertex(arcId, 0);
|
|
7827
|
+
var p2 = arcs.getVertex(arcId, 1);
|
|
7828
|
+
return {
|
|
7829
|
+
x: (p1.x + p2.x) / 2,
|
|
7830
|
+
y: (p1.y + p2.y) / 2
|
|
7831
|
+
};
|
|
7832
|
+
}
|
|
7833
|
+
|
|
7820
7834
|
// Bundle holes with their containing rings for Topo/GeoJSON polygon export.
|
|
7821
7835
|
// Assumes outer rings are CW and inner (hole) rings are CCW, unless
|
|
7822
7836
|
// the reverseWinding flag is set.
|
|
@@ -9525,9 +9539,6 @@
|
|
|
9525
9539
|
return rec && (rec[name] === val);
|
|
9526
9540
|
});
|
|
9527
9541
|
};
|
|
9528
|
-
obj.file_exists = function(name) {
|
|
9529
|
-
return cli.isFile(name);
|
|
9530
|
-
};
|
|
9531
9542
|
return obj;
|
|
9532
9543
|
}
|
|
9533
9544
|
|
|
@@ -13923,7 +13934,7 @@
|
|
|
13923
13934
|
|
|
13924
13935
|
var propertiesBySymbolType = {
|
|
13925
13936
|
polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern')),
|
|
13926
|
-
polyline: utils.arrayToIndex(commonProperties),
|
|
13937
|
+
polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin')),
|
|
13927
13938
|
point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
|
|
13928
13939
|
label: utils.arrayToIndex(commonProperties.concat(
|
|
13929
13940
|
'fill,r,font-family,font-size,text-anchor,font-weight,font-style,letter-spacing,dominant-baseline'.split(',')))
|
|
@@ -18954,6 +18965,10 @@ ${svg}
|
|
|
18954
18965
|
.option('json-path', {
|
|
18955
18966
|
old_alias: 'json-subtree',
|
|
18956
18967
|
describe: '[JSON] path to JSON input data; separator is /'
|
|
18968
|
+
})
|
|
18969
|
+
.option('single-part', {
|
|
18970
|
+
type: 'flag',
|
|
18971
|
+
// describe: '[GeoJSON] split multi-part features into single-part features'
|
|
18957
18972
|
});
|
|
18958
18973
|
|
|
18959
18974
|
parser.command('o')
|
|
@@ -22119,6 +22134,8 @@ ${svg}
|
|
|
22119
22134
|
// TODO: improve so geometry_type option skips features instead of creating null geometries
|
|
22120
22135
|
if (geom && geom.type == 'GeometryCollection') {
|
|
22121
22136
|
GeoJSON.importComplexFeature(importer, geom, rec, opts);
|
|
22137
|
+
} else if (opts.single_part && isMultiPartGeometry(geom)) {
|
|
22138
|
+
GeoJSON.importMultiAsSingles(importer, geom, rec, opts);
|
|
22122
22139
|
} else {
|
|
22123
22140
|
GeoJSON.importSimpleFeature(importer, geom, rec, opts);
|
|
22124
22141
|
}
|
|
@@ -22160,11 +22177,27 @@ ${svg}
|
|
|
22160
22177
|
return Object.values(index);
|
|
22161
22178
|
}
|
|
22162
22179
|
|
|
22180
|
+
function isMultiPartGeometry(geom) {
|
|
22181
|
+
return geom && geom.type && geom.type.indexOf('Multi') === 0;
|
|
22182
|
+
}
|
|
22183
|
+
|
|
22163
22184
|
GeoJSON.importSimpleFeature = function(importer, geom, rec, opts) {
|
|
22164
22185
|
importer.startShape(rec);
|
|
22165
22186
|
GeoJSON.importSimpleGeometry(importer, geom, opts);
|
|
22166
22187
|
};
|
|
22167
22188
|
|
|
22189
|
+
// Split a multi-part feature into several single features
|
|
22190
|
+
GeoJSON.importMultiAsSingles = function(importer, geom, rec, opts) {
|
|
22191
|
+
geom.coordinates.forEach(function(coords, i) {
|
|
22192
|
+
var geom2 = {
|
|
22193
|
+
type: geom.type.substr(5),
|
|
22194
|
+
coordinates: coords
|
|
22195
|
+
};
|
|
22196
|
+
var rec2 = i === 0 ? rec : copyRecord(rec);
|
|
22197
|
+
GeoJSON.importSimpleFeature(importer, geom2, rec2, opts);
|
|
22198
|
+
});
|
|
22199
|
+
};
|
|
22200
|
+
|
|
22168
22201
|
GeoJSON.importSimpleGeometry = function(importer, geom, opts) {
|
|
22169
22202
|
var type = geom ? geom.type : null;
|
|
22170
22203
|
if (type === null) {
|
|
@@ -34614,14 +34647,22 @@ ${svg}
|
|
|
34614
34647
|
return o;
|
|
34615
34648
|
}
|
|
34616
34649
|
|
|
34617
|
-
function
|
|
34618
|
-
var
|
|
34650
|
+
function compileIfCommandExpression(expr, catalog, targ, opts) {
|
|
34651
|
+
var ctx = getLayerProxy(targ.layer, targ.dataset.arcs, opts);
|
|
34619
34652
|
var exprOpts = Object.assign({returns: true}, opts);
|
|
34620
34653
|
var func = compileExpressionToFunction(expr, exprOpts);
|
|
34621
|
-
|
|
34654
|
+
|
|
34655
|
+
ctx.layer_exists = function(name) {
|
|
34656
|
+
return !!catalog.findSingleLayer(name);
|
|
34657
|
+
};
|
|
34658
|
+
|
|
34659
|
+
ctx.file_exists = function(file) {
|
|
34660
|
+
return cli.isFile(file);
|
|
34661
|
+
};
|
|
34662
|
+
|
|
34622
34663
|
return function() {
|
|
34623
34664
|
try {
|
|
34624
|
-
return func.call(
|
|
34665
|
+
return func.call(ctx, {}, ctx);
|
|
34625
34666
|
} catch(e) {
|
|
34626
34667
|
// if (opts.quiet) throw e;
|
|
34627
34668
|
stop(e.name, "in expression [" + expr + "]:", e.message);
|
|
@@ -34674,7 +34715,7 @@ ${svg}
|
|
|
34674
34715
|
function testLayer(catalog, opts) {
|
|
34675
34716
|
var targ = getTargetLayer(catalog, opts);
|
|
34676
34717
|
if (opts.expression) {
|
|
34677
|
-
return
|
|
34718
|
+
return compileIfCommandExpression(opts.expression, catalog, targ, opts)();
|
|
34678
34719
|
}
|
|
34679
34720
|
if (opts.empty) {
|
|
34680
34721
|
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];
|
|
@@ -7009,14 +7021,10 @@
|
|
|
7009
7021
|
var mapBox = [e.x, e.y, dragStartEvt.x, dragStartEvt.y];
|
|
7010
7022
|
var displayBox = pixToCoords(mapBox);
|
|
7011
7023
|
var dataBox = getBBoxCoords(gui.map.getActiveLayer(), displayBox);
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
if (pageBox[1] > pageBox[3]) {
|
|
7017
|
-
swapElements(pageBox, 1, 3);
|
|
7018
|
-
swapElements(mapBox, 1, 3);
|
|
7019
|
-
}
|
|
7024
|
+
fixBounds(pageBox);
|
|
7025
|
+
fixBounds(mapBox);
|
|
7026
|
+
fixBounds(displayBox);
|
|
7027
|
+
fixBounds(dataBox);
|
|
7020
7028
|
return {
|
|
7021
7029
|
map_bbox: mapBox,
|
|
7022
7030
|
page_bbox: pageBox,
|
|
@@ -9372,7 +9380,7 @@
|
|
|
9372
9380
|
});
|
|
9373
9381
|
|
|
9374
9382
|
new SimpleButton(popup.findChild('.clip-btn')).on('click', function() {
|
|
9375
|
-
runCommand('-clip
|
|
9383
|
+
runCommand('-clip bbox=' + bboxData.map_data_bbox.join(','));
|
|
9376
9384
|
});
|
|
9377
9385
|
|
|
9378
9386
|
gui.addMode('box_tool', turnOn, turnOff);
|
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.5.
|
|
3
|
+
var VERSION = "0.5.109";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -7813,10 +7813,24 @@
|
|
|
7813
7813
|
// a, b: two ring data objects (from getPathMetadata);
|
|
7814
7814
|
function testRingInRing(a, b, arcs) {
|
|
7815
7815
|
if (b.bounds.contains(a.bounds) === false) return false;
|
|
7816
|
-
|
|
7816
|
+
// Don't test with first point -- this may return false if a hole intersects
|
|
7817
|
+
// the containing ring at the first vertex.
|
|
7818
|
+
// Instead, use the midpoint of the first segment
|
|
7819
|
+
var p = getFirstMidpoint(a.ids[0], arcs);
|
|
7820
|
+
//// test with first point in the ring
|
|
7821
|
+
// var p = arcs.getVertex(a.ids[0], 0);
|
|
7817
7822
|
return geom.testPointInRing(p.x, p.y, b.ids, arcs) == 1;
|
|
7818
7823
|
}
|
|
7819
7824
|
|
|
7825
|
+
function getFirstMidpoint(arcId, arcs) {
|
|
7826
|
+
var p1 = arcs.getVertex(arcId, 0);
|
|
7827
|
+
var p2 = arcs.getVertex(arcId, 1);
|
|
7828
|
+
return {
|
|
7829
|
+
x: (p1.x + p2.x) / 2,
|
|
7830
|
+
y: (p1.y + p2.y) / 2
|
|
7831
|
+
};
|
|
7832
|
+
}
|
|
7833
|
+
|
|
7820
7834
|
// Bundle holes with their containing rings for Topo/GeoJSON polygon export.
|
|
7821
7835
|
// Assumes outer rings are CW and inner (hole) rings are CCW, unless
|
|
7822
7836
|
// the reverseWinding flag is set.
|
|
@@ -9525,9 +9539,6 @@
|
|
|
9525
9539
|
return rec && (rec[name] === val);
|
|
9526
9540
|
});
|
|
9527
9541
|
};
|
|
9528
|
-
obj.file_exists = function(name) {
|
|
9529
|
-
return cli.isFile(name);
|
|
9530
|
-
};
|
|
9531
9542
|
return obj;
|
|
9532
9543
|
}
|
|
9533
9544
|
|
|
@@ -13923,7 +13934,7 @@
|
|
|
13923
13934
|
|
|
13924
13935
|
var propertiesBySymbolType = {
|
|
13925
13936
|
polygon: utils.arrayToIndex(commonProperties.concat('fill', 'fill-pattern')),
|
|
13926
|
-
polyline: utils.arrayToIndex(commonProperties),
|
|
13937
|
+
polyline: utils.arrayToIndex(commonProperties.concat('stroke-linecap', 'stroke-linejoin')),
|
|
13927
13938
|
point: utils.arrayToIndex(commonProperties.concat('fill', 'r')),
|
|
13928
13939
|
label: utils.arrayToIndex(commonProperties.concat(
|
|
13929
13940
|
'fill,r,font-family,font-size,text-anchor,font-weight,font-style,letter-spacing,dominant-baseline'.split(',')))
|
|
@@ -18954,6 +18965,10 @@ ${svg}
|
|
|
18954
18965
|
.option('json-path', {
|
|
18955
18966
|
old_alias: 'json-subtree',
|
|
18956
18967
|
describe: '[JSON] path to JSON input data; separator is /'
|
|
18968
|
+
})
|
|
18969
|
+
.option('single-part', {
|
|
18970
|
+
type: 'flag',
|
|
18971
|
+
// describe: '[GeoJSON] split multi-part features into single-part features'
|
|
18957
18972
|
});
|
|
18958
18973
|
|
|
18959
18974
|
parser.command('o')
|
|
@@ -22119,6 +22134,8 @@ ${svg}
|
|
|
22119
22134
|
// TODO: improve so geometry_type option skips features instead of creating null geometries
|
|
22120
22135
|
if (geom && geom.type == 'GeometryCollection') {
|
|
22121
22136
|
GeoJSON.importComplexFeature(importer, geom, rec, opts);
|
|
22137
|
+
} else if (opts.single_part && isMultiPartGeometry(geom)) {
|
|
22138
|
+
GeoJSON.importMultiAsSingles(importer, geom, rec, opts);
|
|
22122
22139
|
} else {
|
|
22123
22140
|
GeoJSON.importSimpleFeature(importer, geom, rec, opts);
|
|
22124
22141
|
}
|
|
@@ -22160,11 +22177,27 @@ ${svg}
|
|
|
22160
22177
|
return Object.values(index);
|
|
22161
22178
|
}
|
|
22162
22179
|
|
|
22180
|
+
function isMultiPartGeometry(geom) {
|
|
22181
|
+
return geom && geom.type && geom.type.indexOf('Multi') === 0;
|
|
22182
|
+
}
|
|
22183
|
+
|
|
22163
22184
|
GeoJSON.importSimpleFeature = function(importer, geom, rec, opts) {
|
|
22164
22185
|
importer.startShape(rec);
|
|
22165
22186
|
GeoJSON.importSimpleGeometry(importer, geom, opts);
|
|
22166
22187
|
};
|
|
22167
22188
|
|
|
22189
|
+
// Split a multi-part feature into several single features
|
|
22190
|
+
GeoJSON.importMultiAsSingles = function(importer, geom, rec, opts) {
|
|
22191
|
+
geom.coordinates.forEach(function(coords, i) {
|
|
22192
|
+
var geom2 = {
|
|
22193
|
+
type: geom.type.substr(5),
|
|
22194
|
+
coordinates: coords
|
|
22195
|
+
};
|
|
22196
|
+
var rec2 = i === 0 ? rec : copyRecord(rec);
|
|
22197
|
+
GeoJSON.importSimpleFeature(importer, geom2, rec2, opts);
|
|
22198
|
+
});
|
|
22199
|
+
};
|
|
22200
|
+
|
|
22168
22201
|
GeoJSON.importSimpleGeometry = function(importer, geom, opts) {
|
|
22169
22202
|
var type = geom ? geom.type : null;
|
|
22170
22203
|
if (type === null) {
|
|
@@ -34614,14 +34647,22 @@ ${svg}
|
|
|
34614
34647
|
return o;
|
|
34615
34648
|
}
|
|
34616
34649
|
|
|
34617
|
-
function
|
|
34618
|
-
var
|
|
34650
|
+
function compileIfCommandExpression(expr, catalog, targ, opts) {
|
|
34651
|
+
var ctx = getLayerProxy(targ.layer, targ.dataset.arcs, opts);
|
|
34619
34652
|
var exprOpts = Object.assign({returns: true}, opts);
|
|
34620
34653
|
var func = compileExpressionToFunction(expr, exprOpts);
|
|
34621
|
-
|
|
34654
|
+
|
|
34655
|
+
ctx.layer_exists = function(name) {
|
|
34656
|
+
return !!catalog.findSingleLayer(name);
|
|
34657
|
+
};
|
|
34658
|
+
|
|
34659
|
+
ctx.file_exists = function(file) {
|
|
34660
|
+
return cli.isFile(file);
|
|
34661
|
+
};
|
|
34662
|
+
|
|
34622
34663
|
return function() {
|
|
34623
34664
|
try {
|
|
34624
|
-
return func.call(
|
|
34665
|
+
return func.call(ctx, {}, ctx);
|
|
34625
34666
|
} catch(e) {
|
|
34626
34667
|
// if (opts.quiet) throw e;
|
|
34627
34668
|
stop(e.name, "in expression [" + expr + "]:", e.message);
|
|
@@ -34674,7 +34715,7 @@ ${svg}
|
|
|
34674
34715
|
function testLayer(catalog, opts) {
|
|
34675
34716
|
var targ = getTargetLayer(catalog, opts);
|
|
34676
34717
|
if (opts.expression) {
|
|
34677
|
-
return
|
|
34718
|
+
return compileIfCommandExpression(opts.expression, catalog, targ, opts)();
|
|
34678
34719
|
}
|
|
34679
34720
|
if (opts.empty) {
|
|
34680
34721
|
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 {
|