mapshaper 0.5.79 → 0.5.83
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 +13 -0
- package/mapshaper.js +853 -416
- package/package.json +1 -1
- package/www/mapshaper-gui.js +0 -1
- package/www/mapshaper.js +853 -416
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.5.
|
|
3
|
+
var VERSION = "0.5.79";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
get isFiniteNumber () { return isFiniteNumber; },
|
|
17
17
|
get isNonNegNumber () { return isNonNegNumber; },
|
|
18
18
|
get isInteger () { return isInteger; },
|
|
19
|
+
get isEven () { return isEven; },
|
|
20
|
+
get isOdd () { return isOdd; },
|
|
19
21
|
get isString () { return isString; },
|
|
20
22
|
get isDate () { return isDate; },
|
|
21
23
|
get isBoolean () { return isBoolean; },
|
|
@@ -149,6 +151,14 @@
|
|
|
149
151
|
return isNumber(obj) && ((obj | 0) === obj);
|
|
150
152
|
}
|
|
151
153
|
|
|
154
|
+
function isEven(obj) {
|
|
155
|
+
return (obj % 2) === 0;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function isOdd(obj) {
|
|
159
|
+
return (obj % 2) === 1;
|
|
160
|
+
}
|
|
161
|
+
|
|
152
162
|
function isString(obj) {
|
|
153
163
|
return obj != null && obj.toString === String.prototype.toString;
|
|
154
164
|
// TODO: replace w/ something better.
|
|
@@ -1745,9 +1755,17 @@
|
|
|
1745
1755
|
return [xmin, ymin, xmax, ymax];
|
|
1746
1756
|
}
|
|
1747
1757
|
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1758
|
+
var WGS84 = {
|
|
1759
|
+
// https://en.wikipedia.org/wiki/Earth_radius
|
|
1760
|
+
SEMIMAJOR_AXIS: 6378137,
|
|
1761
|
+
SEMIMINOR_AXIS: 6356752.3142,
|
|
1762
|
+
AUTHALIC_RADIUS: 6371007.2,
|
|
1763
|
+
VOLUMETRIC_RADIUS: 6371000.8
|
|
1764
|
+
};
|
|
1765
|
+
|
|
1766
|
+
// TODO: remove this constant, use actual data from dataset CRS,
|
|
1767
|
+
// also consider using ellipsoidal formulas where greater accuracy might be important.
|
|
1768
|
+
var R$1 = WGS84.SEMIMAJOR_AXIS;
|
|
1751
1769
|
var D2R = Math.PI / 180;
|
|
1752
1770
|
var R2D = 180 / Math.PI;
|
|
1753
1771
|
|
|
@@ -2342,15 +2360,21 @@
|
|
|
2342
2360
|
}, 0);
|
|
2343
2361
|
}
|
|
2344
2362
|
|
|
2345
|
-
function getSphericalShapeArea(shp, arcs) {
|
|
2363
|
+
function getSphericalShapeArea(shp, arcs, R) {
|
|
2346
2364
|
if (arcs.isPlanar()) {
|
|
2347
2365
|
error("[getSphericalShapeArea()] Function requires decimal degree coordinates");
|
|
2348
2366
|
}
|
|
2349
2367
|
return (shp || []).reduce(function(area, ids) {
|
|
2350
|
-
return area + getSphericalPathArea(ids, arcs);
|
|
2368
|
+
return area + getSphericalPathArea(ids, arcs, R);
|
|
2351
2369
|
}, 0);
|
|
2352
2370
|
}
|
|
2353
2371
|
|
|
2372
|
+
// export function getEllipsoidalShapeArea(shp, arcs, crs) {
|
|
2373
|
+
// return (shp || []).reduce(function(area, ids) {
|
|
2374
|
+
// return area + getEllipsoidalPathArea(ids, arcs, crs);
|
|
2375
|
+
// }, 0);
|
|
2376
|
+
// }
|
|
2377
|
+
|
|
2354
2378
|
// Return true if point is inside or on boundary of a shape
|
|
2355
2379
|
//
|
|
2356
2380
|
function testPointInPolygon(x, y, shp, arcs) {
|
|
@@ -2464,16 +2488,17 @@
|
|
|
2464
2488
|
return (arcs.isPlanar() ? getPlanarPathArea : getSphericalPathArea)(ids, arcs);
|
|
2465
2489
|
}
|
|
2466
2490
|
|
|
2467
|
-
function getSphericalPathArea(ids, arcs) {
|
|
2491
|
+
function getSphericalPathArea(ids, arcs, R) {
|
|
2468
2492
|
var iter = arcs.getShapeIter(ids);
|
|
2469
|
-
return getSphericalPathArea2(iter);
|
|
2493
|
+
return getSphericalPathArea2(iter, R);
|
|
2470
2494
|
}
|
|
2471
2495
|
|
|
2472
|
-
function getSphericalPathArea2(iter) {
|
|
2496
|
+
function getSphericalPathArea2(iter, R) {
|
|
2473
2497
|
var sum = 0,
|
|
2474
2498
|
started = false,
|
|
2475
2499
|
deg2rad = Math.PI / 180,
|
|
2476
2500
|
x, y, xp, yp;
|
|
2501
|
+
R = R || WGS84.SEMIMAJOR_AXIS;
|
|
2477
2502
|
while (iter.hasNext()) {
|
|
2478
2503
|
x = iter.x * deg2rad;
|
|
2479
2504
|
y = Math.sin(iter.y * deg2rad);
|
|
@@ -2485,7 +2510,7 @@
|
|
|
2485
2510
|
xp = x;
|
|
2486
2511
|
yp = y;
|
|
2487
2512
|
}
|
|
2488
|
-
return sum / 2 *
|
|
2513
|
+
return sum / 2 * R * R;
|
|
2489
2514
|
}
|
|
2490
2515
|
|
|
2491
2516
|
// Get path area from an array of [x, y] points
|
|
@@ -3949,7 +3974,7 @@
|
|
|
3949
3974
|
function requireSinglePointLayer(lyr, msg) {
|
|
3950
3975
|
requirePointLayer(lyr);
|
|
3951
3976
|
if (countMultiPartFeatures(lyr) > 0) {
|
|
3952
|
-
stop(msg || 'This command requires single points');
|
|
3977
|
+
stop(msg || 'This command requires single points; layer contains multi-point features.');
|
|
3953
3978
|
}
|
|
3954
3979
|
}
|
|
3955
3980
|
|
|
@@ -4004,6 +4029,7 @@
|
|
|
4004
4029
|
return opts && opts.no_replace ? {geometry_type: src.geometry_type} : src;
|
|
4005
4030
|
}
|
|
4006
4031
|
|
|
4032
|
+
//
|
|
4007
4033
|
function setOutputLayerName(dest, src, defName, opts) {
|
|
4008
4034
|
opts = opts || {};
|
|
4009
4035
|
if (opts.name) {
|
|
@@ -4080,6 +4106,7 @@
|
|
|
4080
4106
|
return counts;
|
|
4081
4107
|
}
|
|
4082
4108
|
|
|
4109
|
+
// Returns a Bounds object
|
|
4083
4110
|
function getLayerBounds(lyr, arcs) {
|
|
4084
4111
|
var bounds = null;
|
|
4085
4112
|
if (lyr.geometry_type == 'point') {
|
|
@@ -6151,9 +6178,11 @@
|
|
|
6151
6178
|
arcCount += n;
|
|
6152
6179
|
});
|
|
6153
6180
|
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6181
|
+
if (arcSources.length > 0) {
|
|
6182
|
+
mergedArcs = mergeArcs(arcSources);
|
|
6183
|
+
if (mergedArcs.size() != arcCount) {
|
|
6184
|
+
error("[mergeDatasets()] Arc indexing error");
|
|
6185
|
+
}
|
|
6157
6186
|
}
|
|
6158
6187
|
|
|
6159
6188
|
return {
|
|
@@ -6172,6 +6201,8 @@
|
|
|
6172
6201
|
}
|
|
6173
6202
|
|
|
6174
6203
|
function mergeArcs(arr) {
|
|
6204
|
+
// Returning the original causes a test to fail
|
|
6205
|
+
// if (arr.length < 2) return arr[0];
|
|
6175
6206
|
var dataArr = arr.map(function(arcs) {
|
|
6176
6207
|
if (arcs.getRetainedInterval() > 0) {
|
|
6177
6208
|
verbose("Baking-in simplification setting.");
|
|
@@ -6776,31 +6807,47 @@
|
|
|
6776
6807
|
dataset.layers = currLayers;
|
|
6777
6808
|
}
|
|
6778
6809
|
|
|
6779
|
-
// Replace a layer
|
|
6810
|
+
// Replace a layer with a layer from a second dataset
|
|
6811
|
+
// (in-place)
|
|
6780
6812
|
// (Typically, the second dataset is imported from dynamically generated GeoJSON and contains one layer)
|
|
6781
6813
|
function replaceLayerContents(lyr, dataset, dataset2) {
|
|
6814
|
+
var lyr2 = mergeOutputLayerIntoDataset(lyr, dataset, dataset2, {});
|
|
6815
|
+
if (layerHasPaths(lyr2)) {
|
|
6816
|
+
buildTopology(dataset);
|
|
6817
|
+
}
|
|
6818
|
+
}
|
|
6819
|
+
|
|
6820
|
+
function mergeOutputLayerIntoDataset(lyr, dataset, dataset2, opts) {
|
|
6782
6821
|
if (!dataset2 || dataset2.layers.length != 1) {
|
|
6783
|
-
error('Invalid
|
|
6822
|
+
error('Invalid source dataset');
|
|
6784
6823
|
}
|
|
6785
6824
|
if (dataset.layers.includes(lyr) === false) {
|
|
6786
6825
|
error('Invalid target layer');
|
|
6787
6826
|
}
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
mergeDatasetsIntoDataset(dataset, [dataset2]);
|
|
6792
|
-
}
|
|
6827
|
+
// this command returns merged layers instead of adding them to target dataset
|
|
6828
|
+
var outputLayers = mergeDatasetsIntoDataset(dataset, [dataset2]);
|
|
6829
|
+
var lyr2 = outputLayers[0];
|
|
6793
6830
|
|
|
6794
|
-
|
|
6831
|
+
// TODO: find a more reliable way of knowing when to copy data
|
|
6832
|
+
var copyData = !lyr2.data && lyr.data && getFeatureCount(lyr2) == lyr.data.size();
|
|
6795
6833
|
|
|
6796
|
-
if (
|
|
6797
|
-
|
|
6834
|
+
if (copyData) {
|
|
6835
|
+
lyr2.data = opts.no_replace ? lyr.data.clone() : lyr.data;
|
|
6798
6836
|
}
|
|
6799
|
-
if (
|
|
6800
|
-
//
|
|
6801
|
-
|
|
6802
|
-
|
|
6837
|
+
if (opts.no_replace) {
|
|
6838
|
+
// dataset.layers.push(lyr2);
|
|
6839
|
+
|
|
6840
|
+
} else {
|
|
6841
|
+
lyr2 = Object.assign(lyr, {data: null, shapes: null}, lyr2);
|
|
6842
|
+
if (layerHasPaths(lyr)) {
|
|
6843
|
+
// Remove unused arcs from replaced layer
|
|
6844
|
+
// TODO: consider using clean insead of this
|
|
6845
|
+
dissolveArcs(dataset);
|
|
6846
|
+
}
|
|
6803
6847
|
}
|
|
6848
|
+
|
|
6849
|
+
lyr2.name = opts.name || lyr2.name;
|
|
6850
|
+
return lyr2;
|
|
6804
6851
|
}
|
|
6805
6852
|
|
|
6806
6853
|
// Transform the points in a dataset in-place; don't clean up corrupted shapes
|
|
@@ -6829,6 +6876,7 @@
|
|
|
6829
6876
|
pruneArcs: pruneArcs,
|
|
6830
6877
|
replaceLayers: replaceLayers,
|
|
6831
6878
|
replaceLayerContents: replaceLayerContents,
|
|
6879
|
+
mergeOutputLayerIntoDataset: mergeOutputLayerIntoDataset,
|
|
6832
6880
|
transformPoints: transformPoints
|
|
6833
6881
|
});
|
|
6834
6882
|
|
|
@@ -9412,6 +9460,12 @@
|
|
|
9412
9460
|
area: function() {
|
|
9413
9461
|
return _isPlanar ? ctx.planarArea : geom.getSphericalShapeArea(_ids, arcs);
|
|
9414
9462
|
},
|
|
9463
|
+
// area2: function() {
|
|
9464
|
+
// return _isPlanar ? ctx.planarArea : geom.getSphericalShapeArea(_ids, arcs, WGS84.SEMIMINOR_RADIUS);
|
|
9465
|
+
// },
|
|
9466
|
+
// area3: function() {
|
|
9467
|
+
// return _isPlanar ? ctx.planarArea : geom.getSphericalShapeArea(_ids, arcs, WGS84.AUTHALIC_RADIUS);
|
|
9468
|
+
// },
|
|
9415
9469
|
perimeter: function() {
|
|
9416
9470
|
return geom.getShapePerimeter(_ids, arcs);
|
|
9417
9471
|
},
|
|
@@ -13332,14 +13386,14 @@
|
|
|
13332
13386
|
return mergeArcs([arcs, new ArcCollection(nn, xx, yy)]);
|
|
13333
13387
|
}
|
|
13334
13388
|
|
|
13335
|
-
var roundCoord$
|
|
13389
|
+
var roundCoord$2 = getRoundingFunction(0.01);
|
|
13336
13390
|
|
|
13337
13391
|
function stringifyVertex(p) {
|
|
13338
|
-
return ' ' + roundCoord$
|
|
13392
|
+
return ' ' + roundCoord$2(p[0]) + ' ' + roundCoord$2(p[1]);
|
|
13339
13393
|
}
|
|
13340
13394
|
|
|
13341
13395
|
function stringifyCP(p) {
|
|
13342
|
-
return ' ' + roundCoord$
|
|
13396
|
+
return ' ' + roundCoord$2(p[2]) + ' ' + roundCoord$2(p[3]);
|
|
13343
13397
|
}
|
|
13344
13398
|
|
|
13345
13399
|
function isCubicCtrl(p) {
|
|
@@ -13374,40 +13428,9 @@
|
|
|
13374
13428
|
stringifyCP(p2) + stringifyVertex(p2);
|
|
13375
13429
|
}
|
|
13376
13430
|
|
|
13377
|
-
function findArcCenter(p1, p2, degrees) {
|
|
13378
|
-
var p3 = [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2], // midpoint betw. p1, p2
|
|
13379
|
-
tan = 1 / Math.tan(degrees / 180 * Math.PI / 2),
|
|
13380
|
-
cp = getAffineTransform(90, tan, [0, 0], p3)(p2[0], p2[1]);
|
|
13381
|
-
return cp;
|
|
13382
|
-
}
|
|
13383
|
-
|
|
13384
|
-
// export function addBezierArcControlPoints(p1, p2, degrees) {
|
|
13385
|
-
function addBezierArcControlPoints(points, degrees) {
|
|
13386
|
-
// source: https://stackoverflow.com/questions/734076/how-to-best-approximate-a-geometrical-arc-with-a-bezier-curve
|
|
13387
|
-
var p2 = points.pop(),
|
|
13388
|
-
p1 = points.pop(),
|
|
13389
|
-
cp = findArcCenter(p1, p2, degrees),
|
|
13390
|
-
xc = cp[0],
|
|
13391
|
-
yc = cp[1],
|
|
13392
|
-
ax = p1[0] - xc,
|
|
13393
|
-
ay = p1[1] - yc,
|
|
13394
|
-
bx = p2[0] - xc,
|
|
13395
|
-
by = p2[1] - yc,
|
|
13396
|
-
q1 = ax * ax + ay * ay,
|
|
13397
|
-
q2 = q1 + ax * bx + ay * by,
|
|
13398
|
-
k2 = 4/3 * (Math.sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx);
|
|
13399
|
-
|
|
13400
|
-
points.push(p1);
|
|
13401
|
-
points.push([xc + ax - k2 * ay, yc + ay + k2 * ax, 'C']);
|
|
13402
|
-
points.push([xc + bx + k2 * by, yc + by - k2 * bx, 'C']);
|
|
13403
|
-
points.push(p2);
|
|
13404
|
-
}
|
|
13405
|
-
|
|
13406
13431
|
var SvgPathUtils = /*#__PURE__*/Object.freeze({
|
|
13407
13432
|
__proto__: null,
|
|
13408
|
-
stringifyLineStringCoords: stringifyLineStringCoords
|
|
13409
|
-
findArcCenter: findArcCenter,
|
|
13410
|
-
addBezierArcControlPoints: addBezierArcControlPoints
|
|
13433
|
+
stringifyLineStringCoords: stringifyLineStringCoords
|
|
13411
13434
|
});
|
|
13412
13435
|
|
|
13413
13436
|
/* example patterns
|
|
@@ -13684,11 +13707,19 @@
|
|
|
13684
13707
|
type: null,
|
|
13685
13708
|
length: 'number', // e.g. arrow length
|
|
13686
13709
|
rotation: 'number',
|
|
13687
|
-
|
|
13688
|
-
|
|
13689
|
-
|
|
13690
|
-
|
|
13691
|
-
|
|
13710
|
+
radius: 'number',
|
|
13711
|
+
radii: null, // string, parsed by function
|
|
13712
|
+
flipped: 'boolean',
|
|
13713
|
+
rotated: 'boolean',
|
|
13714
|
+
direction: 'number',
|
|
13715
|
+
'head-angle': 'number',
|
|
13716
|
+
'head-width': 'number',
|
|
13717
|
+
'head-length': 'number',
|
|
13718
|
+
'stem-width': 'number',
|
|
13719
|
+
'stem-curve': 'number', // degrees of arc
|
|
13720
|
+
'stem-taper': 'number',
|
|
13721
|
+
'stem-length': 'number',
|
|
13722
|
+
'min-stem': 'number',
|
|
13692
13723
|
'arrow-scaling': 'number',
|
|
13693
13724
|
effect: null // e.g. "fade"
|
|
13694
13725
|
}, stylePropertyTypes);
|
|
@@ -13724,17 +13755,20 @@
|
|
|
13724
13755
|
function getSymbolDataAccessor(lyr, opts) {
|
|
13725
13756
|
var functions = {};
|
|
13726
13757
|
var properties = [];
|
|
13758
|
+
var fields = lyr.data ? lyr.data.getFields() : [];
|
|
13727
13759
|
|
|
13728
13760
|
Object.keys(opts).forEach(function(optName) {
|
|
13729
13761
|
var svgName = optName.replace(/_/g, '-');
|
|
13730
13762
|
if (!isSupportedSvgSymbolProperty(svgName)) {
|
|
13731
13763
|
return;
|
|
13732
13764
|
}
|
|
13733
|
-
var
|
|
13734
|
-
functions[svgName] = getSymbolPropertyAccessor(
|
|
13765
|
+
var val = opts[optName];
|
|
13766
|
+
functions[svgName] = getSymbolPropertyAccessor(val, svgName, lyr);
|
|
13735
13767
|
properties.push(svgName);
|
|
13736
13768
|
});
|
|
13737
13769
|
|
|
13770
|
+
// TODO: consider applying values of existing fields with names of symbol properties
|
|
13771
|
+
|
|
13738
13772
|
return function(id) {
|
|
13739
13773
|
var d = {}, name;
|
|
13740
13774
|
for (var i=0; i<properties.length; i++) {
|
|
@@ -13750,11 +13784,13 @@
|
|
|
13750
13784
|
// * ???
|
|
13751
13785
|
//
|
|
13752
13786
|
function mightBeExpression(str, fields) {
|
|
13787
|
+
fields = fields || [];
|
|
13753
13788
|
if (fields.indexOf(str.trim()) > -1) return true;
|
|
13754
|
-
return /[(){}
|
|
13789
|
+
return /[(){}./*?:&|=\[+-]/.test(str);
|
|
13755
13790
|
}
|
|
13756
13791
|
|
|
13757
|
-
function getSymbolPropertyAccessor(
|
|
13792
|
+
function getSymbolPropertyAccessor(val, svgName, lyr) {
|
|
13793
|
+
var strVal = String(val).trim();
|
|
13758
13794
|
var typeHint = symbolPropertyTypes[svgName];
|
|
13759
13795
|
var fields = lyr.data ? lyr.data.getFields() : [];
|
|
13760
13796
|
var literalVal = null;
|
|
@@ -13771,6 +13807,7 @@
|
|
|
13771
13807
|
// treating the string as a literal value
|
|
13772
13808
|
literalVal = strVal;
|
|
13773
13809
|
}
|
|
13810
|
+
// console.log("literalVal:", mightBeExpression(strVal, fields), strVal, fields)
|
|
13774
13811
|
if (accessor) return accessor;
|
|
13775
13812
|
if (literalVal !== null) return function(id) {return literalVal;};
|
|
13776
13813
|
stop('Unexpected value for', svgName + ':', strVal);
|
|
@@ -13804,6 +13841,8 @@
|
|
|
13804
13841
|
val = isDashArray(strVal) ? strVal : null;
|
|
13805
13842
|
} else if (type == 'pattern') {
|
|
13806
13843
|
val = isPattern(strVal) ? strVal : null;
|
|
13844
|
+
} else if (type == 'boolean') {
|
|
13845
|
+
val = parseBoolean(strVal);
|
|
13807
13846
|
}
|
|
13808
13847
|
// else {
|
|
13809
13848
|
// // unknown type -- assume literal value
|
|
@@ -13824,10 +13863,17 @@
|
|
|
13824
13863
|
return /^( ?[_a-z][-_a-z0-9]*\b)+$/i.test(str);
|
|
13825
13864
|
}
|
|
13826
13865
|
|
|
13866
|
+
|
|
13827
13867
|
function isSvgNumber(o) {
|
|
13828
13868
|
return utils.isFiniteNumber(o) || utils.isString(o) && /^-?[.0-9]+$/.test(o);
|
|
13829
13869
|
}
|
|
13830
13870
|
|
|
13871
|
+
function parseBoolean(o) {
|
|
13872
|
+
if (o === true || o === 'true') return true;
|
|
13873
|
+
if (o === false || o === 'false') return false;
|
|
13874
|
+
return null;
|
|
13875
|
+
}
|
|
13876
|
+
|
|
13831
13877
|
function isSvgMeasure(o) {
|
|
13832
13878
|
return utils.isFiniteNumber(o) || utils.isString(o) && /^-?[.0-9]+[a-z]*$/.test(o);
|
|
13833
13879
|
}
|
|
@@ -13851,12 +13897,12 @@
|
|
|
13851
13897
|
getSymbolPropertyAccessor: getSymbolPropertyAccessor,
|
|
13852
13898
|
isSvgClassName: isSvgClassName,
|
|
13853
13899
|
isSvgNumber: isSvgNumber,
|
|
13900
|
+
parseBoolean: parseBoolean,
|
|
13854
13901
|
isSvgMeasure: isSvgMeasure,
|
|
13855
13902
|
parseSvgMeasure: parseSvgMeasure,
|
|
13856
13903
|
isSvgColor: isSvgColor
|
|
13857
13904
|
});
|
|
13858
13905
|
|
|
13859
|
-
var symbolBuilders = {};
|
|
13860
13906
|
var symbolRenderers = {};
|
|
13861
13907
|
|
|
13862
13908
|
function getTransform(xy, scale) {
|
|
@@ -13869,7 +13915,6 @@
|
|
|
13869
13915
|
|
|
13870
13916
|
var SvgCommon = /*#__PURE__*/Object.freeze({
|
|
13871
13917
|
__proto__: null,
|
|
13872
|
-
symbolBuilders: symbolBuilders,
|
|
13873
13918
|
symbolRenderers: symbolRenderers,
|
|
13874
13919
|
getTransform: getTransform
|
|
13875
13920
|
});
|
|
@@ -14071,6 +14116,9 @@
|
|
|
14071
14116
|
o = importLineString(coords[i]);
|
|
14072
14117
|
o.properties.d = d + o.properties.d + ' Z';
|
|
14073
14118
|
}
|
|
14119
|
+
if (coords.length > 1) {
|
|
14120
|
+
o.properties['fill-rule'] = 'evenodd'; // support polygons with holes
|
|
14121
|
+
}
|
|
14074
14122
|
return o;
|
|
14075
14123
|
}
|
|
14076
14124
|
|
|
@@ -17987,6 +18035,10 @@ ${svg}
|
|
|
17987
18035
|
return chunks;
|
|
17988
18036
|
}
|
|
17989
18037
|
|
|
18038
|
+
function parseNumberList(token) {
|
|
18039
|
+
return token.split(',').map(parseFloat);
|
|
18040
|
+
}
|
|
18041
|
+
|
|
17990
18042
|
// Split comma-delimited list, trim quotes from entire list and
|
|
17991
18043
|
// individual members
|
|
17992
18044
|
function parseStringList(token) {
|
|
@@ -18022,9 +18074,9 @@ ${svg}
|
|
|
18022
18074
|
// Updated: don't trim space from tokens like [delimeter= ]
|
|
18023
18075
|
argv = argv.map(function(s) {
|
|
18024
18076
|
if (!/= $/.test(s)) {
|
|
18025
|
-
s =
|
|
18077
|
+
s = utils.rtrim(s);
|
|
18026
18078
|
}
|
|
18027
|
-
s =
|
|
18079
|
+
s = utils.ltrim(s);
|
|
18028
18080
|
return s;
|
|
18029
18081
|
});
|
|
18030
18082
|
argv = argv.filter(function(s) {return s !== '';}); // remove empty tokens
|
|
@@ -18076,6 +18128,7 @@ ${svg}
|
|
|
18076
18128
|
var OptionParsingUtils = /*#__PURE__*/Object.freeze({
|
|
18077
18129
|
__proto__: null,
|
|
18078
18130
|
splitShellTokens: splitShellTokens,
|
|
18131
|
+
parseNumberList: parseNumberList,
|
|
18079
18132
|
parseStringList: parseStringList,
|
|
18080
18133
|
parseColorList: parseColorList,
|
|
18081
18134
|
cleanArgv: cleanArgv,
|
|
@@ -18267,7 +18320,7 @@ ${svg}
|
|
|
18267
18320
|
} else if (type == 'strings') {
|
|
18268
18321
|
val = parseStringList(token);
|
|
18269
18322
|
} else if (type == 'bbox' || type == 'numbers') {
|
|
18270
|
-
val = token
|
|
18323
|
+
val = parseNumberList(token);
|
|
18271
18324
|
} else if (type == 'percent') {
|
|
18272
18325
|
// val = utils.parsePercent(token);
|
|
18273
18326
|
val = token; // string value is parsed by command function
|
|
@@ -19479,6 +19532,13 @@ ${svg}
|
|
|
19479
19532
|
})
|
|
19480
19533
|
.option('target', targetOpt);
|
|
19481
19534
|
|
|
19535
|
+
parser.command('include')
|
|
19536
|
+
.describe('import JS data and functions for use in JS expressions')
|
|
19537
|
+
.option('file', {
|
|
19538
|
+
DEFAULT: true,
|
|
19539
|
+
describe: 'file containing a JS object with key:value pairs to import'
|
|
19540
|
+
});
|
|
19541
|
+
|
|
19482
19542
|
parser.command('inlay')
|
|
19483
19543
|
.describe('inscribe a polygon layer inside another polygon layer')
|
|
19484
19544
|
.option('source', {
|
|
@@ -19791,6 +19851,7 @@ ${svg}
|
|
|
19791
19851
|
})
|
|
19792
19852
|
.option('target', targetOpt);
|
|
19793
19853
|
|
|
19854
|
+
|
|
19794
19855
|
parser.command('simplify')
|
|
19795
19856
|
.validate(validateSimplifyOpts)
|
|
19796
19857
|
.example('Retain 10% of removable vertices\n$ mapshaper input.shp -simplify 10%')
|
|
@@ -20029,26 +20090,112 @@ ${svg}
|
|
|
20029
20090
|
.option('target', targetOpt);
|
|
20030
20091
|
|
|
20031
20092
|
parser.command('symbols')
|
|
20032
|
-
// .describe('
|
|
20093
|
+
// .describe('symbolize points as polygons, circles, stars or arrows')
|
|
20033
20094
|
.option('type', {
|
|
20034
|
-
describe: 'symbol type'
|
|
20095
|
+
describe: 'symbol type (e.g. star, polygon, circle, arrow)'
|
|
20096
|
+
})
|
|
20097
|
+
.option('scale', {
|
|
20098
|
+
describe: 'scale symbols by a factor',
|
|
20099
|
+
type: 'number'
|
|
20100
|
+
})
|
|
20101
|
+
.option('pixel-scale', {
|
|
20102
|
+
describe: 'symbol scale in meters-per-pixel (see polygons option)',
|
|
20103
|
+
type: 'number',
|
|
20104
|
+
})
|
|
20105
|
+
.option('polygons', {
|
|
20106
|
+
describe: 'generate symbols as polygons instead of SVG objects',
|
|
20107
|
+
type: 'flag'
|
|
20108
|
+
})
|
|
20109
|
+
.option('radius', {
|
|
20110
|
+
describe: 'distance from center to farthest point on the symbol',
|
|
20111
|
+
type: 'distance'
|
|
20112
|
+
})
|
|
20113
|
+
.option('sides', {
|
|
20114
|
+
describe: 'sides of a polygon or star symbol',
|
|
20115
|
+
type: 'number'
|
|
20116
|
+
})
|
|
20117
|
+
.option('orientation', {
|
|
20118
|
+
// describe: 'use orientation=b for a rotated or flipped orientation'
|
|
20119
|
+
})
|
|
20120
|
+
.option('flipped', {
|
|
20121
|
+
type: 'flag',
|
|
20122
|
+
describe: 'symbol is vertically flipped'
|
|
20123
|
+
})
|
|
20124
|
+
.option('rotated', {
|
|
20125
|
+
type: 'flag',
|
|
20126
|
+
describe: 'symbol is rotated to a different orientation'
|
|
20127
|
+
})
|
|
20128
|
+
.option('rotation', {
|
|
20129
|
+
describe: 'rotation of symbol in degrees'
|
|
20130
|
+
})
|
|
20131
|
+
.option('length', {
|
|
20132
|
+
// alias for arrow-length
|
|
20133
|
+
})
|
|
20134
|
+
.option('point-ratio', {
|
|
20135
|
+
old_alias: 'star-ratio',
|
|
20136
|
+
describe: '(star) ratio of minor to major radius of star',
|
|
20137
|
+
type: 'number'
|
|
20138
|
+
})
|
|
20139
|
+
.option('radii', {
|
|
20140
|
+
describe: '(ring) comma-sep. list of concentric radii, ascending order'
|
|
20141
|
+
})
|
|
20142
|
+
.option('length', {
|
|
20143
|
+
old_alias: 'arrow-length',
|
|
20144
|
+
describe: '(arrow) length of arrow in pixels'
|
|
20145
|
+
})
|
|
20146
|
+
.option('direction', {
|
|
20147
|
+
old_alias: 'arrow-direction',
|
|
20148
|
+
describe: '(arrow) angle off vertical (-90 = left-pointing)'
|
|
20149
|
+
})
|
|
20150
|
+
.option('head-angle', {
|
|
20151
|
+
old_alias: 'arrow-head-angle',
|
|
20152
|
+
describe: '(arrow) angle of tip of arrow (default is 40 degrees)'
|
|
20153
|
+
})
|
|
20154
|
+
.option('head-width', {
|
|
20155
|
+
old_alias: 'arrow-head-width',
|
|
20156
|
+
describe: '(arrow) width of arrow head from side to side'
|
|
20157
|
+
})
|
|
20158
|
+
.option('head-length', {
|
|
20159
|
+
old_alias: 'arrow-head-width',
|
|
20160
|
+
describe: '(arrow) length of head (alternative to head-angle)'
|
|
20161
|
+
})
|
|
20162
|
+
.option('head-shape', {
|
|
20163
|
+
// describe: 'options: a b c'
|
|
20164
|
+
})
|
|
20165
|
+
.option('stem-width', {
|
|
20166
|
+
old_alias: 'arrow-stem-width',
|
|
20167
|
+
describe: '(arrow) width of stem at its widest point'
|
|
20168
|
+
})
|
|
20169
|
+
.option('stem-length', {
|
|
20170
|
+
old_alias: 'arrow-stem-length',
|
|
20171
|
+
describe: '(arrow) alternative to length'
|
|
20172
|
+
})
|
|
20173
|
+
.option('stem-taper', {
|
|
20174
|
+
old_alias: 'arrow-stem-taper',
|
|
20175
|
+
describe: '(arrow) factor for tapering the width of the stem (0-1)'
|
|
20176
|
+
})
|
|
20177
|
+
.option('stem-curve', {
|
|
20178
|
+
old_alias: 'arrow-stem-curve',
|
|
20179
|
+
describe: '(arrow) curvature in degrees (default is 0)'
|
|
20180
|
+
})
|
|
20181
|
+
.option('min-stem-ratio', {
|
|
20182
|
+
old_alias: 'arrow-min-stem',
|
|
20183
|
+
describe: '(arrow) min ratio of stem to total length',
|
|
20184
|
+
type: 'number'
|
|
20035
20185
|
})
|
|
20036
20186
|
.option('stroke', {})
|
|
20037
20187
|
.option('stroke-width', {})
|
|
20038
|
-
.option('fill', {
|
|
20039
|
-
|
|
20040
|
-
|
|
20188
|
+
.option('fill', {
|
|
20189
|
+
describe: 'symbol fill color'
|
|
20190
|
+
})
|
|
20041
20191
|
.option('effect', {})
|
|
20042
|
-
.option('
|
|
20043
|
-
.option('
|
|
20044
|
-
.option('
|
|
20045
|
-
.option('
|
|
20046
|
-
.option('arrow-stem-taper', {})
|
|
20047
|
-
.option('arrow-scaling', {})
|
|
20048
|
-
.option('where', whereOpt)
|
|
20049
|
-
.option('target', targetOpt);
|
|
20192
|
+
// .option('where', whereOpt)
|
|
20193
|
+
.option('name', nameOpt)
|
|
20194
|
+
.option('target', targetOpt)
|
|
20195
|
+
.option('no-replace', noReplaceOpt);
|
|
20050
20196
|
// .option('name', nameOpt);
|
|
20051
20197
|
|
|
20198
|
+
|
|
20052
20199
|
parser.command('target')
|
|
20053
20200
|
.describe('set active layer (or layers)')
|
|
20054
20201
|
.option('target', {
|
|
@@ -20199,13 +20346,6 @@ ${svg}
|
|
|
20199
20346
|
})
|
|
20200
20347
|
.option('name', nameOpt);
|
|
20201
20348
|
|
|
20202
|
-
parser.command('include')
|
|
20203
|
-
.describe('import JS data and functions for use in JS expressions')
|
|
20204
|
-
.option('file', {
|
|
20205
|
-
DEFAULT: true,
|
|
20206
|
-
describe: 'file containing a JS object with key:value pairs to import'
|
|
20207
|
-
});
|
|
20208
|
-
|
|
20209
20349
|
parser.command('fuzzy-join')
|
|
20210
20350
|
.describe('join points to polygons, with data fill and fuzzy match')
|
|
20211
20351
|
.option('source', {
|
|
@@ -20341,16 +20481,6 @@ ${svg}
|
|
|
20341
20481
|
})
|
|
20342
20482
|
.option('name', nameOpt);
|
|
20343
20483
|
|
|
20344
|
-
// parser.command('shapes')
|
|
20345
|
-
// .describe('convert points to shapes')
|
|
20346
|
-
// .option('type', {
|
|
20347
|
-
// })
|
|
20348
|
-
// .option('size', {
|
|
20349
|
-
// })
|
|
20350
|
-
// .option('rotation', {
|
|
20351
|
-
// })
|
|
20352
|
-
|
|
20353
|
-
|
|
20354
20484
|
parser.command('subdivide')
|
|
20355
20485
|
.describe('recursively split a layer using a JS expression')
|
|
20356
20486
|
.validate(validateExpressionOpt)
|
|
@@ -21214,12 +21344,13 @@ ${svg}
|
|
|
21214
21344
|
if (this instanceof ShpReader === false) {
|
|
21215
21345
|
return new ShpReader(shpSrc, shxSrc);
|
|
21216
21346
|
}
|
|
21217
|
-
|
|
21218
21347
|
var shpFile = utils.isString(shpSrc) ? new FileReader(shpSrc) : new BufferReader(shpSrc);
|
|
21219
21348
|
var header = parseHeader(shpFile.readToBinArray(0, 100));
|
|
21220
|
-
var
|
|
21221
|
-
var
|
|
21222
|
-
var
|
|
21349
|
+
var shpType = header.type;
|
|
21350
|
+
var shpOffset = 100; // used when reading .shp without .shx
|
|
21351
|
+
var recordCount = 0;
|
|
21352
|
+
var badRecordNumberCount = 0;
|
|
21353
|
+
var RecordClass = new ShpRecordClass(shpType);
|
|
21223
21354
|
var shxBin, shxFile;
|
|
21224
21355
|
|
|
21225
21356
|
if (shxSrc) {
|
|
@@ -21227,8 +21358,6 @@ ${svg}
|
|
|
21227
21358
|
shxBin = shxFile.readToBinArray(0, shxFile.size()).bigEndian();
|
|
21228
21359
|
}
|
|
21229
21360
|
|
|
21230
|
-
reset();
|
|
21231
|
-
|
|
21232
21361
|
this.header = function() {
|
|
21233
21362
|
return header;
|
|
21234
21363
|
};
|
|
@@ -21246,37 +21375,35 @@ ${svg}
|
|
|
21246
21375
|
|
|
21247
21376
|
// Iterator interface for reading shape records
|
|
21248
21377
|
this.nextShape = function() {
|
|
21249
|
-
var shape
|
|
21250
|
-
if (
|
|
21251
|
-
|
|
21252
|
-
|
|
21253
|
-
shpFile.close();
|
|
21254
|
-
reset();
|
|
21378
|
+
var shape;
|
|
21379
|
+
if (!shpFile) {
|
|
21380
|
+
error('Tried to read from a used ShpReader');
|
|
21381
|
+
// return null; // this reader was already used
|
|
21255
21382
|
}
|
|
21383
|
+
shape = readNextShape(recordCount);
|
|
21384
|
+
if (!shape) {
|
|
21385
|
+
done();
|
|
21386
|
+
return null;
|
|
21387
|
+
}
|
|
21388
|
+
recordCount++;
|
|
21256
21389
|
return shape;
|
|
21257
21390
|
};
|
|
21258
21391
|
|
|
21259
21392
|
// Returns a shape record or null if no more shapes can be read
|
|
21393
|
+
// i: Expected 0-based index of the next record
|
|
21260
21394
|
//
|
|
21261
21395
|
function readNextShape(i) {
|
|
21262
|
-
|
|
21263
|
-
|
|
21264
|
-
|
|
21265
|
-
if (shxFile.size() <= 100 + i * 8) return null; // done
|
|
21266
|
-
shxBin.position(100 + i * 8);
|
|
21267
|
-
offset = shxBin.readUint32() * 2;
|
|
21268
|
-
shape = readIndexedShape(shpFile, offset, expectedId);
|
|
21269
|
-
} else {
|
|
21270
|
-
// Reading without a .shx file (returns null at end-of-file)
|
|
21271
|
-
offset = shpOffset;
|
|
21272
|
-
shape = readNonIndexedShape(shpFile, offset, expectedId);
|
|
21273
|
-
}
|
|
21274
|
-
return shape || null;
|
|
21396
|
+
return shxBin ?
|
|
21397
|
+
readIndexedShape(shpFile, shxBin, i) :
|
|
21398
|
+
readNonIndexedShape(shpFile, shpOffset, i);
|
|
21275
21399
|
}
|
|
21276
21400
|
|
|
21277
|
-
function
|
|
21278
|
-
|
|
21279
|
-
|
|
21401
|
+
function done() {
|
|
21402
|
+
shpFile.close();
|
|
21403
|
+
shpFile = shxFile = shxBin = null;
|
|
21404
|
+
if (badRecordNumberCount > 0) {
|
|
21405
|
+
message(`Warning: ${badRecordNumberCount}/${recordCount} features have non-standard record numbers in the .shp file.`);
|
|
21406
|
+
}
|
|
21280
21407
|
}
|
|
21281
21408
|
|
|
21282
21409
|
function parseHeader(bin) {
|
|
@@ -21307,33 +21434,35 @@ ${svg}
|
|
|
21307
21434
|
|
|
21308
21435
|
|
|
21309
21436
|
function readShapeAtOffset(shpFile, offset) {
|
|
21310
|
-
var
|
|
21311
|
-
|
|
21312
|
-
|
|
21313
|
-
|
|
21314
|
-
|
|
21315
|
-
|
|
21316
|
-
|
|
21317
|
-
|
|
21318
|
-
|
|
21319
|
-
|
|
21320
|
-
|
|
21321
|
-
if (goodSize && goodType) {
|
|
21322
|
-
bin = shpFile.readToBinArray(offset, recordSize);
|
|
21323
|
-
shape = new RecordClass(bin, recordSize);
|
|
21324
|
-
}
|
|
21437
|
+
var fileSize = shpFile.size();
|
|
21438
|
+
if (offset + 12 > fileSize) return null; // reached end-of-file
|
|
21439
|
+
var bin = shpFile.readToBinArray(offset, 12);
|
|
21440
|
+
var recordId = bin.bigEndian().readUint32();
|
|
21441
|
+
// record size is bytes in content section + 8 header bytes
|
|
21442
|
+
var recordSize = bin.readUint32() * 2 + 8;
|
|
21443
|
+
var recordType = bin.littleEndian().readUint32();
|
|
21444
|
+
var goodSize = offset + recordSize <= fileSize && recordSize >= 12;
|
|
21445
|
+
var goodType = recordType === 0 || recordType == shpType;
|
|
21446
|
+
if (!goodSize || !goodType) {
|
|
21447
|
+
return null;
|
|
21325
21448
|
}
|
|
21326
|
-
|
|
21449
|
+
bin = shpFile.readToBinArray(offset, recordSize);
|
|
21450
|
+
return new RecordClass(bin, recordSize);
|
|
21327
21451
|
}
|
|
21328
21452
|
|
|
21329
|
-
function readIndexedShape(shpFile,
|
|
21453
|
+
function readIndexedShape(shpFile, shxBin, i) {
|
|
21454
|
+
if (shxBin.size() <= 100 + i * 8) return null; // done
|
|
21455
|
+
shxBin.position(100 + i * 8);
|
|
21456
|
+
var expectedId = i + 1;
|
|
21457
|
+
var offset = shxBin.readUint32() * 2;
|
|
21458
|
+
var recLen = shxBin.readUint32() * 2; // TODO: match this to recLen in .shp
|
|
21330
21459
|
var shape = readShapeAtOffset(shpFile, offset);
|
|
21331
21460
|
if (!shape) {
|
|
21332
21461
|
stop('Index of Shapefile record', expectedId, 'in the .shx file is invalid.');
|
|
21333
21462
|
}
|
|
21334
21463
|
if (shape.id != expectedId) {
|
|
21335
|
-
|
|
21336
|
-
|
|
21464
|
+
badRecordNumberCount++;
|
|
21465
|
+
verbose(`Warning: A feature has a different record number in .shx (${expectedId}) and .shp (${shape.id}).`);
|
|
21337
21466
|
}
|
|
21338
21467
|
// TODO: consider printing verbose message if a .shp file contains garbage bytes
|
|
21339
21468
|
// example files:
|
|
@@ -21346,11 +21475,12 @@ ${svg}
|
|
|
21346
21475
|
// in consecutive sequence in the .shp file. This is a problem when the .shx
|
|
21347
21476
|
// index file is not present.
|
|
21348
21477
|
//
|
|
21349
|
-
// Here, we try to scan past invalid content to find the next record.
|
|
21478
|
+
// Here, we try to scan past any invalid content to find the next record.
|
|
21350
21479
|
// Records are required to be in sequential order.
|
|
21351
21480
|
//
|
|
21352
|
-
function readNonIndexedShape(shpFile, start,
|
|
21353
|
-
var
|
|
21481
|
+
function readNonIndexedShape(shpFile, start, i) {
|
|
21482
|
+
var expectedId = i + 1, // Shapefile ids are 1-based
|
|
21483
|
+
offset = start,
|
|
21354
21484
|
fileSize = shpFile.size(),
|
|
21355
21485
|
shape = null,
|
|
21356
21486
|
bin, recordId, recordType, isValidType;
|
|
@@ -21358,7 +21488,7 @@ ${svg}
|
|
|
21358
21488
|
bin = shpFile.readToBinArray(offset, 12);
|
|
21359
21489
|
recordId = bin.bigEndian().readUint32();
|
|
21360
21490
|
recordType = bin.littleEndian().skipBytes(4).readUint32();
|
|
21361
|
-
isValidType = recordType ==
|
|
21491
|
+
isValidType = recordType == shpType || recordType === 0;
|
|
21362
21492
|
if (!isValidType || recordId != expectedId && recordType === 0) {
|
|
21363
21493
|
offset += 4; // keep scanning -- try next integer position
|
|
21364
21494
|
continue;
|
|
@@ -21385,22 +21515,6 @@ ${svg}
|
|
|
21385
21515
|
return this.header().type;
|
|
21386
21516
|
};
|
|
21387
21517
|
|
|
21388
|
-
ShpReader.prototype.getCounts = function() {
|
|
21389
|
-
var counts = {
|
|
21390
|
-
nullCount: 0,
|
|
21391
|
-
partCount: 0,
|
|
21392
|
-
shapeCount: 0,
|
|
21393
|
-
pointCount: 0
|
|
21394
|
-
};
|
|
21395
|
-
this.forEachShape(function(shp) {
|
|
21396
|
-
if (shp.isNull) counts.nullCount++;
|
|
21397
|
-
counts.pointCount += shp.pointCount;
|
|
21398
|
-
counts.partCount += shp.partCount;
|
|
21399
|
-
counts.shapeCount++;
|
|
21400
|
-
});
|
|
21401
|
-
return counts;
|
|
21402
|
-
};
|
|
21403
|
-
|
|
21404
21518
|
// Apply snapping, remove duplicate coords and clean up defective paths in a dataset
|
|
21405
21519
|
// Assumes that any CRS info has been added to the dataset
|
|
21406
21520
|
// @opts: import options
|
|
@@ -21603,7 +21717,7 @@ ${svg}
|
|
|
21603
21717
|
collectionType = 'mixed';
|
|
21604
21718
|
}
|
|
21605
21719
|
} else if (currType != t) {
|
|
21606
|
-
stop("Unable to import mixed-geometry
|
|
21720
|
+
stop("Unable to import mixed-geometry features");
|
|
21607
21721
|
}
|
|
21608
21722
|
}
|
|
21609
21723
|
|
|
@@ -21714,6 +21828,33 @@ ${svg}
|
|
|
21714
21828
|
importShp: importShp
|
|
21715
21829
|
});
|
|
21716
21830
|
|
|
21831
|
+
function importGeoJSON(src, optsArg) {
|
|
21832
|
+
var opts = optsArg || {};
|
|
21833
|
+
var supportedGeometries = Object.keys(GeoJSON.pathImporters),
|
|
21834
|
+
srcObj = utils.isString(src) ? JSON.parse(src) : src,
|
|
21835
|
+
importer = new GeoJSONParser(opts),
|
|
21836
|
+
srcCollection, dataset;
|
|
21837
|
+
|
|
21838
|
+
// Convert single feature or geometry into a collection with one member
|
|
21839
|
+
if (srcObj.type == 'Feature') {
|
|
21840
|
+
srcCollection = {
|
|
21841
|
+
type: 'FeatureCollection',
|
|
21842
|
+
features: [srcObj]
|
|
21843
|
+
};
|
|
21844
|
+
} else if (supportedGeometries.includes(srcObj.type)) {
|
|
21845
|
+
srcCollection = {
|
|
21846
|
+
type: 'GeometryCollection',
|
|
21847
|
+
geometries: [srcObj]
|
|
21848
|
+
};
|
|
21849
|
+
} else {
|
|
21850
|
+
srcCollection = srcObj;
|
|
21851
|
+
}
|
|
21852
|
+
(srcCollection.features || srcCollection.geometries || []).forEach(importer.parseObject);
|
|
21853
|
+
dataset = importer.done();
|
|
21854
|
+
importCRS(dataset, srcObj); // TODO: remove this
|
|
21855
|
+
return dataset;
|
|
21856
|
+
}
|
|
21857
|
+
|
|
21717
21858
|
function GeoJSONParser(opts) {
|
|
21718
21859
|
var idField = opts.id_field || GeoJSON.ID_FIELD,
|
|
21719
21860
|
importer = new PathImporter(opts),
|
|
@@ -21735,8 +21876,11 @@ ${svg}
|
|
|
21735
21876
|
geom = o;
|
|
21736
21877
|
}
|
|
21737
21878
|
// TODO: improve so geometry_type option skips features instead of creating null geometries
|
|
21738
|
-
|
|
21739
|
-
|
|
21879
|
+
if (geom && geom.type == 'GeometryCollection') {
|
|
21880
|
+
GeoJSON.importComplexFeature(importer, geom, rec, opts);
|
|
21881
|
+
} else {
|
|
21882
|
+
GeoJSON.importSimpleFeature(importer, geom, rec, opts);
|
|
21883
|
+
}
|
|
21740
21884
|
};
|
|
21741
21885
|
|
|
21742
21886
|
this.done = function() {
|
|
@@ -21744,50 +21888,58 @@ ${svg}
|
|
|
21744
21888
|
};
|
|
21745
21889
|
}
|
|
21746
21890
|
|
|
21747
|
-
function
|
|
21748
|
-
var
|
|
21749
|
-
|
|
21750
|
-
|
|
21751
|
-
|
|
21752
|
-
srcCollection, dataset;
|
|
21753
|
-
|
|
21754
|
-
// Convert single feature or geometry into a collection with one member
|
|
21755
|
-
if (srcObj.type == 'Feature') {
|
|
21756
|
-
srcCollection = {
|
|
21757
|
-
type: 'FeatureCollection',
|
|
21758
|
-
features: [srcObj]
|
|
21759
|
-
};
|
|
21760
|
-
} else if (supportedGeometries.includes(srcObj.type)) {
|
|
21761
|
-
srcCollection = {
|
|
21762
|
-
type: 'GeometryCollection',
|
|
21763
|
-
geometries: [srcObj]
|
|
21764
|
-
};
|
|
21765
|
-
} else {
|
|
21766
|
-
srcCollection = srcObj;
|
|
21891
|
+
GeoJSON.importComplexFeature = function(importer, geom, rec, opts) {
|
|
21892
|
+
var types = divideGeometriesByType(geom.geometries || []);
|
|
21893
|
+
if (types.length === 0) {
|
|
21894
|
+
importer.startShape(rec); // import a feature with null geometry
|
|
21895
|
+
return;
|
|
21767
21896
|
}
|
|
21768
|
-
(
|
|
21769
|
-
|
|
21770
|
-
|
|
21771
|
-
|
|
21897
|
+
types.forEach(function(geometries, i) {
|
|
21898
|
+
importer.startShape(copyRecord(rec));
|
|
21899
|
+
geometries.forEach(function(geom) {
|
|
21900
|
+
GeoJSON.importSimpleGeometry(importer, geom, opts);
|
|
21901
|
+
});
|
|
21902
|
+
});
|
|
21903
|
+
};
|
|
21904
|
+
|
|
21905
|
+
function divideGeometriesByType(geometries, index) {
|
|
21906
|
+
index = index || {};
|
|
21907
|
+
geometries.forEach(function(geom) {
|
|
21908
|
+
if (!geom) return;
|
|
21909
|
+
var mtype = GeoJSON.translateGeoJSONType(geom.type);
|
|
21910
|
+
if (mtype) {
|
|
21911
|
+
if (mtype in index === false) {
|
|
21912
|
+
index[mtype] = [];
|
|
21913
|
+
}
|
|
21914
|
+
index[mtype].push(geom);
|
|
21915
|
+
} else if (geom.type == 'GeometryCollection') {
|
|
21916
|
+
divideGeometriesByType(geom.geometries || [], index);
|
|
21917
|
+
}
|
|
21918
|
+
});
|
|
21919
|
+
return Object.values(index);
|
|
21772
21920
|
}
|
|
21773
21921
|
|
|
21774
|
-
GeoJSON.
|
|
21775
|
-
|
|
21776
|
-
|
|
21922
|
+
GeoJSON.importSimpleFeature = function(importer, geom, rec, opts) {
|
|
21923
|
+
importer.startShape(rec);
|
|
21924
|
+
GeoJSON.importSimpleGeometry(importer, geom, opts);
|
|
21925
|
+
};
|
|
21926
|
+
|
|
21927
|
+
GeoJSON.importSimpleGeometry = function(importer, geom, opts) {
|
|
21928
|
+
var type = geom ? geom.type : null;
|
|
21929
|
+
if (type === null) {
|
|
21930
|
+
// no geometry to import
|
|
21931
|
+
} else if (type in GeoJSON.pathImporters) {
|
|
21777
21932
|
if (opts.geometry_type && opts.geometry_type != GeoJSON.translateGeoJSONType(type)) {
|
|
21778
21933
|
// kludge to filter out all but one type of geometry
|
|
21779
21934
|
return;
|
|
21780
21935
|
}
|
|
21781
21936
|
GeoJSON.pathImporters[type](geom.coordinates, importer);
|
|
21782
|
-
} else if (type == 'GeometryCollection') {
|
|
21783
|
-
geom.geometries.forEach(function(geom) {
|
|
21784
|
-
GeoJSON.importGeometry(geom, importer, opts);
|
|
21785
|
-
});
|
|
21786
21937
|
} else {
|
|
21787
|
-
verbose("
|
|
21938
|
+
verbose("Unsupported geometry type:", geom.type);
|
|
21788
21939
|
}
|
|
21789
21940
|
};
|
|
21790
21941
|
|
|
21942
|
+
|
|
21791
21943
|
// Functions for importing geometry coordinates using a PathImporter
|
|
21792
21944
|
//
|
|
21793
21945
|
GeoJSON.pathImporters = {
|
|
@@ -21826,8 +21978,8 @@ ${svg}
|
|
|
21826
21978
|
|
|
21827
21979
|
var GeojsonImport = /*#__PURE__*/Object.freeze({
|
|
21828
21980
|
__proto__: null,
|
|
21829
|
-
GeoJSONParser: GeoJSONParser,
|
|
21830
21981
|
importGeoJSON: importGeoJSON,
|
|
21982
|
+
GeoJSONParser: GeoJSONParser,
|
|
21831
21983
|
importCRS: importCRS
|
|
21832
21984
|
});
|
|
21833
21985
|
|
|
@@ -26209,7 +26361,6 @@ ${svg}
|
|
|
26209
26361
|
if (constTol) return constTol;
|
|
26210
26362
|
return constTol ? constTol : meterDist * pctOfRadius;
|
|
26211
26363
|
};
|
|
26212
|
-
|
|
26213
26364
|
}
|
|
26214
26365
|
|
|
26215
26366
|
function getBufferDistanceFunction(lyr, dataset, opts) {
|
|
@@ -27382,7 +27533,7 @@ ${svg}
|
|
|
27382
27533
|
cmd.buffer = makeBufferLayer;
|
|
27383
27534
|
|
|
27384
27535
|
function makeBufferLayer(lyr, dataset, opts) {
|
|
27385
|
-
var dataset2
|
|
27536
|
+
var dataset2;
|
|
27386
27537
|
if (lyr.geometry_type == 'point') {
|
|
27387
27538
|
dataset2 = makePointBuffer(lyr, dataset, opts);
|
|
27388
27539
|
} else if (lyr.geometry_type == 'polyline') {
|
|
@@ -27392,13 +27543,9 @@ ${svg}
|
|
|
27392
27543
|
} else {
|
|
27393
27544
|
stop("Unsupported geometry type");
|
|
27394
27545
|
}
|
|
27395
|
-
|
|
27396
|
-
lyr2 =
|
|
27397
|
-
|
|
27398
|
-
if (lyr.data && !lyr2.data) {
|
|
27399
|
-
lyr2.data = opts.no_replace ? lyr.data.clone() : lyr.data;
|
|
27400
|
-
}
|
|
27401
|
-
return outputLayers;
|
|
27546
|
+
|
|
27547
|
+
var lyr2 = mergeOutputLayerIntoDataset(lyr, dataset, dataset2, opts);
|
|
27548
|
+
return [lyr2];
|
|
27402
27549
|
}
|
|
27403
27550
|
|
|
27404
27551
|
// TODO: support three or more stops
|
|
@@ -33983,7 +34130,7 @@ ${svg}
|
|
|
33983
34130
|
|
|
33984
34131
|
function createMeridianPart(x, ymin, ymax) {
|
|
33985
34132
|
var coords = densifyPathByInterval([[x, ymin], [x, ymax]], precision);
|
|
33986
|
-
meridians.push(graticuleFeature(coords, {type: 'meridian', value: roundCoord(x)}));
|
|
34133
|
+
meridians.push(graticuleFeature(coords, {type: 'meridian', value: roundCoord$1(x)}));
|
|
33987
34134
|
}
|
|
33988
34135
|
|
|
33989
34136
|
function createParallel(y) {
|
|
@@ -33993,7 +34140,7 @@ ${svg}
|
|
|
33993
34140
|
}
|
|
33994
34141
|
|
|
33995
34142
|
// remove tiny offsets
|
|
33996
|
-
function roundCoord(x) {
|
|
34143
|
+
function roundCoord$1(x) {
|
|
33997
34144
|
return +x.toFixed(3) || 0;
|
|
33998
34145
|
}
|
|
33999
34146
|
|
|
@@ -36644,6 +36791,99 @@ ${svg}
|
|
|
36644
36791
|
parseScalebarLabelToKm: parseScalebarLabelToKm
|
|
36645
36792
|
});
|
|
36646
36793
|
|
|
36794
|
+
cmd.shape = function(targetDataset, opts) {
|
|
36795
|
+
var geojson, dataset;
|
|
36796
|
+
if (opts.coordinates) {
|
|
36797
|
+
geojson = makeShapeFromCoords(opts);
|
|
36798
|
+
} else if (opts.type == 'circle') {
|
|
36799
|
+
geojson = makeCircle(opts);
|
|
36800
|
+
} else if (opts.type == 'rectangle' && opts.bbox) {
|
|
36801
|
+
geojson = getRectangleGeoJSON(opts);
|
|
36802
|
+
} else {
|
|
36803
|
+
stop('Missing coordinates parameter');
|
|
36804
|
+
}
|
|
36805
|
+
// TODO: project shape if targetDataset is projected
|
|
36806
|
+
dataset = importGeoJSON(geojson, {});
|
|
36807
|
+
if (opts.rotation) {
|
|
36808
|
+
rotateDatasetCoords(dataset, opts.rotation);
|
|
36809
|
+
}
|
|
36810
|
+
dataset.layers[0].name = opts.name || opts.type || 'shape';
|
|
36811
|
+
return dataset;
|
|
36812
|
+
};
|
|
36813
|
+
|
|
36814
|
+
function getRectangleGeoJSON(opts) {
|
|
36815
|
+
var bbox = opts.bbox,
|
|
36816
|
+
xmin = bbox[0],
|
|
36817
|
+
ymin = bbox[1],
|
|
36818
|
+
xmax = bbox[2],
|
|
36819
|
+
ymax = bbox[3],
|
|
36820
|
+
interval = 0.5,
|
|
36821
|
+
coords = [],
|
|
36822
|
+
type = opts.geometry == 'polyline' ? 'LineString' : 'Polygon';
|
|
36823
|
+
addSide(xmin, ymin, xmin, ymax);
|
|
36824
|
+
addSide(xmin, ymax, xmax, ymax);
|
|
36825
|
+
addSide(xmax, ymax, xmax, ymin);
|
|
36826
|
+
addSide(xmax, ymin, xmin, ymin);
|
|
36827
|
+
coords.push([xmin, ymin]);
|
|
36828
|
+
return {
|
|
36829
|
+
type: type,
|
|
36830
|
+
coordinates: type == 'Polygon' ? [coords] : coords
|
|
36831
|
+
};
|
|
36832
|
+
|
|
36833
|
+
function addSide(x1, y1, x2, y2) {
|
|
36834
|
+
var dx = x2 - x1,
|
|
36835
|
+
dy = y2 - y1,
|
|
36836
|
+
n = Math.ceil(Math.max(Math.abs(dx) / interval, Math.abs(dy) / interval)),
|
|
36837
|
+
xint = dx / n,
|
|
36838
|
+
yint = dy / n;
|
|
36839
|
+
for (var i=0; i<n; i++) {
|
|
36840
|
+
coords.push([x1 + i * xint, y1 + i * yint]);
|
|
36841
|
+
}
|
|
36842
|
+
}
|
|
36843
|
+
}
|
|
36844
|
+
|
|
36845
|
+
function makeCircle(opts) {
|
|
36846
|
+
if (opts.radius > 0 === false && opts.radius_angle > 0 === false) {
|
|
36847
|
+
stop('Missing required radius parameter.');
|
|
36848
|
+
}
|
|
36849
|
+
var cp = opts.center || [0, 0];
|
|
36850
|
+
var radius = opts.radius || getCircleRadiusFromAngle(getCRS('wgs84'), opts.radius_angle);
|
|
36851
|
+
return getCircleGeoJSON(cp, radius, null, {geometry_type : opts.geometry || 'polygon'});
|
|
36852
|
+
}
|
|
36853
|
+
|
|
36854
|
+
function makeShapeFromCoords(opts) {
|
|
36855
|
+
var coordinates = [];
|
|
36856
|
+
var offsets = opts.offsets || [];
|
|
36857
|
+
var coords = opts.coordinates;
|
|
36858
|
+
var type, i, x, y;
|
|
36859
|
+
if (coords.length >= 2 === false) {
|
|
36860
|
+
stop('Invalid coordinates parameter.');
|
|
36861
|
+
}
|
|
36862
|
+
for (i=0; i<coords.length; i+= 2) {
|
|
36863
|
+
x = coords[i];
|
|
36864
|
+
y = coords[i + 1];
|
|
36865
|
+
coordinates.push([x, y]);
|
|
36866
|
+
}
|
|
36867
|
+
for (i=0; i<offsets.length; i+=2) {
|
|
36868
|
+
x += offsets[i];
|
|
36869
|
+
y += offsets[i + 1];
|
|
36870
|
+
coordinates.push([x, y]);
|
|
36871
|
+
}
|
|
36872
|
+
if (GeoJSON.pathIsRing(coordinates)) {
|
|
36873
|
+
type = 'Polygon';
|
|
36874
|
+
} else if (opts.closed && coordinates.length >= 3) {
|
|
36875
|
+
type = 'Polygon';
|
|
36876
|
+
coordinates.push(coordinates[0]);
|
|
36877
|
+
} else {
|
|
36878
|
+
type = 'LineString';
|
|
36879
|
+
}
|
|
36880
|
+
return {
|
|
36881
|
+
type: type,
|
|
36882
|
+
coordinates: type == 'Polygon' ? [coordinates] : coordinates
|
|
36883
|
+
};
|
|
36884
|
+
|
|
36885
|
+
}
|
|
36886
|
+
|
|
36647
36887
|
function calcSimplifyStats(arcs, use3D) {
|
|
36648
36888
|
var distSq = use3D ? pointSegGeoDistSq : geom.pointSegDistSq,
|
|
36649
36889
|
calcAngle = use3D ? geom.signedAngleSph : geom.signedAngle,
|
|
@@ -37731,144 +37971,431 @@ ${svg}
|
|
|
37731
37971
|
});
|
|
37732
37972
|
};
|
|
37733
37973
|
|
|
37734
|
-
|
|
37735
|
-
var len = 'length' in d ? d.length : 10;
|
|
37736
|
-
var filled = 'fill' in d;
|
|
37737
|
-
return filled ? getFilledArrow(d, len) : getStickArrow(d, len);
|
|
37738
|
-
};
|
|
37974
|
+
var roundCoord = getRoundingFunction(0.01);
|
|
37739
37975
|
|
|
37740
|
-
function
|
|
37741
|
-
|
|
37742
|
-
|
|
37743
|
-
|
|
37744
|
-
|
|
37745
|
-
|
|
37746
|
-
}
|
|
37976
|
+
function forEachSymbolCoord(coords, cb) {
|
|
37977
|
+
var isPoint = coords && utils.isNumber(coords[0]);
|
|
37978
|
+
var isNested = !isPoint && coords && Array.isArray(coords[0]);
|
|
37979
|
+
if (isPoint) return cb(coords);
|
|
37980
|
+
for (var i=0; i<coords.length; i++) {
|
|
37981
|
+
if (isNested) forEachSymbolCoord(coords[i], cb);
|
|
37982
|
+
}
|
|
37747
37983
|
}
|
|
37748
37984
|
|
|
37749
|
-
function
|
|
37750
|
-
|
|
37751
|
-
|
|
37752
|
-
|
|
37753
|
-
fill: d.fill || 'magenta'
|
|
37754
|
-
};
|
|
37985
|
+
function flipY(coords) {
|
|
37986
|
+
forEachSymbolCoord(coords, function(p) {
|
|
37987
|
+
p[1] = -p[1];
|
|
37988
|
+
});
|
|
37755
37989
|
}
|
|
37756
37990
|
|
|
37757
|
-
function
|
|
37758
|
-
|
|
37759
|
-
|
|
37760
|
-
|
|
37761
|
-
|
|
37991
|
+
function scaleAndShiftCoords(coords, scale, shift) {
|
|
37992
|
+
forEachSymbolCoord(coords, function(xy) {
|
|
37993
|
+
xy[0] = xy[0] * scale + shift[0];
|
|
37994
|
+
xy[1] = xy[1] * scale + shift[1];
|
|
37995
|
+
});
|
|
37996
|
+
}
|
|
37997
|
+
|
|
37998
|
+
function roundCoordsForSVG(coords) {
|
|
37999
|
+
forEachSymbolCoord(coords, function(p) {
|
|
38000
|
+
p[0] = roundCoord(p[0]);
|
|
38001
|
+
p[1] = roundCoord(p[1]);
|
|
38002
|
+
});
|
|
38003
|
+
}
|
|
38004
|
+
|
|
38005
|
+
function rotateCoords(coords, rotation) {
|
|
38006
|
+
if (!rotation) return;
|
|
38007
|
+
var f = getAffineTransform(rotation, 1, [0, 0], [0, 0]);
|
|
38008
|
+
forEachSymbolCoord(coords, function(p) {
|
|
38009
|
+
var p2 = f(p[0], p[1]);
|
|
38010
|
+
p[0] = p2[0];
|
|
38011
|
+
p[1] = p2[1];
|
|
38012
|
+
});
|
|
38013
|
+
}
|
|
38014
|
+
|
|
38015
|
+
function findArcCenter(p1, p2, degrees) {
|
|
38016
|
+
var p3 = [(p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2], // midpoint betw. p1, p2
|
|
38017
|
+
tan = 1 / Math.tan(degrees / 180 * Math.PI / 2),
|
|
38018
|
+
cp = getAffineTransform(90, tan, [0, 0], p3)(p2[0], p2[1]);
|
|
38019
|
+
return cp;
|
|
38020
|
+
}
|
|
38021
|
+
|
|
38022
|
+
// export function addBezierArcControlPoints(p1, p2, degrees) {
|
|
38023
|
+
function addBezierArcControlPoints(points, degrees) {
|
|
38024
|
+
// source: https://stackoverflow.com/questions/734076/how-to-best-approximate-a-geometrical-arc-with-a-bezier-curve
|
|
38025
|
+
var p2 = points.pop(),
|
|
38026
|
+
p1 = points.pop(),
|
|
38027
|
+
cp = findArcCenter(p1, p2, degrees),
|
|
38028
|
+
xc = cp[0],
|
|
38029
|
+
yc = cp[1],
|
|
38030
|
+
ax = p1[0] - xc,
|
|
38031
|
+
ay = p1[1] - yc,
|
|
38032
|
+
bx = p2[0] - xc,
|
|
38033
|
+
by = p2[1] - yc,
|
|
38034
|
+
q1 = ax * ax + ay * ay,
|
|
38035
|
+
q2 = q1 + ax * bx + ay * by,
|
|
38036
|
+
k2 = 4/3 * (Math.sqrt(2 * q1 * q2) - q2) / (ax * by - ay * bx);
|
|
38037
|
+
|
|
38038
|
+
points.push(p1);
|
|
38039
|
+
points.push([xc + ax - k2 * ay, yc + ay + k2 * ax, 'C']);
|
|
38040
|
+
points.push([xc + bx + k2 * by, yc + by - k2 * bx, 'C']);
|
|
38041
|
+
points.push(p2);
|
|
38042
|
+
}
|
|
38043
|
+
|
|
38044
|
+
// export function getStickArrowCoords(d, totalLen) {
|
|
38045
|
+
// var minStemRatio = getMinStemRatio(d);
|
|
38046
|
+
// var headAngle = d['arrow-head-angle'] || 90;
|
|
38047
|
+
// var curve = d['arrow-stem-curve'] || 0;
|
|
38048
|
+
// var unscaledHeadWidth = d['arrow-head-width'] || 9;
|
|
38049
|
+
// var unscaledHeadLen = getHeadLength(unscaledHeadWidth, headAngle);
|
|
38050
|
+
// var scale = getScale(totalLen, unscaledHeadLen, minStemRatio);
|
|
38051
|
+
// var headWidth = unscaledHeadWidth * scale;
|
|
38052
|
+
// var headLen = unscaledHeadLen * scale;
|
|
38053
|
+
// var tip = getStickArrowTip(totalLen, curve);
|
|
38054
|
+
// var stem = [[0, 0], tip.concat()];
|
|
38055
|
+
// if (curve) {
|
|
38056
|
+
// addBezierArcControlPoints(stem, curve);
|
|
38057
|
+
// }
|
|
38058
|
+
// if (!headLen) return [stem];
|
|
38059
|
+
// var head = [addPoints([-headWidth / 2, -headLen], tip), tip.concat(), addPoints([headWidth / 2, -headLen], tip)];
|
|
38060
|
+
|
|
38061
|
+
// rotateCoords(stem, d.rotation);
|
|
38062
|
+
// rotateCoords(head, d.rotation);
|
|
38063
|
+
// return [stem, head];
|
|
38064
|
+
// }
|
|
38065
|
+
|
|
38066
|
+
|
|
38067
|
+
function getFilledArrowCoords(d) {
|
|
38068
|
+
var direction = d.rotation || d.direction || 0,
|
|
38069
|
+
stemTaper = d['stem-taper'] || 0,
|
|
38070
|
+
stemCurve = d['stem-curve'] || 0,
|
|
38071
|
+
size = calcArrowSize(d);
|
|
38072
|
+
|
|
38073
|
+
if (!size) return null;
|
|
38074
|
+
|
|
38075
|
+
var headDx = size.headWidth / 2,
|
|
38076
|
+
stemDx = size.stemWidth / 2,
|
|
38077
|
+
baseDx = stemDx * (1 - stemTaper),
|
|
38078
|
+
coords;
|
|
38079
|
+
|
|
38080
|
+
if (!stemCurve || Math.abs(stemCurve) > 90) {
|
|
38081
|
+
coords = calcStraightArrowCoords(size.stemLen, size.headLen, stemDx, headDx, baseDx);
|
|
38082
|
+
} else {
|
|
38083
|
+
if (direction > 0) stemCurve = -stemCurve;
|
|
38084
|
+
coords = getCurvedArrowCoords(size.stemLen, size.headLen, size.stemCurve, stemDx, headDx, baseDx);
|
|
37762
38085
|
}
|
|
37763
|
-
|
|
38086
|
+
|
|
38087
|
+
rotateCoords(coords, direction);
|
|
38088
|
+
if (d.flipped) {
|
|
38089
|
+
flipY(coords);
|
|
38090
|
+
}
|
|
38091
|
+
return [coords];
|
|
37764
38092
|
}
|
|
37765
38093
|
|
|
37766
|
-
function
|
|
37767
|
-
|
|
37768
|
-
|
|
37769
|
-
var dx = totalLen * Math.sin(theta) * (curve > 0 ? -1 : 1);
|
|
37770
|
-
var dy = totalLen * Math.cos(theta);
|
|
37771
|
-
return [dx, dy];
|
|
38094
|
+
function calcStraightArrowCoords(stemLen, headLen, stemDx, headDx, baseDx) {
|
|
38095
|
+
return [[baseDx, 0], [stemDx, stemLen], [headDx, stemLen], [0, stemLen + headLen],
|
|
38096
|
+
[-headDx, stemLen], [-stemDx, stemLen], [-baseDx, 0], [baseDx, 0]];
|
|
37772
38097
|
}
|
|
37773
38098
|
|
|
37774
|
-
function
|
|
37775
|
-
|
|
38099
|
+
function calcArrowSize(d) {
|
|
38100
|
+
var totalLen = d.radius || d.length || d.r || 0,
|
|
38101
|
+
unscaledStemWidth = d['stem-width'] || 2,
|
|
38102
|
+
unscaledHeadWidth = d['head-width'] || unscaledStemWidth * 3,
|
|
38103
|
+
unscaledHeadLen = d['head-length'] || calcHeadLength(unscaledHeadWidth, d),
|
|
38104
|
+
scale = 1,
|
|
38105
|
+
o = {};
|
|
38106
|
+
|
|
38107
|
+
if (totalLen > 0) {
|
|
38108
|
+
scale = calcScale(totalLen, unscaledHeadLen, d);
|
|
38109
|
+
o.headWidth = unscaledHeadWidth * scale;
|
|
38110
|
+
o.headLen = unscaledHeadLen * scale;
|
|
38111
|
+
o.stemWidth = unscaledStemWidth * scale;
|
|
38112
|
+
o.stemLen = totalLen - o.headLen;
|
|
38113
|
+
|
|
38114
|
+
} else {
|
|
38115
|
+
o.headWidth = unscaledHeadWidth;
|
|
38116
|
+
o.headLen = unscaledHeadLen;
|
|
38117
|
+
o.stemWidth = unscaledStemWidth;
|
|
38118
|
+
o.stemLen = d['stem-length'] || 0;
|
|
38119
|
+
}
|
|
38120
|
+
|
|
38121
|
+
if (unscaledHeadWidth < unscaledStemWidth) {
|
|
38122
|
+
stop('Arrow head must be at least as wide as the stem.');
|
|
38123
|
+
}
|
|
38124
|
+
return o;
|
|
37776
38125
|
}
|
|
37777
38126
|
|
|
37778
|
-
function
|
|
37779
|
-
var
|
|
37780
|
-
var
|
|
37781
|
-
var
|
|
37782
|
-
var
|
|
37783
|
-
var scale =
|
|
37784
|
-
|
|
37785
|
-
|
|
37786
|
-
|
|
37787
|
-
|
|
37788
|
-
|
|
37789
|
-
addBezierArcControlPoints(stem, curve);
|
|
38127
|
+
function calcScale(totalLen, headLen, d) {
|
|
38128
|
+
var minStemRatio = d['min-stem'] >= 0 ? d['min-stem'] : 0;
|
|
38129
|
+
var stemLen = d['stem-length'] || 0;
|
|
38130
|
+
var maxHeadPct = 1 - minStemRatio;
|
|
38131
|
+
var headPct = headLen / totalLen;
|
|
38132
|
+
var scale = 1;
|
|
38133
|
+
|
|
38134
|
+
if (headPct > maxHeadPct) {
|
|
38135
|
+
scale = maxHeadPct / headPct;
|
|
38136
|
+
} else if (stemLen + headLen > totalLen) {
|
|
38137
|
+
scale = totalLen / (stemLen + headLen);
|
|
37790
38138
|
}
|
|
37791
|
-
|
|
37792
|
-
|
|
38139
|
+
return scale;
|
|
38140
|
+
}
|
|
37793
38141
|
|
|
37794
|
-
|
|
37795
|
-
|
|
37796
|
-
|
|
38142
|
+
// function getStickArrowTip(totalLen, curve) {
|
|
38143
|
+
// // curve/2 intersects the arrowhead at 90deg (trigonometry)
|
|
38144
|
+
// var theta = Math.abs(curve/2) / 180 * Math.PI;
|
|
38145
|
+
// var dx = totalLen * Math.sin(theta) * (curve > 0 ? -1 : 1);
|
|
38146
|
+
// var dy = totalLen * Math.cos(theta);
|
|
38147
|
+
// return [dx, dy];
|
|
38148
|
+
// }
|
|
38149
|
+
|
|
38150
|
+
function addPoints(a, b) {
|
|
38151
|
+
return [a[0] + b[0], a[1] + b[1]];
|
|
37797
38152
|
}
|
|
37798
38153
|
|
|
37799
|
-
|
|
38154
|
+
|
|
38155
|
+
function calcHeadLength(headWidth, d) {
|
|
38156
|
+
var headAngle = d['head-angle'] || 40;
|
|
37800
38157
|
var headRatio = 1 / Math.tan(Math.PI * headAngle / 180 / 2) / 2; // length-to-width head ratio
|
|
37801
38158
|
return headWidth * headRatio;
|
|
37802
38159
|
}
|
|
37803
38160
|
|
|
37804
|
-
function
|
|
37805
|
-
|
|
37806
|
-
|
|
37807
|
-
|
|
37808
|
-
|
|
37809
|
-
|
|
37810
|
-
|
|
37811
|
-
|
|
37812
|
-
|
|
37813
|
-
|
|
37814
|
-
|
|
37815
|
-
|
|
37816
|
-
var
|
|
37817
|
-
|
|
37818
|
-
|
|
37819
|
-
|
|
37820
|
-
|
|
37821
|
-
|
|
38161
|
+
function getCurvedArrowCoords(stemLen, headLen, curvature, stemDx, headDx, baseDx) {
|
|
38162
|
+
// coordinates go counter clockwise, starting from the leftmost head coordinate
|
|
38163
|
+
var theta = Math.abs(curvature) / 180 * Math.PI;
|
|
38164
|
+
var sign = curvature > 0 ? 1 : -1;
|
|
38165
|
+
var dx = stemLen * Math.sin(theta / 2) * sign;
|
|
38166
|
+
var dy = stemLen * Math.cos(theta / 2);
|
|
38167
|
+
var head = [[stemDx + dx, dy], [headDx + dx, dy],
|
|
38168
|
+
[dx, headLen + dy], [-headDx + dx, dy], [-stemDx + dx, dy]];
|
|
38169
|
+
var ax = baseDx * Math.cos(theta); // rotate arrow base
|
|
38170
|
+
var ay = baseDx * Math.sin(theta) * -sign;
|
|
38171
|
+
var leftStem = getCurvedStemCoords(-ax, -ay, -stemDx + dx, dy, theta);
|
|
38172
|
+
var rightStem = getCurvedStemCoords(ax, ay, stemDx + dx, dy, theta);
|
|
38173
|
+
var stem = leftStem.concat(rightStem.reverse());
|
|
38174
|
+
// stem.pop();
|
|
38175
|
+
return stem.concat(head);
|
|
38176
|
+
}
|
|
38177
|
+
|
|
38178
|
+
// ax, ay: point on the base
|
|
38179
|
+
// bx, by: point on the stem
|
|
38180
|
+
function getCurvedStemCoords(ax, ay, bx, by, theta0) {
|
|
38181
|
+
// case: curved side intrudes into head (because stem is too short)
|
|
38182
|
+
if (ay > by) {
|
|
38183
|
+
return [[ax * by / ay, by]];
|
|
38184
|
+
}
|
|
38185
|
+
var dx = bx - ax,
|
|
38186
|
+
dy = by - ay,
|
|
38187
|
+
dy1 = (dy * dy - dx * dx) / (2 * dy),
|
|
38188
|
+
dy2 = dy - dy1,
|
|
38189
|
+
dx2 = Math.sqrt(dx * dx + dy * dy) / 2,
|
|
38190
|
+
theta = Math.PI - Math.asin(dx2 / dy2) * 2,
|
|
38191
|
+
degrees = theta * 180 / Math.PI,
|
|
38192
|
+
radius = dy2 / Math.tan(theta / 2),
|
|
38193
|
+
leftBend = bx > ax,
|
|
38194
|
+
sign = leftBend ? 1 : -1,
|
|
38195
|
+
points = Math.round(degrees / 5) + 2,
|
|
38196
|
+
increment = theta / (points + 1),
|
|
38197
|
+
coords = [[bx, by]];
|
|
38198
|
+
|
|
38199
|
+
for (var i=1; i<= points; i++) {
|
|
38200
|
+
var phi = i * increment / 2;
|
|
38201
|
+
var sinPhi = Math.sin(phi);
|
|
38202
|
+
var cosPhi = Math.cos(phi);
|
|
38203
|
+
var c = sinPhi * radius * 2;
|
|
38204
|
+
var a = sinPhi * c;
|
|
38205
|
+
var b = cosPhi * c;
|
|
38206
|
+
coords.push([bx - a * sign, by - b]);
|
|
38207
|
+
}
|
|
38208
|
+
coords.push([ax, ay]);
|
|
38209
|
+
return coords;
|
|
38210
|
+
}
|
|
37822
38211
|
|
|
37823
|
-
|
|
38212
|
+
// sides: e.g. 5-pointed star has 10 sides
|
|
38213
|
+
// radius: distance from center to point
|
|
38214
|
+
//
|
|
38215
|
+
function getPolygonCoords(d) {
|
|
38216
|
+
var radius = d.radius || d.length || d.r;
|
|
38217
|
+
if (radius > 0 === false) return null;
|
|
38218
|
+
var type = d.type;
|
|
38219
|
+
var sides = +d.sides || getDefaultSides(type);
|
|
38220
|
+
var isStar = type == 'star';
|
|
38221
|
+
if (isStar && (sides < 6 || sides % 2 !== 0)) {
|
|
38222
|
+
stop(`Invalid number of sides for a star (${sides})`);
|
|
38223
|
+
} else if (sides >= 3 === false) {
|
|
38224
|
+
stop(`Invalid number of sides (${sides})`);
|
|
38225
|
+
}
|
|
38226
|
+
var coords = [],
|
|
38227
|
+
angle = 360 / sides,
|
|
38228
|
+
b = isStar ? 1 : 0.5,
|
|
38229
|
+
theta, even, len;
|
|
38230
|
+
if (d.orientation == 'b' || d.flipped || d.rotated) {
|
|
38231
|
+
b = 0;
|
|
38232
|
+
}
|
|
38233
|
+
for (var i=0; i<sides; i++) {
|
|
38234
|
+
even = i % 2 == 0;
|
|
38235
|
+
len = radius;
|
|
38236
|
+
if (isStar && even) {
|
|
38237
|
+
len *= (d.star_ratio || 0.5);
|
|
38238
|
+
}
|
|
38239
|
+
theta = (i + b) * angle % 360;
|
|
38240
|
+
coords.push(getPlanarSegmentEndpoint(0, 0, theta, len));
|
|
38241
|
+
}
|
|
38242
|
+
coords.push(coords[0].concat());
|
|
37824
38243
|
return [coords];
|
|
37825
38244
|
}
|
|
37826
38245
|
|
|
37827
|
-
function
|
|
37828
|
-
|
|
37829
|
-
|
|
37830
|
-
|
|
37831
|
-
|
|
37832
|
-
|
|
37833
|
-
|
|
37834
|
-
|
|
38246
|
+
function getDefaultSides(type) {
|
|
38247
|
+
return {
|
|
38248
|
+
star: 10,
|
|
38249
|
+
circle: 72,
|
|
38250
|
+
triangle: 3,
|
|
38251
|
+
square: 4,
|
|
38252
|
+
pentagon: 5,
|
|
38253
|
+
hexagon: 6,
|
|
38254
|
+
heptagon: 7,
|
|
38255
|
+
octagon: 8,
|
|
38256
|
+
nonagon: 9,
|
|
38257
|
+
decagon: 10
|
|
38258
|
+
}[type] || 4;
|
|
38259
|
+
}
|
|
38260
|
+
|
|
38261
|
+
// Returns GeoJSON MultiPolygon coords
|
|
38262
|
+
function getRingCoords(d) {
|
|
38263
|
+
var radii = parseRings(d.radii || '2');
|
|
38264
|
+
var coords = [];
|
|
38265
|
+
var solidCenter = utils.isOdd(radii.length);
|
|
38266
|
+
var ring, hole;
|
|
38267
|
+
for (var i=0; i<radii.length; i++) {
|
|
38268
|
+
ring = getPolygonCoords({
|
|
38269
|
+
type: 'circle',
|
|
38270
|
+
radius: radii[i]
|
|
38271
|
+
});
|
|
38272
|
+
if (!solidCenter || i > 0) {
|
|
38273
|
+
i++;
|
|
38274
|
+
hole = ring;
|
|
38275
|
+
ring = getPolygonCoords({
|
|
38276
|
+
type: 'circle',
|
|
38277
|
+
radius: radii[i]
|
|
38278
|
+
});
|
|
38279
|
+
ring.push(hole[0]);
|
|
38280
|
+
}
|
|
38281
|
+
coords.push(ring);
|
|
38282
|
+
}
|
|
38283
|
+
return coords;
|
|
38284
|
+
}
|
|
38285
|
+
|
|
38286
|
+
function parseRings(arg) {
|
|
38287
|
+
var arr = Array.isArray(arg) ? arg : parseNumberList(arg);
|
|
38288
|
+
utils.genericSort(arr, true);
|
|
38289
|
+
return utils.uniq(arr);
|
|
37835
38290
|
}
|
|
37836
38291
|
|
|
37837
38292
|
// TODO: refactor to remove duplication in mapshaper-svg-style.js
|
|
37838
|
-
cmd.symbols = function(
|
|
37839
|
-
|
|
37840
|
-
|
|
37841
|
-
|
|
37842
|
-
|
|
37843
|
-
if (
|
|
37844
|
-
|
|
37845
|
-
|
|
37846
|
-
|
|
37847
|
-
|
|
37848
|
-
|
|
37849
|
-
|
|
37850
|
-
|
|
38293
|
+
cmd.symbols = function(inputLyr, dataset, opts) {
|
|
38294
|
+
requireSinglePointLayer(inputLyr);
|
|
38295
|
+
var lyr = opts.no_replace ? copyLayer(inputLyr) : inputLyr;
|
|
38296
|
+
var polygonMode = !!opts.polygons;
|
|
38297
|
+
var metersPerPx;
|
|
38298
|
+
if (polygonMode) {
|
|
38299
|
+
requireProjectedDataset(dataset);
|
|
38300
|
+
metersPerPx = opts.pixel_scale || getMetersPerPixel(lyr, dataset);
|
|
38301
|
+
}
|
|
38302
|
+
var records = getLayerDataTable(lyr).getRecords();
|
|
38303
|
+
var getSymbolData = getSymbolDataAccessor(lyr, opts);
|
|
38304
|
+
var geometries = lyr.shapes.map(function(shp, i) {
|
|
38305
|
+
if (!shp) return null;
|
|
38306
|
+
var d = getSymbolData(i);
|
|
38307
|
+
var rec = records[i] || {};
|
|
38308
|
+
var geojsonType = 'Polygon';
|
|
38309
|
+
var coords;
|
|
38310
|
+
if (d.type == 'arrow') {
|
|
38311
|
+
coords = getFilledArrowCoords(d);
|
|
38312
|
+
} else if (d.type == 'ring') {
|
|
38313
|
+
coords = getRingCoords(d);
|
|
38314
|
+
geojsonType = 'MultiPolygon';
|
|
37851
38315
|
} else {
|
|
37852
|
-
|
|
38316
|
+
coords = getPolygonCoords(d);
|
|
38317
|
+
}
|
|
38318
|
+
if (!coords) return null;
|
|
38319
|
+
rotateCoords(coords, +d.rotation || 0);
|
|
38320
|
+
if (!polygonMode) {
|
|
38321
|
+
flipY(coords);
|
|
38322
|
+
}
|
|
38323
|
+
if (+opts.scale) {
|
|
38324
|
+
scaleAndShiftCoords(coords, +opts.scale, [0, 0]);
|
|
38325
|
+
}
|
|
38326
|
+
if (polygonMode) {
|
|
38327
|
+
scaleAndShiftCoords(coords, metersPerPx, shp[0]);
|
|
38328
|
+
if (d.tfill) rec.fill = d.fill;
|
|
38329
|
+
return createGeometry(coords, geojsonType);
|
|
38330
|
+
} else {
|
|
38331
|
+
rec['svg-symbol'] = makeSvgPolygonSymbol(coords, d, geojsonType);
|
|
37853
38332
|
}
|
|
37854
38333
|
});
|
|
38334
|
+
|
|
38335
|
+
var outputLyr, dataset2;
|
|
38336
|
+
if (polygonMode) {
|
|
38337
|
+
dataset2 = importGeometries(geometries, records);
|
|
38338
|
+
outputLyr = mergeOutputLayerIntoDataset(inputLyr, dataset, dataset2, opts);
|
|
38339
|
+
outputLyr.data = lyr.data;
|
|
38340
|
+
} else {
|
|
38341
|
+
outputLyr = lyr;
|
|
38342
|
+
}
|
|
38343
|
+
return [outputLyr];
|
|
37855
38344
|
};
|
|
37856
38345
|
|
|
38346
|
+
function importGeometries(geometries, records) {
|
|
38347
|
+
var features = geometries.map(function(geom, i) {
|
|
38348
|
+
var d = records[i];
|
|
38349
|
+
return {
|
|
38350
|
+
type: 'Feature',
|
|
38351
|
+
properties: records[i] || null,
|
|
38352
|
+
geometry: geom
|
|
38353
|
+
};
|
|
38354
|
+
});
|
|
38355
|
+
var geojson = {
|
|
38356
|
+
type: 'FeatureCollection',
|
|
38357
|
+
features: features
|
|
38358
|
+
};
|
|
38359
|
+
return importGeoJSON(geojson);
|
|
38360
|
+
}
|
|
38361
|
+
|
|
38362
|
+
function createGeometry(coords, type) {
|
|
38363
|
+
return {
|
|
38364
|
+
type: type,
|
|
38365
|
+
coordinates: coords
|
|
38366
|
+
};
|
|
38367
|
+
}
|
|
38368
|
+
|
|
38369
|
+
function getMetersPerPixel(lyr, dataset) {
|
|
38370
|
+
|
|
38371
|
+
// TODO: handle single point, no extent
|
|
38372
|
+
var bounds = getLayerBounds(lyr);
|
|
38373
|
+
return bounds.width() / 800;
|
|
38374
|
+
}
|
|
38375
|
+
|
|
37857
38376
|
// Returns an svg-symbol data object for one symbol
|
|
37858
|
-
function
|
|
37859
|
-
|
|
37860
|
-
|
|
37861
|
-
if (
|
|
37862
|
-
|
|
37863
|
-
} else if (!f) {
|
|
37864
|
-
stop('Unknown symbol type:', type);
|
|
38377
|
+
function makeSvgPolygonSymbol(coords, properties, geojsonType) {
|
|
38378
|
+
if (geojsonType == 'MultiPolygon') {
|
|
38379
|
+
coords = convertMultiPolygonCoords(coords);
|
|
38380
|
+
} else if (geojsonType != 'Polygon') {
|
|
38381
|
+
error('Unsupported type:', geojsonType);
|
|
37865
38382
|
}
|
|
37866
|
-
|
|
38383
|
+
roundCoordsForSVG(coords);
|
|
38384
|
+
return {
|
|
38385
|
+
type: 'polygon',
|
|
38386
|
+
coordinates: coords,
|
|
38387
|
+
fill: properties.fill || 'magenta'
|
|
38388
|
+
};
|
|
38389
|
+
}
|
|
38390
|
+
|
|
38391
|
+
function convertMultiPolygonCoords(coords) {
|
|
38392
|
+
return coords.reduce(function(memo, poly) {
|
|
38393
|
+
return memo.concat(poly);
|
|
38394
|
+
}, []);
|
|
37867
38395
|
}
|
|
37868
38396
|
|
|
37869
38397
|
var Symbols = /*#__PURE__*/Object.freeze({
|
|
37870
|
-
__proto__: null
|
|
37871
|
-
buildSymbol: buildSymbol
|
|
38398
|
+
__proto__: null
|
|
37872
38399
|
});
|
|
37873
38400
|
|
|
37874
38401
|
cmd.target = function(catalog, opts) {
|
|
@@ -38014,99 +38541,6 @@ ${svg}
|
|
|
38014
38541
|
}
|
|
38015
38542
|
};
|
|
38016
38543
|
|
|
38017
|
-
cmd.shape = function(targetDataset, opts) {
|
|
38018
|
-
var geojson, dataset;
|
|
38019
|
-
if (opts.coordinates) {
|
|
38020
|
-
geojson = makeShapeFromCoords(opts);
|
|
38021
|
-
} else if (opts.type == 'circle') {
|
|
38022
|
-
geojson = makeCircle(opts);
|
|
38023
|
-
} else if (opts.type == 'rectangle' && opts.bbox) {
|
|
38024
|
-
geojson = getRectangleGeoJSON(opts);
|
|
38025
|
-
} else {
|
|
38026
|
-
stop('Missing coordinates parameter');
|
|
38027
|
-
}
|
|
38028
|
-
// TODO: project shape if targetDataset is projected
|
|
38029
|
-
dataset = importGeoJSON(geojson, {});
|
|
38030
|
-
if (opts.rotation) {
|
|
38031
|
-
rotateDatasetCoords(dataset, opts.rotation);
|
|
38032
|
-
}
|
|
38033
|
-
dataset.layers[0].name = opts.name || opts.type || 'shape';
|
|
38034
|
-
return dataset;
|
|
38035
|
-
};
|
|
38036
|
-
|
|
38037
|
-
function getRectangleGeoJSON(opts) {
|
|
38038
|
-
var bbox = opts.bbox,
|
|
38039
|
-
xmin = bbox[0],
|
|
38040
|
-
ymin = bbox[1],
|
|
38041
|
-
xmax = bbox[2],
|
|
38042
|
-
ymax = bbox[3],
|
|
38043
|
-
interval = 0.5,
|
|
38044
|
-
coords = [],
|
|
38045
|
-
type = opts.geometry == 'polyline' ? 'LineString' : 'Polygon';
|
|
38046
|
-
addSide(xmin, ymin, xmin, ymax);
|
|
38047
|
-
addSide(xmin, ymax, xmax, ymax);
|
|
38048
|
-
addSide(xmax, ymax, xmax, ymin);
|
|
38049
|
-
addSide(xmax, ymin, xmin, ymin);
|
|
38050
|
-
coords.push([xmin, ymin]);
|
|
38051
|
-
return {
|
|
38052
|
-
type: type,
|
|
38053
|
-
coordinates: type == 'Polygon' ? [coords] : coords
|
|
38054
|
-
};
|
|
38055
|
-
|
|
38056
|
-
function addSide(x1, y1, x2, y2) {
|
|
38057
|
-
var dx = x2 - x1,
|
|
38058
|
-
dy = y2 - y1,
|
|
38059
|
-
n = Math.ceil(Math.max(Math.abs(dx) / interval, Math.abs(dy) / interval)),
|
|
38060
|
-
xint = dx / n,
|
|
38061
|
-
yint = dy / n;
|
|
38062
|
-
for (var i=0; i<n; i++) {
|
|
38063
|
-
coords.push([x1 + i * xint, y1 + i * yint]);
|
|
38064
|
-
}
|
|
38065
|
-
}
|
|
38066
|
-
}
|
|
38067
|
-
|
|
38068
|
-
function makeCircle(opts) {
|
|
38069
|
-
if (opts.radius > 0 === false && opts.radius_angle > 0 === false) {
|
|
38070
|
-
stop('Missing required radius parameter.');
|
|
38071
|
-
}
|
|
38072
|
-
var cp = opts.center || [0, 0];
|
|
38073
|
-
var radius = opts.radius || getCircleRadiusFromAngle(getCRS('wgs84'), opts.radius_angle);
|
|
38074
|
-
return getCircleGeoJSON(cp, radius, null, {geometry_type : opts.geometry || 'polygon'});
|
|
38075
|
-
}
|
|
38076
|
-
|
|
38077
|
-
function makeShapeFromCoords(opts) {
|
|
38078
|
-
var coordinates = [];
|
|
38079
|
-
var offsets = opts.offsets || [];
|
|
38080
|
-
var coords = opts.coordinates;
|
|
38081
|
-
var type, i, x, y;
|
|
38082
|
-
if (coords.length >= 2 === false) {
|
|
38083
|
-
stop('Invalid coordinates parameter.');
|
|
38084
|
-
}
|
|
38085
|
-
for (i=0; i<coords.length; i+= 2) {
|
|
38086
|
-
x = coords[i];
|
|
38087
|
-
y = coords[i + 1];
|
|
38088
|
-
coordinates.push([x, y]);
|
|
38089
|
-
}
|
|
38090
|
-
for (i=0; i<offsets.length; i+=2) {
|
|
38091
|
-
x += offsets[i];
|
|
38092
|
-
y += offsets[i + 1];
|
|
38093
|
-
coordinates.push([x, y]);
|
|
38094
|
-
}
|
|
38095
|
-
if (GeoJSON.pathIsRing(coordinates)) {
|
|
38096
|
-
type = 'Polygon';
|
|
38097
|
-
} else if (opts.closed && coordinates.length >= 3) {
|
|
38098
|
-
type = 'Polygon';
|
|
38099
|
-
coordinates.push(coordinates[0]);
|
|
38100
|
-
} else {
|
|
38101
|
-
type = 'LineString';
|
|
38102
|
-
}
|
|
38103
|
-
return {
|
|
38104
|
-
type: type,
|
|
38105
|
-
coordinates: type == 'Polygon' ? [coordinates] : coordinates
|
|
38106
|
-
};
|
|
38107
|
-
|
|
38108
|
-
}
|
|
38109
|
-
|
|
38110
38544
|
cmd.variableSimplify = function(layers, dataset, opts) {
|
|
38111
38545
|
var lyr = layers[0];
|
|
38112
38546
|
var arcs = dataset.arcs;
|
|
@@ -38648,6 +39082,9 @@ ${svg}
|
|
|
38648
39082
|
} else if (name == 'shape') {
|
|
38649
39083
|
catalog.addDataset(cmd.shape(targetDataset, opts));
|
|
38650
39084
|
|
|
39085
|
+
} else if (name == 'shapes') {
|
|
39086
|
+
outputLayers = applyCommandToEachLayer(cmd.shapes, targetLayers, targetDataset, opts);
|
|
39087
|
+
|
|
38651
39088
|
} else if (name == 'simplify') {
|
|
38652
39089
|
if (opts.variable) {
|
|
38653
39090
|
cmd.variableSimplify(targetLayers, targetDataset, opts);
|
|
@@ -38677,7 +39114,7 @@ ${svg}
|
|
|
38677
39114
|
applyCommandToEachLayer(cmd.svgStyle, targetLayers, targetDataset, opts);
|
|
38678
39115
|
|
|
38679
39116
|
} else if (name == 'symbols') {
|
|
38680
|
-
applyCommandToEachLayer(cmd.symbols, targetLayers, opts);
|
|
39117
|
+
outputLayers = applyCommandToEachLayer(cmd.symbols, targetLayers, targetDataset, opts);
|
|
38681
39118
|
|
|
38682
39119
|
} else if (name == 'subdivide') {
|
|
38683
39120
|
outputLayers = applyCommandToEachLayer(cmd.subdivideLayer, targetLayers, arcs, opts.expression);
|