mapshaper 0.5.83 → 0.5.87
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 +12 -0
- package/mapshaper.js +167 -104
- package/package.json +1 -1
- package/www/mapshaper-gui.js +2300 -2112
- package/www/mapshaper.js +167 -104
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
v0.5.87
|
|
2
|
+
* Added undo/redo to the "drag vertices" interactive editing mode.
|
|
3
|
+
|
|
4
|
+
v0.5.86
|
|
5
|
+
* Added keyboard commands for undo/redo for interactive point and label positioning.
|
|
6
|
+
|
|
7
|
+
v0.5.85
|
|
8
|
+
* Improved arrow and star symbols.
|
|
9
|
+
|
|
10
|
+
v0.5.84
|
|
11
|
+
* Bug fixes
|
|
12
|
+
|
|
1
13
|
v0.5.83
|
|
2
14
|
* Added support for importing GeoJSON features with GeometryCollection type geometries.
|
|
3
15
|
* Added "ring" symbol type.
|
package/mapshaper.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
(function () {
|
|
2
2
|
|
|
3
|
-
var VERSION = "0.5.
|
|
3
|
+
var VERSION = "0.5.86";
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
var utils = /*#__PURE__*/Object.freeze({
|
|
@@ -5362,6 +5362,10 @@
|
|
|
5362
5362
|
return i - i2;
|
|
5363
5363
|
};
|
|
5364
5364
|
|
|
5365
|
+
this.getVertex2 = function(i) {
|
|
5366
|
+
return [_xx[i], _yy[i]];
|
|
5367
|
+
};
|
|
5368
|
+
|
|
5365
5369
|
this.getVertex = function(arcId, nth) {
|
|
5366
5370
|
var i = this.indexOfVertex(arcId, nth);
|
|
5367
5371
|
return {
|
|
@@ -13712,6 +13716,9 @@
|
|
|
13712
13716
|
flipped: 'boolean',
|
|
13713
13717
|
rotated: 'boolean',
|
|
13714
13718
|
direction: 'number',
|
|
13719
|
+
sides: 'number', // polygons and stars
|
|
13720
|
+
points: 'number', // polygons and stars
|
|
13721
|
+
anchor: null, // arrows; takes start, middle, end
|
|
13715
13722
|
'head-angle': 'number',
|
|
13716
13723
|
'head-width': 'number',
|
|
13717
13724
|
'head-length': 'number',
|
|
@@ -13719,7 +13726,7 @@
|
|
|
13719
13726
|
'stem-curve': 'number', // degrees of arc
|
|
13720
13727
|
'stem-taper': 'number',
|
|
13721
13728
|
'stem-length': 'number',
|
|
13722
|
-
'min-stem': 'number',
|
|
13729
|
+
'min-stem-ratio': 'number',
|
|
13723
13730
|
'arrow-scaling': 'number',
|
|
13724
13731
|
effect: null // e.g. "fade"
|
|
13725
13732
|
}, stylePropertyTypes);
|
|
@@ -20111,16 +20118,17 @@ ${svg}
|
|
|
20111
20118
|
type: 'distance'
|
|
20112
20119
|
})
|
|
20113
20120
|
.option('sides', {
|
|
20114
|
-
describe: 'sides of a polygon
|
|
20121
|
+
describe: 'number of sides of a polygon symbol',
|
|
20115
20122
|
type: 'number'
|
|
20116
20123
|
})
|
|
20117
20124
|
.option('orientation', {
|
|
20125
|
+
// TODO: removed (replaced by flipped and rotated)
|
|
20118
20126
|
// describe: 'use orientation=b for a rotated or flipped orientation'
|
|
20119
20127
|
})
|
|
20120
|
-
.option('flipped', {
|
|
20121
|
-
|
|
20122
|
-
|
|
20123
|
-
})
|
|
20128
|
+
// .option('flipped', {
|
|
20129
|
+
// type: 'flag',
|
|
20130
|
+
// describe: 'symbol is vertically flipped'
|
|
20131
|
+
// })
|
|
20124
20132
|
.option('rotated', {
|
|
20125
20133
|
type: 'flag',
|
|
20126
20134
|
describe: 'symbol is rotated to a different orientation'
|
|
@@ -20128,8 +20136,8 @@ ${svg}
|
|
|
20128
20136
|
.option('rotation', {
|
|
20129
20137
|
describe: 'rotation of symbol in degrees'
|
|
20130
20138
|
})
|
|
20131
|
-
.option('
|
|
20132
|
-
|
|
20139
|
+
.option('points', {
|
|
20140
|
+
describe: '(star) number of points'
|
|
20133
20141
|
})
|
|
20134
20142
|
.option('point-ratio', {
|
|
20135
20143
|
old_alias: 'star-ratio',
|
|
@@ -20183,6 +20191,9 @@ ${svg}
|
|
|
20183
20191
|
describe: '(arrow) min ratio of stem to total length',
|
|
20184
20192
|
type: 'number'
|
|
20185
20193
|
})
|
|
20194
|
+
.option('anchor', {
|
|
20195
|
+
describe: '(arrow) takes one of: start, middle, end (default is start)'
|
|
20196
|
+
})
|
|
20186
20197
|
.option('stroke', {})
|
|
20187
20198
|
.option('stroke-width', {})
|
|
20188
20199
|
.option('fill', {
|
|
@@ -38063,33 +38074,17 @@ ${svg}
|
|
|
38063
38074
|
// return [stem, head];
|
|
38064
38075
|
// }
|
|
38065
38076
|
|
|
38077
|
+
// function getStickArrowTip(totalLen, curve) {
|
|
38078
|
+
// // curve/2 intersects the arrowhead at 90deg (trigonometry)
|
|
38079
|
+
// var theta = Math.abs(curve/2) / 180 * Math.PI;
|
|
38080
|
+
// var dx = totalLen * Math.sin(theta) * (curve > 0 ? -1 : 1);
|
|
38081
|
+
// var dy = totalLen * Math.cos(theta);
|
|
38082
|
+
// return [dx, dy];
|
|
38083
|
+
// }
|
|
38066
38084
|
|
|
38067
|
-
function
|
|
38068
|
-
|
|
38069
|
-
|
|
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);
|
|
38085
|
-
}
|
|
38086
|
-
|
|
38087
|
-
rotateCoords(coords, direction);
|
|
38088
|
-
if (d.flipped) {
|
|
38089
|
-
flipY(coords);
|
|
38090
|
-
}
|
|
38091
|
-
return [coords];
|
|
38092
|
-
}
|
|
38085
|
+
// function addPoints(a, b) {
|
|
38086
|
+
// return [a[0] + b[0], a[1] + b[1]];
|
|
38087
|
+
// }
|
|
38093
38088
|
|
|
38094
38089
|
function calcStraightArrowCoords(stemLen, headLen, stemDx, headDx, baseDx) {
|
|
38095
38090
|
return [[baseDx, 0], [stemDx, stemLen], [headDx, stemLen], [0, stemLen + headLen],
|
|
@@ -38097,35 +38092,27 @@ ${svg}
|
|
|
38097
38092
|
}
|
|
38098
38093
|
|
|
38099
38094
|
function calcArrowSize(d) {
|
|
38100
|
-
|
|
38101
|
-
|
|
38102
|
-
unscaledHeadWidth = d['head-width'] || unscaledStemWidth * 3,
|
|
38103
|
-
unscaledHeadLen = d['head-length'] || calcHeadLength(unscaledHeadWidth, d),
|
|
38095
|
+
// don't display arrows with negative length
|
|
38096
|
+
var totalLen = Math.max(d.radius || d.length || d.r || 0, 0),
|
|
38104
38097
|
scale = 1,
|
|
38105
|
-
o =
|
|
38098
|
+
o = initArrowSize(d); // calc several parameters
|
|
38106
38099
|
|
|
38107
38100
|
if (totalLen > 0) {
|
|
38108
|
-
scale = calcScale(totalLen,
|
|
38109
|
-
o.
|
|
38110
|
-
o.
|
|
38111
|
-
o.
|
|
38101
|
+
scale = calcScale(totalLen, o.headLen, d);
|
|
38102
|
+
o.stemWidth *= scale;
|
|
38103
|
+
o.headWidth *= scale;
|
|
38104
|
+
o.headLen *= scale;
|
|
38112
38105
|
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
38106
|
}
|
|
38120
38107
|
|
|
38121
|
-
if (
|
|
38108
|
+
if (o.headWidth < o.stemWidth) {
|
|
38122
38109
|
stop('Arrow head must be at least as wide as the stem.');
|
|
38123
38110
|
}
|
|
38124
38111
|
return o;
|
|
38125
38112
|
}
|
|
38126
38113
|
|
|
38127
38114
|
function calcScale(totalLen, headLen, d) {
|
|
38128
|
-
var minStemRatio = d['min-stem'] >= 0 ? d['min-stem'] : 0;
|
|
38115
|
+
var minStemRatio = d['min-stem-ratio'] >= 0 ? d['min-stem-ratio'] : 0;
|
|
38129
38116
|
var stemLen = d['stem-length'] || 0;
|
|
38130
38117
|
var maxHeadPct = 1 - minStemRatio;
|
|
38131
38118
|
var headPct = headLen / totalLen;
|
|
@@ -38139,40 +38126,80 @@ ${svg}
|
|
|
38139
38126
|
return scale;
|
|
38140
38127
|
}
|
|
38141
38128
|
|
|
38142
|
-
|
|
38143
|
-
|
|
38144
|
-
|
|
38145
|
-
|
|
38146
|
-
|
|
38147
|
-
|
|
38148
|
-
|
|
38149
|
-
|
|
38150
|
-
|
|
38151
|
-
|
|
38129
|
+
function initArrowSize(d) {
|
|
38130
|
+
var sizeRatio = getHeadSizeRatio(d['head-angle'] || 40); // length to width
|
|
38131
|
+
var o = {
|
|
38132
|
+
stemWidth: d['stem-width'] || 2,
|
|
38133
|
+
stemLen: d['stem-length'] || 0,
|
|
38134
|
+
headWidth: d['head-width'],
|
|
38135
|
+
headLen: d['head-length']
|
|
38136
|
+
};
|
|
38137
|
+
if (!o.headWidth) {
|
|
38138
|
+
if (o.headLen) {
|
|
38139
|
+
o.headWidth = o.headLen / sizeRatio;
|
|
38140
|
+
} else {
|
|
38141
|
+
o.headWidth = o.stemWidth * 3; // assumes stemWidth has been set
|
|
38142
|
+
}
|
|
38143
|
+
}
|
|
38144
|
+
if (!o.headLen) {
|
|
38145
|
+
o.headLen = o.headWidth * sizeRatio;
|
|
38146
|
+
}
|
|
38147
|
+
return o;
|
|
38152
38148
|
}
|
|
38153
38149
|
|
|
38154
38150
|
|
|
38155
|
-
|
|
38156
|
-
|
|
38157
|
-
|
|
38158
|
-
return headWidth * headRatio;
|
|
38151
|
+
// Returns ratio of head length to head width
|
|
38152
|
+
function getHeadSizeRatio(headAngle) {
|
|
38153
|
+
return 1 / Math.tan(Math.PI * headAngle / 180 / 2) / 2;
|
|
38159
38154
|
}
|
|
38160
38155
|
|
|
38161
|
-
function
|
|
38156
|
+
function getFilledArrowCoords(d) {
|
|
38157
|
+
var direction = d.rotation || d.direction || 0,
|
|
38158
|
+
stemTaper = d['stem-taper'] || 0,
|
|
38159
|
+
curvature = d['stem-curve'] || 0,
|
|
38160
|
+
size = calcArrowSize(d);
|
|
38161
|
+
if (!size) return null;
|
|
38162
|
+
var stemLen = size.stemLen,
|
|
38163
|
+
headLen = size.headLen,
|
|
38164
|
+
headDx = size.headWidth / 2,
|
|
38165
|
+
stemDx = size.stemWidth / 2,
|
|
38166
|
+
baseDx = stemDx * (1 - stemTaper),
|
|
38167
|
+
head, stem, coords, dx, dy;
|
|
38168
|
+
|
|
38169
|
+
if (curvature) {
|
|
38170
|
+
if (direction > 0) curvature = -curvature;
|
|
38171
|
+
var theta = Math.abs(curvature) / 180 * Math.PI;
|
|
38172
|
+
var sign = curvature > 0 ? 1 : -1;
|
|
38173
|
+
var ax = baseDx * Math.cos(theta); // rotate arrow base
|
|
38174
|
+
var ay = baseDx * Math.sin(theta) * -sign;
|
|
38175
|
+
dx = stemLen * Math.sin(theta / 2) * sign;
|
|
38176
|
+
dy = stemLen * Math.cos(theta / 2);
|
|
38177
|
+
var leftStem = getCurvedStemCoords(-ax, -ay, -stemDx + dx, dy, theta);
|
|
38178
|
+
var rightStem = getCurvedStemCoords(ax, ay, stemDx + dx, dy, theta);
|
|
38179
|
+
stem = leftStem.concat(rightStem.reverse());
|
|
38180
|
+
|
|
38181
|
+
} else {
|
|
38182
|
+
dx = 0;
|
|
38183
|
+
dy = stemLen;
|
|
38184
|
+
stem = [[-baseDx, 0], [baseDx, 0], [baseDx, 0]];
|
|
38185
|
+
}
|
|
38186
|
+
|
|
38162
38187
|
// coordinates go counter clockwise, starting from the leftmost head coordinate
|
|
38163
|
-
|
|
38164
|
-
|
|
38165
|
-
|
|
38166
|
-
|
|
38167
|
-
|
|
38168
|
-
|
|
38169
|
-
|
|
38170
|
-
|
|
38171
|
-
|
|
38172
|
-
|
|
38173
|
-
|
|
38174
|
-
|
|
38175
|
-
|
|
38188
|
+
head = [[stemDx + dx, dy], [headDx + dx, dy],
|
|
38189
|
+
[dx, headLen + dy], [-headDx + dx, dy], [-stemDx + dx, dy]];
|
|
38190
|
+
|
|
38191
|
+
coords = stem.concat(head);
|
|
38192
|
+
if (d.anchor == 'end') {
|
|
38193
|
+
scaleAndShiftCoords(coords, 1, [-dx, -dy - headLen]);
|
|
38194
|
+
} else if (d.anchor == 'middle') {
|
|
38195
|
+
scaleAndShiftCoords(coords, 1, [-dx/2, (-dy - headLen)/2]);
|
|
38196
|
+
}
|
|
38197
|
+
|
|
38198
|
+
rotateCoords(coords, direction);
|
|
38199
|
+
if (d.flipped) {
|
|
38200
|
+
flipY(coords);
|
|
38201
|
+
}
|
|
38202
|
+
return [coords];
|
|
38176
38203
|
}
|
|
38177
38204
|
|
|
38178
38205
|
// ax, ay: point on the base
|
|
@@ -38209,43 +38236,31 @@ ${svg}
|
|
|
38209
38236
|
return coords;
|
|
38210
38237
|
}
|
|
38211
38238
|
|
|
38212
|
-
// sides: e.g. 5-pointed star has 10 sides
|
|
38213
|
-
// radius: distance from center to point
|
|
38214
|
-
//
|
|
38215
38239
|
function getPolygonCoords(d) {
|
|
38216
|
-
var radius = d.radius || d.length || d.r
|
|
38240
|
+
var radius = d.radius || d.length || d.r,
|
|
38241
|
+
sides = +d.sides || getSidesByType(d.type),
|
|
38242
|
+
rotated = sides % 2 == 1,
|
|
38243
|
+
coords = [],
|
|
38244
|
+
angle, b;
|
|
38245
|
+
|
|
38217
38246
|
if (radius > 0 === false) return null;
|
|
38218
|
-
|
|
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) {
|
|
38247
|
+
if (sides >= 3 === false) {
|
|
38224
38248
|
stop(`Invalid number of sides (${sides})`);
|
|
38225
38249
|
}
|
|
38226
|
-
var coords = [],
|
|
38227
|
-
angle = 360 / sides,
|
|
38228
|
-
b = isStar ? 1 : 0.5,
|
|
38229
|
-
theta, even, len;
|
|
38230
38250
|
if (d.orientation == 'b' || d.flipped || d.rotated) {
|
|
38231
|
-
|
|
38251
|
+
rotated = !rotated;
|
|
38232
38252
|
}
|
|
38253
|
+
b = rotated ? 0 : 0.5;
|
|
38233
38254
|
for (var i=0; i<sides; i++) {
|
|
38234
|
-
|
|
38235
|
-
|
|
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));
|
|
38255
|
+
angle = (i + b) / sides * 360;
|
|
38256
|
+
coords.push(getPlanarSegmentEndpoint(0, 0, angle, radius));
|
|
38241
38257
|
}
|
|
38242
38258
|
coords.push(coords[0].concat());
|
|
38243
38259
|
return [coords];
|
|
38244
38260
|
}
|
|
38245
38261
|
|
|
38246
|
-
function
|
|
38262
|
+
function getSidesByType(type) {
|
|
38247
38263
|
return {
|
|
38248
|
-
star: 10,
|
|
38249
38264
|
circle: 72,
|
|
38250
38265
|
triangle: 3,
|
|
38251
38266
|
square: 4,
|
|
@@ -38258,6 +38273,52 @@ ${svg}
|
|
|
38258
38273
|
}[type] || 4;
|
|
38259
38274
|
}
|
|
38260
38275
|
|
|
38276
|
+
function getStarCoords(d) {
|
|
38277
|
+
var radius = d.radius || d.length || d.r,
|
|
38278
|
+
points = d.points || d.sides && d.sides / 2 || 5,
|
|
38279
|
+
sides = points * 2,
|
|
38280
|
+
minorRadius = getMinorRadius(points) * radius,
|
|
38281
|
+
b = d.orientation == 'b' || d.flipped || d.rotated ? 0 : 1,
|
|
38282
|
+
coords = [],
|
|
38283
|
+
angle, len;
|
|
38284
|
+
|
|
38285
|
+
if (radius > 0 === false) return null;
|
|
38286
|
+
if (points < 5) {
|
|
38287
|
+
stop(`Invalid number of points for a star (${points})`);
|
|
38288
|
+
}
|
|
38289
|
+
for (var i=0; i<sides; i++) {
|
|
38290
|
+
len = i % 2 == 0 ? minorRadius : radius;
|
|
38291
|
+
angle = (i + b) / sides * 360;
|
|
38292
|
+
coords.push(getPlanarSegmentEndpoint(0, 0, angle, len));
|
|
38293
|
+
}
|
|
38294
|
+
coords.push(coords[0].concat());
|
|
38295
|
+
return [coords];
|
|
38296
|
+
}
|
|
38297
|
+
|
|
38298
|
+
function getMinorRadius(points) {
|
|
38299
|
+
var innerAngle = 360 / points;
|
|
38300
|
+
var pointAngle = getDefaultPointAngle(points);
|
|
38301
|
+
var thetaA = Math.PI / 180 * innerAngle / 2;
|
|
38302
|
+
var thetaB = Math.PI / 180 * pointAngle / 2;
|
|
38303
|
+
var a = Math.tan(thetaB) / (Math.tan(thetaB) + Math.tan(thetaA));
|
|
38304
|
+
var c = a / Math.cos(thetaA);
|
|
38305
|
+
return c;
|
|
38306
|
+
}
|
|
38307
|
+
|
|
38308
|
+
function getDefaultPointAngle(points) {
|
|
38309
|
+
var minSkip = 1;
|
|
38310
|
+
var maxSkip = Math.ceil(points / 2) - 2;
|
|
38311
|
+
var skip = Math.floor((maxSkip + minSkip) / 2);
|
|
38312
|
+
return getPointAngle(points, skip);
|
|
38313
|
+
}
|
|
38314
|
+
|
|
38315
|
+
// skip: number of adjacent points to skip when drawing a segment
|
|
38316
|
+
function getPointAngle(points, skip) {
|
|
38317
|
+
var unitAngle = 360 / points;
|
|
38318
|
+
var centerAngle = unitAngle * (skip + 1);
|
|
38319
|
+
return 180 - centerAngle;
|
|
38320
|
+
}
|
|
38321
|
+
|
|
38261
38322
|
// Returns GeoJSON MultiPolygon coords
|
|
38262
38323
|
function getRingCoords(d) {
|
|
38263
38324
|
var radii = parseRings(d.radii || '2');
|
|
@@ -38312,6 +38373,8 @@ ${svg}
|
|
|
38312
38373
|
} else if (d.type == 'ring') {
|
|
38313
38374
|
coords = getRingCoords(d);
|
|
38314
38375
|
geojsonType = 'MultiPolygon';
|
|
38376
|
+
} else if (d.type == 'star') {
|
|
38377
|
+
coords = getStarCoords(d);
|
|
38315
38378
|
} else {
|
|
38316
38379
|
coords = getPolygonCoords(d);
|
|
38317
38380
|
}
|