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/www/mapshaper.js CHANGED
@@ -1,6 +1,6 @@
1
1
  (function () {
2
2
 
3
- var VERSION = "0.5.79";
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 or star symbol',
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
- type: 'flag',
20122
- describe: 'symbol is vertically flipped'
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('length', {
20132
- // alias for arrow-length
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 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);
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
- 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),
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, unscaledHeadLen, d);
38109
- o.headWidth = unscaledHeadWidth * scale;
38110
- o.headLen = unscaledHeadLen * scale;
38111
- o.stemWidth = unscaledStemWidth * scale;
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 (unscaledHeadWidth < unscaledStemWidth) {
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
- // 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]];
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
- function calcHeadLength(headWidth, d) {
38156
- var headAngle = d['head-angle'] || 40;
38157
- var headRatio = 1 / Math.tan(Math.PI * headAngle / 180 / 2) / 2; // length-to-width head ratio
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 getCurvedArrowCoords(stemLen, headLen, curvature, stemDx, headDx, baseDx) {
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
- 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);
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
- 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) {
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
- b = 0;
38251
+ rotated = !rotated;
38232
38252
  }
38253
+ b = rotated ? 0 : 0.5;
38233
38254
  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));
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 getDefaultSides(type) {
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
  }