mapshaper 0.5.80 → 0.5.84
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 +356 -158
- package/package.json +1 -1
- package/www/mapshaper-gui.js +0 -1
- package/www/mapshaper.js +356 -158
package/www/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.5.
|
|
3
|
+
var VERSION = "0.5.83";
|
|
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.
|
|
@@ -2359,6 +2369,12 @@
|
|
|
2359
2369
|
}, 0);
|
|
2360
2370
|
}
|
|
2361
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
|
+
|
|
2362
2378
|
// Return true if point is inside or on boundary of a shape
|
|
2363
2379
|
//
|
|
2364
2380
|
function testPointInPolygon(x, y, shp, arcs) {
|
|
@@ -13692,14 +13708,18 @@
|
|
|
13692
13708
|
length: 'number', // e.g. arrow length
|
|
13693
13709
|
rotation: 'number',
|
|
13694
13710
|
radius: 'number',
|
|
13695
|
-
|
|
13696
|
-
|
|
13697
|
-
|
|
13698
|
-
|
|
13699
|
-
'
|
|
13700
|
-
'
|
|
13701
|
-
'
|
|
13702
|
-
'
|
|
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-ratio': 'number',
|
|
13703
13723
|
'arrow-scaling': 'number',
|
|
13704
13724
|
effect: null // e.g. "fade"
|
|
13705
13725
|
}, stylePropertyTypes);
|
|
@@ -13735,6 +13755,7 @@
|
|
|
13735
13755
|
function getSymbolDataAccessor(lyr, opts) {
|
|
13736
13756
|
var functions = {};
|
|
13737
13757
|
var properties = [];
|
|
13758
|
+
var fields = lyr.data ? lyr.data.getFields() : [];
|
|
13738
13759
|
|
|
13739
13760
|
Object.keys(opts).forEach(function(optName) {
|
|
13740
13761
|
var svgName = optName.replace(/_/g, '-');
|
|
@@ -13746,6 +13767,8 @@
|
|
|
13746
13767
|
properties.push(svgName);
|
|
13747
13768
|
});
|
|
13748
13769
|
|
|
13770
|
+
// TODO: consider applying values of existing fields with names of symbol properties
|
|
13771
|
+
|
|
13749
13772
|
return function(id) {
|
|
13750
13773
|
var d = {}, name;
|
|
13751
13774
|
for (var i=0; i<properties.length; i++) {
|
|
@@ -13761,8 +13784,9 @@
|
|
|
13761
13784
|
// * ???
|
|
13762
13785
|
//
|
|
13763
13786
|
function mightBeExpression(str, fields) {
|
|
13787
|
+
fields = fields || [];
|
|
13764
13788
|
if (fields.indexOf(str.trim()) > -1) return true;
|
|
13765
|
-
return /[(){}
|
|
13789
|
+
return /[(){}./*?:&|=\[+-]/.test(str);
|
|
13766
13790
|
}
|
|
13767
13791
|
|
|
13768
13792
|
function getSymbolPropertyAccessor(val, svgName, lyr) {
|
|
@@ -13783,6 +13807,7 @@
|
|
|
13783
13807
|
// treating the string as a literal value
|
|
13784
13808
|
literalVal = strVal;
|
|
13785
13809
|
}
|
|
13810
|
+
// console.log("literalVal:", mightBeExpression(strVal, fields), strVal, fields)
|
|
13786
13811
|
if (accessor) return accessor;
|
|
13787
13812
|
if (literalVal !== null) return function(id) {return literalVal;};
|
|
13788
13813
|
stop('Unexpected value for', svgName + ':', strVal);
|
|
@@ -13816,6 +13841,8 @@
|
|
|
13816
13841
|
val = isDashArray(strVal) ? strVal : null;
|
|
13817
13842
|
} else if (type == 'pattern') {
|
|
13818
13843
|
val = isPattern(strVal) ? strVal : null;
|
|
13844
|
+
} else if (type == 'boolean') {
|
|
13845
|
+
val = parseBoolean(strVal);
|
|
13819
13846
|
}
|
|
13820
13847
|
// else {
|
|
13821
13848
|
// // unknown type -- assume literal value
|
|
@@ -13836,10 +13863,17 @@
|
|
|
13836
13863
|
return /^( ?[_a-z][-_a-z0-9]*\b)+$/i.test(str);
|
|
13837
13864
|
}
|
|
13838
13865
|
|
|
13866
|
+
|
|
13839
13867
|
function isSvgNumber(o) {
|
|
13840
13868
|
return utils.isFiniteNumber(o) || utils.isString(o) && /^-?[.0-9]+$/.test(o);
|
|
13841
13869
|
}
|
|
13842
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
|
+
|
|
13843
13877
|
function isSvgMeasure(o) {
|
|
13844
13878
|
return utils.isFiniteNumber(o) || utils.isString(o) && /^-?[.0-9]+[a-z]*$/.test(o);
|
|
13845
13879
|
}
|
|
@@ -13863,6 +13897,7 @@
|
|
|
13863
13897
|
getSymbolPropertyAccessor: getSymbolPropertyAccessor,
|
|
13864
13898
|
isSvgClassName: isSvgClassName,
|
|
13865
13899
|
isSvgNumber: isSvgNumber,
|
|
13900
|
+
parseBoolean: parseBoolean,
|
|
13866
13901
|
isSvgMeasure: isSvgMeasure,
|
|
13867
13902
|
parseSvgMeasure: parseSvgMeasure,
|
|
13868
13903
|
isSvgColor: isSvgColor
|
|
@@ -14081,6 +14116,9 @@
|
|
|
14081
14116
|
o = importLineString(coords[i]);
|
|
14082
14117
|
o.properties.d = d + o.properties.d + ' Z';
|
|
14083
14118
|
}
|
|
14119
|
+
if (coords.length > 1) {
|
|
14120
|
+
o.properties['fill-rule'] = 'evenodd'; // support polygons with holes
|
|
14121
|
+
}
|
|
14084
14122
|
return o;
|
|
14085
14123
|
}
|
|
14086
14124
|
|
|
@@ -17997,6 +18035,10 @@ ${svg}
|
|
|
17997
18035
|
return chunks;
|
|
17998
18036
|
}
|
|
17999
18037
|
|
|
18038
|
+
function parseNumberList(token) {
|
|
18039
|
+
return token.split(',').map(parseFloat);
|
|
18040
|
+
}
|
|
18041
|
+
|
|
18000
18042
|
// Split comma-delimited list, trim quotes from entire list and
|
|
18001
18043
|
// individual members
|
|
18002
18044
|
function parseStringList(token) {
|
|
@@ -18032,9 +18074,9 @@ ${svg}
|
|
|
18032
18074
|
// Updated: don't trim space from tokens like [delimeter= ]
|
|
18033
18075
|
argv = argv.map(function(s) {
|
|
18034
18076
|
if (!/= $/.test(s)) {
|
|
18035
|
-
s =
|
|
18077
|
+
s = utils.rtrim(s);
|
|
18036
18078
|
}
|
|
18037
|
-
s =
|
|
18079
|
+
s = utils.ltrim(s);
|
|
18038
18080
|
return s;
|
|
18039
18081
|
});
|
|
18040
18082
|
argv = argv.filter(function(s) {return s !== '';}); // remove empty tokens
|
|
@@ -18086,6 +18128,7 @@ ${svg}
|
|
|
18086
18128
|
var OptionParsingUtils = /*#__PURE__*/Object.freeze({
|
|
18087
18129
|
__proto__: null,
|
|
18088
18130
|
splitShellTokens: splitShellTokens,
|
|
18131
|
+
parseNumberList: parseNumberList,
|
|
18089
18132
|
parseStringList: parseStringList,
|
|
18090
18133
|
parseColorList: parseColorList,
|
|
18091
18134
|
cleanArgv: cleanArgv,
|
|
@@ -18277,7 +18320,7 @@ ${svg}
|
|
|
18277
18320
|
} else if (type == 'strings') {
|
|
18278
18321
|
val = parseStringList(token);
|
|
18279
18322
|
} else if (type == 'bbox' || type == 'numbers') {
|
|
18280
|
-
val = token
|
|
18323
|
+
val = parseNumberList(token);
|
|
18281
18324
|
} else if (type == 'percent') {
|
|
18282
18325
|
// val = utils.parsePercent(token);
|
|
18283
18326
|
val = token; // string value is parsed by command function
|
|
@@ -20071,42 +20114,73 @@ ${svg}
|
|
|
20071
20114
|
describe: 'sides of a polygon or star symbol',
|
|
20072
20115
|
type: 'number'
|
|
20073
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
|
+
})
|
|
20074
20128
|
.option('rotation', {
|
|
20075
20129
|
describe: 'rotation of symbol in degrees'
|
|
20076
20130
|
})
|
|
20077
|
-
.option('orientation', {
|
|
20078
|
-
describe: 'use orientation=b for a rotated or flipped orientation'
|
|
20079
|
-
})
|
|
20080
20131
|
.option('length', {
|
|
20081
20132
|
// alias for arrow-length
|
|
20082
20133
|
})
|
|
20083
|
-
.option('
|
|
20084
|
-
|
|
20134
|
+
.option('point-ratio', {
|
|
20135
|
+
old_alias: 'star-ratio',
|
|
20136
|
+
describe: '(star) ratio of minor to major radius of star',
|
|
20085
20137
|
type: 'number'
|
|
20086
20138
|
})
|
|
20087
|
-
.option('
|
|
20088
|
-
describe: '
|
|
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'
|
|
20089
20157
|
})
|
|
20090
|
-
.option('
|
|
20091
|
-
|
|
20158
|
+
.option('head-length', {
|
|
20159
|
+
old_alias: 'arrow-head-width',
|
|
20160
|
+
describe: '(arrow) length of head (alternative to head-angle)'
|
|
20092
20161
|
})
|
|
20093
|
-
.option('
|
|
20094
|
-
describe: '
|
|
20162
|
+
.option('head-shape', {
|
|
20163
|
+
// describe: 'options: a b c'
|
|
20095
20164
|
})
|
|
20096
|
-
.option('
|
|
20097
|
-
|
|
20165
|
+
.option('stem-width', {
|
|
20166
|
+
old_alias: 'arrow-stem-width',
|
|
20167
|
+
describe: '(arrow) width of stem at its widest point'
|
|
20098
20168
|
})
|
|
20099
|
-
.option('
|
|
20100
|
-
|
|
20169
|
+
.option('stem-length', {
|
|
20170
|
+
old_alias: 'arrow-stem-length',
|
|
20171
|
+
describe: '(arrow) alternative to length'
|
|
20101
20172
|
})
|
|
20102
|
-
.option('
|
|
20103
|
-
|
|
20173
|
+
.option('stem-taper', {
|
|
20174
|
+
old_alias: 'arrow-stem-taper',
|
|
20175
|
+
describe: '(arrow) factor for tapering the width of the stem (0-1)'
|
|
20104
20176
|
})
|
|
20105
|
-
.option('
|
|
20106
|
-
|
|
20177
|
+
.option('stem-curve', {
|
|
20178
|
+
old_alias: 'arrow-stem-curve',
|
|
20179
|
+
describe: '(arrow) curvature in degrees (default is 0)'
|
|
20107
20180
|
})
|
|
20108
|
-
.option('
|
|
20109
|
-
|
|
20181
|
+
.option('min-stem-ratio', {
|
|
20182
|
+
old_alias: 'arrow-min-stem',
|
|
20183
|
+
describe: '(arrow) min ratio of stem to total length',
|
|
20110
20184
|
type: 'number'
|
|
20111
20185
|
})
|
|
20112
20186
|
.option('stroke', {})
|
|
@@ -21643,7 +21717,7 @@ ${svg}
|
|
|
21643
21717
|
collectionType = 'mixed';
|
|
21644
21718
|
}
|
|
21645
21719
|
} else if (currType != t) {
|
|
21646
|
-
stop("Unable to import mixed-geometry
|
|
21720
|
+
stop("Unable to import mixed-geometry features");
|
|
21647
21721
|
}
|
|
21648
21722
|
}
|
|
21649
21723
|
|
|
@@ -21754,6 +21828,33 @@ ${svg}
|
|
|
21754
21828
|
importShp: importShp
|
|
21755
21829
|
});
|
|
21756
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
|
+
|
|
21757
21858
|
function GeoJSONParser(opts) {
|
|
21758
21859
|
var idField = opts.id_field || GeoJSON.ID_FIELD,
|
|
21759
21860
|
importer = new PathImporter(opts),
|
|
@@ -21775,8 +21876,11 @@ ${svg}
|
|
|
21775
21876
|
geom = o;
|
|
21776
21877
|
}
|
|
21777
21878
|
// TODO: improve so geometry_type option skips features instead of creating null geometries
|
|
21778
|
-
|
|
21779
|
-
|
|
21879
|
+
if (geom && geom.type == 'GeometryCollection') {
|
|
21880
|
+
GeoJSON.importComplexFeature(importer, geom, rec, opts);
|
|
21881
|
+
} else {
|
|
21882
|
+
GeoJSON.importSimpleFeature(importer, geom, rec, opts);
|
|
21883
|
+
}
|
|
21780
21884
|
};
|
|
21781
21885
|
|
|
21782
21886
|
this.done = function() {
|
|
@@ -21784,50 +21888,58 @@ ${svg}
|
|
|
21784
21888
|
};
|
|
21785
21889
|
}
|
|
21786
21890
|
|
|
21787
|
-
function
|
|
21788
|
-
var
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
21792
|
-
srcCollection, dataset;
|
|
21793
|
-
|
|
21794
|
-
// Convert single feature or geometry into a collection with one member
|
|
21795
|
-
if (srcObj.type == 'Feature') {
|
|
21796
|
-
srcCollection = {
|
|
21797
|
-
type: 'FeatureCollection',
|
|
21798
|
-
features: [srcObj]
|
|
21799
|
-
};
|
|
21800
|
-
} else if (supportedGeometries.includes(srcObj.type)) {
|
|
21801
|
-
srcCollection = {
|
|
21802
|
-
type: 'GeometryCollection',
|
|
21803
|
-
geometries: [srcObj]
|
|
21804
|
-
};
|
|
21805
|
-
} else {
|
|
21806
|
-
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;
|
|
21807
21896
|
}
|
|
21808
|
-
(
|
|
21809
|
-
|
|
21810
|
-
|
|
21811
|
-
|
|
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);
|
|
21812
21920
|
}
|
|
21813
21921
|
|
|
21814
|
-
GeoJSON.
|
|
21815
|
-
|
|
21816
|
-
|
|
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) {
|
|
21817
21932
|
if (opts.geometry_type && opts.geometry_type != GeoJSON.translateGeoJSONType(type)) {
|
|
21818
21933
|
// kludge to filter out all but one type of geometry
|
|
21819
21934
|
return;
|
|
21820
21935
|
}
|
|
21821
21936
|
GeoJSON.pathImporters[type](geom.coordinates, importer);
|
|
21822
|
-
} else if (type == 'GeometryCollection') {
|
|
21823
|
-
geom.geometries.forEach(function(geom) {
|
|
21824
|
-
GeoJSON.importGeometry(geom, importer, opts);
|
|
21825
|
-
});
|
|
21826
21937
|
} else {
|
|
21827
|
-
verbose("
|
|
21938
|
+
verbose("Unsupported geometry type:", geom.type);
|
|
21828
21939
|
}
|
|
21829
21940
|
};
|
|
21830
21941
|
|
|
21942
|
+
|
|
21831
21943
|
// Functions for importing geometry coordinates using a PathImporter
|
|
21832
21944
|
//
|
|
21833
21945
|
GeoJSON.pathImporters = {
|
|
@@ -21866,8 +21978,8 @@ ${svg}
|
|
|
21866
21978
|
|
|
21867
21979
|
var GeojsonImport = /*#__PURE__*/Object.freeze({
|
|
21868
21980
|
__proto__: null,
|
|
21869
|
-
GeoJSONParser: GeoJSONParser,
|
|
21870
21981
|
importGeoJSON: importGeoJSON,
|
|
21982
|
+
GeoJSONParser: GeoJSONParser,
|
|
21871
21983
|
importCRS: importCRS
|
|
21872
21984
|
});
|
|
21873
21985
|
|
|
@@ -37929,91 +38041,131 @@ ${svg}
|
|
|
37929
38041
|
points.push(p2);
|
|
37930
38042
|
}
|
|
37931
38043
|
|
|
37932
|
-
function getStickArrowCoords(d, totalLen) {
|
|
37933
|
-
|
|
37934
|
-
|
|
37935
|
-
|
|
37936
|
-
|
|
37937
|
-
|
|
37938
|
-
|
|
37939
|
-
|
|
37940
|
-
|
|
37941
|
-
|
|
37942
|
-
|
|
37943
|
-
|
|
37944
|
-
|
|
37945
|
-
|
|
37946
|
-
|
|
37947
|
-
|
|
37948
|
-
|
|
37949
|
-
rotateCoords(stem, d.rotation);
|
|
37950
|
-
rotateCoords(head, d.rotation);
|
|
37951
|
-
return [stem, head];
|
|
37952
|
-
}
|
|
37953
|
-
|
|
37954
|
-
function getMinStemRatio(d) {
|
|
37955
|
-
return d['arrow-min-stem'] >= 0 ? d['arrow-min-stem'] : 0.4;
|
|
37956
|
-
}
|
|
37957
|
-
|
|
37958
|
-
function getFilledArrowCoords(totalLen, d) {
|
|
37959
|
-
var minStemRatio = getMinStemRatio(d),
|
|
37960
|
-
headAngle = d['arrow-head-angle'] || 40,
|
|
37961
|
-
direction = d.rotation || d['arrow-direction'] || 0,
|
|
37962
|
-
unscaledStemWidth = d['arrow-stem-width'] || 2,
|
|
37963
|
-
unscaledHeadWidth = d['arrow-head-width'] || unscaledStemWidth * 3,
|
|
37964
|
-
unscaledHeadLen = getHeadLength(unscaledHeadWidth, headAngle),
|
|
37965
|
-
scale = getScale(totalLen, unscaledHeadLen, minStemRatio),
|
|
37966
|
-
headWidth = unscaledHeadWidth * scale,
|
|
37967
|
-
headLen = unscaledHeadLen * scale,
|
|
37968
|
-
stemWidth = unscaledStemWidth * scale,
|
|
37969
|
-
stemTaper = d['arrow-stem-taper'] || 0,
|
|
37970
|
-
stemCurve = d['arrow-stem-curve'] || 0,
|
|
37971
|
-
stemLen = totalLen - headLen;
|
|
37972
|
-
|
|
37973
|
-
var headDx = headWidth / 2,
|
|
37974
|
-
stemDx = stemWidth / 2,
|
|
37975
|
-
baseDx = stemDx * (1 - stemTaper);
|
|
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)];
|
|
37976
38060
|
|
|
37977
|
-
|
|
38061
|
+
// rotateCoords(stem, d.rotation);
|
|
38062
|
+
// rotateCoords(head, d.rotation);
|
|
38063
|
+
// return [stem, head];
|
|
38064
|
+
// }
|
|
38065
|
+
|
|
38066
|
+
// function getStickArrowTip(totalLen, curve) {
|
|
38067
|
+
// // curve/2 intersects the arrowhead at 90deg (trigonometry)
|
|
38068
|
+
// var theta = Math.abs(curve/2) / 180 * Math.PI;
|
|
38069
|
+
// var dx = totalLen * Math.sin(theta) * (curve > 0 ? -1 : 1);
|
|
38070
|
+
// var dy = totalLen * Math.cos(theta);
|
|
38071
|
+
// return [dx, dy];
|
|
38072
|
+
// }
|
|
38073
|
+
|
|
38074
|
+
// function addPoints(a, b) {
|
|
38075
|
+
// return [a[0] + b[0], a[1] + b[1]];
|
|
38076
|
+
// }
|
|
38077
|
+
|
|
38078
|
+
function getFilledArrowCoords(d) {
|
|
38079
|
+
var direction = d.rotation || d.direction || 0,
|
|
38080
|
+
stemTaper = d['stem-taper'] || 0,
|
|
38081
|
+
stemCurve = d['stem-curve'] || 0,
|
|
38082
|
+
size = calcArrowSize(d);
|
|
38083
|
+
|
|
38084
|
+
if (!size) return null;
|
|
38085
|
+
|
|
38086
|
+
var headDx = size.headWidth / 2,
|
|
38087
|
+
stemDx = size.stemWidth / 2,
|
|
38088
|
+
baseDx = stemDx * (1 - stemTaper),
|
|
38089
|
+
coords;
|
|
37978
38090
|
|
|
37979
38091
|
if (!stemCurve || Math.abs(stemCurve) > 90) {
|
|
37980
|
-
coords =
|
|
37981
|
-
[-headDx, stemLen], [-stemDx, stemLen], [-baseDx, 0], [baseDx, 0]];
|
|
38092
|
+
coords = calcStraightArrowCoords(size.stemLen, size.headLen, stemDx, headDx, baseDx);
|
|
37982
38093
|
} else {
|
|
37983
38094
|
if (direction > 0) stemCurve = -stemCurve;
|
|
37984
|
-
coords = getCurvedArrowCoords(stemLen, headLen, stemCurve, stemDx, headDx, baseDx);
|
|
38095
|
+
coords = getCurvedArrowCoords(size.stemLen, size.headLen, stemCurve, stemDx, headDx, baseDx);
|
|
37985
38096
|
}
|
|
37986
38097
|
|
|
37987
38098
|
rotateCoords(coords, direction);
|
|
38099
|
+
if (d.flipped) {
|
|
38100
|
+
flipY(coords);
|
|
38101
|
+
}
|
|
37988
38102
|
return [coords];
|
|
37989
38103
|
}
|
|
37990
38104
|
|
|
38105
|
+
function calcStraightArrowCoords(stemLen, headLen, stemDx, headDx, baseDx) {
|
|
38106
|
+
return [[baseDx, 0], [stemDx, stemLen], [headDx, stemLen], [0, stemLen + headLen],
|
|
38107
|
+
[-headDx, stemLen], [-stemDx, stemLen], [-baseDx, 0], [baseDx, 0]];
|
|
38108
|
+
}
|
|
37991
38109
|
|
|
37992
|
-
function
|
|
38110
|
+
function calcArrowSize(d) {
|
|
38111
|
+
var totalLen = d.radius || d.length || d.r || 0,
|
|
38112
|
+
scale = 1,
|
|
38113
|
+
o = initArrowSize(d); // calc several parameters
|
|
38114
|
+
|
|
38115
|
+
if (totalLen > 0) {
|
|
38116
|
+
scale = calcScale(totalLen, o.headLen, d);
|
|
38117
|
+
o.stemWidth *= scale;
|
|
38118
|
+
o.headWidth *= scale;
|
|
38119
|
+
o.headLen *= scale;
|
|
38120
|
+
o.stemLen = totalLen - o.headLen;
|
|
38121
|
+
}
|
|
38122
|
+
|
|
38123
|
+
if (o.headWidth < o.stemWidth) {
|
|
38124
|
+
stop('Arrow head must be at least as wide as the stem.');
|
|
38125
|
+
}
|
|
38126
|
+
return o;
|
|
38127
|
+
}
|
|
38128
|
+
|
|
38129
|
+
function calcScale(totalLen, headLen, d) {
|
|
38130
|
+
var minStemRatio = d['min-stem-ratio'] >= 0 ? d['min-stem-ratio'] : 0;
|
|
38131
|
+
var stemLen = d['stem-length'] || 0;
|
|
37993
38132
|
var maxHeadPct = 1 - minStemRatio;
|
|
37994
38133
|
var headPct = headLen / totalLen;
|
|
38134
|
+
var scale = 1;
|
|
38135
|
+
|
|
37995
38136
|
if (headPct > maxHeadPct) {
|
|
37996
|
-
|
|
38137
|
+
scale = maxHeadPct / headPct;
|
|
38138
|
+
} else if (stemLen + headLen > totalLen) {
|
|
38139
|
+
scale = totalLen / (stemLen + headLen);
|
|
37997
38140
|
}
|
|
37998
|
-
return
|
|
38141
|
+
return scale;
|
|
37999
38142
|
}
|
|
38000
38143
|
|
|
38001
|
-
function
|
|
38002
|
-
|
|
38003
|
-
var
|
|
38004
|
-
|
|
38005
|
-
|
|
38006
|
-
|
|
38007
|
-
|
|
38008
|
-
|
|
38009
|
-
|
|
38010
|
-
|
|
38144
|
+
function initArrowSize(d) {
|
|
38145
|
+
var sizeRatio = getHeadSizeRatio(d['head-angle'] || 40); // length to width
|
|
38146
|
+
var o = {
|
|
38147
|
+
stemWidth: d['stem-width'] || 2,
|
|
38148
|
+
stemLen: d['stem-length'] || 0,
|
|
38149
|
+
headWidth: d['head-width'],
|
|
38150
|
+
headLen: d['head-length']
|
|
38151
|
+
};
|
|
38152
|
+
if (!o.headWidth) {
|
|
38153
|
+
if (o.headLen) {
|
|
38154
|
+
o.headWidth = o.headLen / sizeRatio;
|
|
38155
|
+
} else {
|
|
38156
|
+
o.headWidth = o.stemWidth * 3; // assumes stemWidth has been set
|
|
38157
|
+
}
|
|
38158
|
+
}
|
|
38159
|
+
if (!o.headLen) {
|
|
38160
|
+
o.headLen = o.headWidth * sizeRatio;
|
|
38161
|
+
}
|
|
38162
|
+
return o;
|
|
38011
38163
|
}
|
|
38012
38164
|
|
|
38013
38165
|
|
|
38014
|
-
|
|
38015
|
-
|
|
38016
|
-
return
|
|
38166
|
+
// Returns ratio of head length to head width
|
|
38167
|
+
function getHeadSizeRatio(headAngle) {
|
|
38168
|
+
return 1 / Math.tan(Math.PI * headAngle / 180 / 2) / 2;
|
|
38017
38169
|
}
|
|
38018
38170
|
|
|
38019
38171
|
function getCurvedArrowCoords(stemLen, headLen, curvature, stemDx, headDx, baseDx) {
|
|
@@ -38028,15 +38180,18 @@ ${svg}
|
|
|
38028
38180
|
var ay = baseDx * Math.sin(theta) * -sign;
|
|
38029
38181
|
var leftStem = getCurvedStemCoords(-ax, -ay, -stemDx + dx, dy, theta);
|
|
38030
38182
|
var rightStem = getCurvedStemCoords(ax, ay, stemDx + dx, dy, theta);
|
|
38031
|
-
// if (stemTaper == 1) leftStem.pop();
|
|
38032
38183
|
var stem = leftStem.concat(rightStem.reverse());
|
|
38033
|
-
stem.pop();
|
|
38184
|
+
// stem.pop();
|
|
38034
38185
|
return stem.concat(head);
|
|
38035
38186
|
}
|
|
38036
38187
|
|
|
38037
38188
|
// ax, ay: point on the base
|
|
38038
38189
|
// bx, by: point on the stem
|
|
38039
38190
|
function getCurvedStemCoords(ax, ay, bx, by, theta0) {
|
|
38191
|
+
// case: curved side intrudes into head (because stem is too short)
|
|
38192
|
+
if (ay > by) {
|
|
38193
|
+
return [[ax * by / ay, by]];
|
|
38194
|
+
}
|
|
38040
38195
|
var dx = bx - ax,
|
|
38041
38196
|
dy = by - ay,
|
|
38042
38197
|
dy1 = (dy * dy - dx * dx) / (2 * dy),
|
|
@@ -38048,10 +38203,9 @@ ${svg}
|
|
|
38048
38203
|
leftBend = bx > ax,
|
|
38049
38204
|
sign = leftBend ? 1 : -1,
|
|
38050
38205
|
points = Math.round(degrees / 5) + 2,
|
|
38051
|
-
|
|
38052
|
-
|
|
38206
|
+
increment = theta / (points + 1),
|
|
38207
|
+
coords = [[bx, by]];
|
|
38053
38208
|
|
|
38054
|
-
var coords = [[bx, by]];
|
|
38055
38209
|
for (var i=1; i<= points; i++) {
|
|
38056
38210
|
var phi = i * increment / 2;
|
|
38057
38211
|
var sinPhi = Math.sin(phi);
|
|
@@ -38068,9 +38222,11 @@ ${svg}
|
|
|
38068
38222
|
// sides: e.g. 5-pointed star has 10 sides
|
|
38069
38223
|
// radius: distance from center to point
|
|
38070
38224
|
//
|
|
38071
|
-
function getPolygonCoords(
|
|
38072
|
-
var
|
|
38073
|
-
|
|
38225
|
+
function getPolygonCoords(d) {
|
|
38226
|
+
var radius = d.radius || d.length || d.r;
|
|
38227
|
+
if (radius > 0 === false) return null;
|
|
38228
|
+
var type = d.type;
|
|
38229
|
+
var sides = +d.sides || getDefaultSides(type);
|
|
38074
38230
|
var isStar = type == 'star';
|
|
38075
38231
|
if (isStar && (sides < 6 || sides % 2 !== 0)) {
|
|
38076
38232
|
stop(`Invalid number of sides for a star (${sides})`);
|
|
@@ -38081,14 +38237,14 @@ ${svg}
|
|
|
38081
38237
|
angle = 360 / sides,
|
|
38082
38238
|
b = isStar ? 1 : 0.5,
|
|
38083
38239
|
theta, even, len;
|
|
38084
|
-
if (
|
|
38240
|
+
if (d.orientation == 'b' || d.flipped || d.rotated) {
|
|
38085
38241
|
b = 0;
|
|
38086
38242
|
}
|
|
38087
38243
|
for (var i=0; i<sides; i++) {
|
|
38088
38244
|
even = i % 2 == 0;
|
|
38089
38245
|
len = radius;
|
|
38090
38246
|
if (isStar && even) {
|
|
38091
|
-
len *= (
|
|
38247
|
+
len *= (d.star_ratio || 0.5);
|
|
38092
38248
|
}
|
|
38093
38249
|
theta = (i + b) * angle % 360;
|
|
38094
38250
|
coords.push(getPlanarSegmentEndpoint(0, 0, theta, len));
|
|
@@ -38112,6 +38268,37 @@ ${svg}
|
|
|
38112
38268
|
}[type] || 4;
|
|
38113
38269
|
}
|
|
38114
38270
|
|
|
38271
|
+
// Returns GeoJSON MultiPolygon coords
|
|
38272
|
+
function getRingCoords(d) {
|
|
38273
|
+
var radii = parseRings(d.radii || '2');
|
|
38274
|
+
var coords = [];
|
|
38275
|
+
var solidCenter = utils.isOdd(radii.length);
|
|
38276
|
+
var ring, hole;
|
|
38277
|
+
for (var i=0; i<radii.length; i++) {
|
|
38278
|
+
ring = getPolygonCoords({
|
|
38279
|
+
type: 'circle',
|
|
38280
|
+
radius: radii[i]
|
|
38281
|
+
});
|
|
38282
|
+
if (!solidCenter || i > 0) {
|
|
38283
|
+
i++;
|
|
38284
|
+
hole = ring;
|
|
38285
|
+
ring = getPolygonCoords({
|
|
38286
|
+
type: 'circle',
|
|
38287
|
+
radius: radii[i]
|
|
38288
|
+
});
|
|
38289
|
+
ring.push(hole[0]);
|
|
38290
|
+
}
|
|
38291
|
+
coords.push(ring);
|
|
38292
|
+
}
|
|
38293
|
+
return coords;
|
|
38294
|
+
}
|
|
38295
|
+
|
|
38296
|
+
function parseRings(arg) {
|
|
38297
|
+
var arr = Array.isArray(arg) ? arg : parseNumberList(arg);
|
|
38298
|
+
utils.genericSort(arr, true);
|
|
38299
|
+
return utils.uniq(arr);
|
|
38300
|
+
}
|
|
38301
|
+
|
|
38115
38302
|
// TODO: refactor to remove duplication in mapshaper-svg-style.js
|
|
38116
38303
|
cmd.symbols = function(inputLyr, dataset, opts) {
|
|
38117
38304
|
requireSinglePointLayer(inputLyr);
|
|
@@ -38128,16 +38315,17 @@ ${svg}
|
|
|
38128
38315
|
if (!shp) return null;
|
|
38129
38316
|
var d = getSymbolData(i);
|
|
38130
38317
|
var rec = records[i] || {};
|
|
38131
|
-
var
|
|
38318
|
+
var geojsonType = 'Polygon';
|
|
38319
|
+
var coords;
|
|
38132
38320
|
if (d.type == 'arrow') {
|
|
38133
|
-
|
|
38134
|
-
|
|
38321
|
+
coords = getFilledArrowCoords(d);
|
|
38322
|
+
} else if (d.type == 'ring') {
|
|
38323
|
+
coords = getRingCoords(d);
|
|
38324
|
+
geojsonType = 'MultiPolygon';
|
|
38135
38325
|
} else {
|
|
38136
|
-
|
|
38137
|
-
constructor = getPolygonCoords;
|
|
38326
|
+
coords = getPolygonCoords(d);
|
|
38138
38327
|
}
|
|
38139
|
-
if (
|
|
38140
|
-
coords = constructor(size, d, opts);
|
|
38328
|
+
if (!coords) return null;
|
|
38141
38329
|
rotateCoords(coords, +d.rotation || 0);
|
|
38142
38330
|
if (!polygonMode) {
|
|
38143
38331
|
flipY(coords);
|
|
@@ -38148,9 +38336,9 @@ ${svg}
|
|
|
38148
38336
|
if (polygonMode) {
|
|
38149
38337
|
scaleAndShiftCoords(coords, metersPerPx, shp[0]);
|
|
38150
38338
|
if (d.tfill) rec.fill = d.fill;
|
|
38151
|
-
return createGeometry(coords);
|
|
38339
|
+
return createGeometry(coords, geojsonType);
|
|
38152
38340
|
} else {
|
|
38153
|
-
rec['svg-symbol'] =
|
|
38341
|
+
rec['svg-symbol'] = makeSvgPolygonSymbol(coords, d, geojsonType);
|
|
38154
38342
|
}
|
|
38155
38343
|
});
|
|
38156
38344
|
|
|
@@ -38181,9 +38369,9 @@ ${svg}
|
|
|
38181
38369
|
return importGeoJSON(geojson);
|
|
38182
38370
|
}
|
|
38183
38371
|
|
|
38184
|
-
function createGeometry(coords) {
|
|
38372
|
+
function createGeometry(coords, type) {
|
|
38185
38373
|
return {
|
|
38186
|
-
type:
|
|
38374
|
+
type: type,
|
|
38187
38375
|
coordinates: coords
|
|
38188
38376
|
};
|
|
38189
38377
|
}
|
|
@@ -38196,7 +38384,12 @@ ${svg}
|
|
|
38196
38384
|
}
|
|
38197
38385
|
|
|
38198
38386
|
// Returns an svg-symbol data object for one symbol
|
|
38199
|
-
function
|
|
38387
|
+
function makeSvgPolygonSymbol(coords, properties, geojsonType) {
|
|
38388
|
+
if (geojsonType == 'MultiPolygon') {
|
|
38389
|
+
coords = convertMultiPolygonCoords(coords);
|
|
38390
|
+
} else if (geojsonType != 'Polygon') {
|
|
38391
|
+
error('Unsupported type:', geojsonType);
|
|
38392
|
+
}
|
|
38200
38393
|
roundCoordsForSVG(coords);
|
|
38201
38394
|
return {
|
|
38202
38395
|
type: 'polygon',
|
|
@@ -38205,9 +38398,14 @@ ${svg}
|
|
|
38205
38398
|
};
|
|
38206
38399
|
}
|
|
38207
38400
|
|
|
38401
|
+
function convertMultiPolygonCoords(coords) {
|
|
38402
|
+
return coords.reduce(function(memo, poly) {
|
|
38403
|
+
return memo.concat(poly);
|
|
38404
|
+
}, []);
|
|
38405
|
+
}
|
|
38406
|
+
|
|
38208
38407
|
var Symbols = /*#__PURE__*/Object.freeze({
|
|
38209
|
-
__proto__: null
|
|
38210
|
-
makeSvgSymbol: makeSvgSymbol
|
|
38408
|
+
__proto__: null
|
|
38211
38409
|
});
|
|
38212
38410
|
|
|
38213
38411
|
cmd.target = function(catalog, opts) {
|