mapshaper 0.6.80 → 0.6.81

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/mapshaper.js CHANGED
@@ -45535,7 +45535,7 @@ ${svg}
45535
45535
  });
45536
45536
  }
45537
45537
 
45538
- var version = "0.6.80";
45538
+ var version = "0.6.81";
45539
45539
 
45540
45540
  // Parse command line args into commands and run them
45541
45541
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.80",
3
+ "version": "0.6.81",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
package/www/index.html CHANGED
@@ -294,7 +294,6 @@ encoding=big5</span>. Click to see all options.</div></div></div></div>
294
294
  <div class="console-window"><div class="console-buffer selectable"></div></div>
295
295
  </div>
296
296
  <div class="mshp-main-map main-area map-area">
297
- <div class="coordinate-info colored-text selectable"></div>
298
297
  <div class="intersection-display">
299
298
  <span class="intersection-check text-btn colored-text">Check line intersections</span><span class="intersection-count">0 line intersections</span>
300
299
  <img class="close-btn" draggable="false" src="images/close.png">
@@ -3419,15 +3419,19 @@
3419
3419
  }
3420
3420
  }
3421
3421
 
3422
- function pencilPointIsSkippable(p2, points) {
3423
- var p1 = points[0];
3424
- var dist;
3425
- if (points.length < 2) return true;
3422
+ // Test if adding point p to a sequence of points (in pixel coords)
3423
+ // would result in a polyline that deviates from a straight line by
3424
+ // more than a given number of pixels
3425
+ //
3426
+ function pointExceedsTolerance(p, points, tolerance) {
3427
+ if (points.length < 2) return false;
3428
+ var p1 = points[0], p2, dist;
3426
3429
  for (var i=1; i<points.length; i++) {
3427
- dist = Math.sqrt(geom.pointSegDistSq(points[i][0], points[i][1], p1[0], p1[1], p2[0], p2[1]));
3428
- if (dist > 1.5) return false;
3430
+ p2 = points[i];
3431
+ dist = Math.sqrt(geom.pointSegDistSq(p2[0], p2[1], p1[0], p1[1], p[0], p[1]));
3432
+ if (dist > tolerance) return true;
3429
3433
  }
3430
- return true;
3434
+ return false;
3431
3435
  }
3432
3436
 
3433
3437
  function setZ(lyr, z) {
@@ -3499,6 +3503,15 @@
3499
3503
  }
3500
3504
  }
3501
3505
 
3506
+ function deleteFeature(lyr, fid) {
3507
+ var records = lyr.data?.getRecords();
3508
+ if (records) records.splice(fid, 1);
3509
+ lyr.shapes.splice(fid, 1);
3510
+ if (isProjectedLayer(lyr) && lyr.shapes != lyr.gui.displayLayer.shapes) {
3511
+ lyr.gui.displayLayer.shapes.splice(fid, 1);
3512
+ }
3513
+ }
3514
+
3502
3515
  // p: one point in source data coords
3503
3516
  function appendNewPoint(lyr, p) {
3504
3517
  lyr.shapes.push([p]);
@@ -3512,12 +3525,7 @@
3512
3525
  }
3513
3526
 
3514
3527
  function deletePoint(lyr, fid) {
3515
- var records = lyr.data?.getRecords();
3516
- lyr.shapes.splice(fid, 1);
3517
- if (records) records.splice(fid, 1);
3518
- if (isProjectedLayer(lyr)) {
3519
- lyr.gui.displayLayer.shapes.splice(fid, 1);
3520
- }
3528
+ deleteFeature(lyr, fid);
3521
3529
  }
3522
3530
 
3523
3531
  function insertPoint(lyr, fid, shp, d) {
@@ -8536,69 +8544,6 @@
8536
8544
  return self;
8537
8545
  }
8538
8546
 
8539
- function CoordinatesDisplay(gui, ext, mouse) {
8540
- var readout = gui.container.findChild('.coordinate-info').hide();
8541
-
8542
- function enabled() {
8543
- var lyr = gui.map.getActiveLayer();
8544
- return !!(lyr && lyr.gui.displayLayer.geometry_type);
8545
- }
8546
-
8547
- gui.model.on('update', function(e) {
8548
- readout.hide();
8549
- });
8550
-
8551
- readout.on('copy', function(e) {
8552
- // remove selection on copy (using timeout or else copy is cancelled)
8553
- setTimeout(function() {
8554
- window.getSelection().removeAllRanges();
8555
- }, 50);
8556
- });
8557
-
8558
- // clear coords when map pans
8559
- ext.on('change', function() {
8560
- clearCoords();
8561
- // shapes may change along with map scale
8562
- // target = lyr ? lyr.getDisplayLayer() : null;
8563
- });
8564
-
8565
- mouse.on('leave', clearCoords);
8566
-
8567
- mouse.on('click', function(e) {
8568
- if (!enabled()) return;
8569
- GUI.selectElement(readout.node());
8570
- });
8571
-
8572
- mouse.on('hover', onMouseChange);
8573
- mouse.on('drag', onMouseChange, null, 10); // high priority so editor doesn't block propagation
8574
-
8575
- function onMouseChange(e) {
8576
- if (!enabled()) return;
8577
- if (isOverMap(e)) {
8578
- displayCoords(gui.map.translatePixelCoords(e.x, e.y));
8579
- } else {
8580
- clearCoords();
8581
- }
8582
- }
8583
-
8584
- function displayCoords(p) {
8585
- var p1 = gui.map.translatePixelCoords(0, ext.height());
8586
- var p2 = gui.map.translatePixelCoords(ext.width(), 0);
8587
- var bbox = p1.concat(p2);
8588
- var decimals = internal.getBoundsPrecisionForDisplay(bbox);
8589
- var str = internal.getRoundedCoordString(p, decimals);
8590
- readout.text(str).show();
8591
- }
8592
-
8593
- function clearCoords() {
8594
- readout.hide();
8595
- }
8596
-
8597
- function isOverMap(e) {
8598
- return e.x >= 0 && e.y >= 0 && e.x < ext.width() && e.y < ext.height();
8599
- }
8600
- }
8601
-
8602
8547
  function getTimerFunction() {
8603
8548
  return typeof requestAnimationFrame == 'function' ?
8604
8549
  requestAnimationFrame : function(cb) {setTimeout(cb, 25);};
@@ -9147,7 +9092,8 @@
9147
9092
  if (!boxCoords) return null;
9148
9093
  var dataBox = getBBoxCoords(gui.map.getActiveLayer(), boxCoords);
9149
9094
  fixBounds(dataBox);
9150
- return internal.getRoundedCoords(dataBox, internal.getBoundsPrecisionForDisplay(dataBox));
9095
+ // return internal.getRoundedCoords(dataBox, internal.getBoundsPrecisionForDisplay(dataBox));
9096
+ return dataBox;
9151
9097
  };
9152
9098
 
9153
9099
  box.turnOn = function() {
@@ -9904,12 +9850,18 @@
9904
9850
  });
9905
9851
 
9906
9852
  hit.on('contextmenu', function(e) {
9907
- var target = hit.getHitTarget();
9908
- if (!e.overMap || e.mode == 'edit_lines' ||
9909
- e.mode == 'edit_polygons' || e.mode == 'edit_points') {
9853
+ if (!e.overMap || e.mode == 'edit_lines' || e.mode == 'edit_polygons' ||
9854
+ e.mode == 'edit_points') {
9910
9855
  return;
9911
9856
  }
9912
- gui.contextMenu.open(e, hit.getHitTarget());
9857
+ var target = hit.getHitTarget();
9858
+ if (e.ids.length == 1) {
9859
+ e.deleteFeature = function() {
9860
+ deleteFeature(target, e.ids[0]);
9861
+ gui.model.updated({filter:true});
9862
+ };
9863
+ }
9864
+ gui.contextMenu.open(e, target);
9913
9865
  });
9914
9866
 
9915
9867
  hit.on('change', function(e) {
@@ -10332,23 +10284,27 @@
10332
10284
  var drawingId = -1; // feature id of path being drawn
10333
10285
  var sessionCount = 0;
10334
10286
  var alert;
10335
- var pencilPoints;
10287
+ var pencilPoints = [];
10336
10288
  var _dragging = false;
10337
10289
 
10338
10290
  function active() {
10339
10291
  return initialArcCount >= 0;
10340
10292
  }
10341
10293
 
10342
- function dragging() {
10294
+ function vertexDragging() {
10343
10295
  return _dragging;
10344
10296
  }
10345
10297
 
10346
- function drawing() {
10298
+ function pathDrawing() {
10347
10299
  return drawingId > -1;
10348
10300
  }
10349
10301
 
10350
- function usingPencil() {
10351
- return (gui.keyboard.altIsPressed() || gui.keyboard.metaIsPressed()) && active() && !dragging();
10302
+ function cmdKeyDown() {
10303
+ return gui.keyboard.altIsPressed() || gui.keyboard.metaIsPressed();
10304
+ }
10305
+
10306
+ function pencilIsActive() {
10307
+ return cmdKeyDown() && active() && !vertexDragging() && !!pencilPoints;
10352
10308
  }
10353
10309
 
10354
10310
  function polygonMode() {
@@ -10392,7 +10348,7 @@
10392
10348
 
10393
10349
  gui.on('redo_path_extend', function(e) {
10394
10350
  var target = hit.getHitTarget();
10395
- if (drawing() && prevHoverEvent) {
10351
+ if (pathDrawing() && prevHoverEvent) {
10396
10352
  updatePathEndpoint(e.p);
10397
10353
  appendVertex$1(target, pixToDataCoords(prevHoverEvent.x, prevHoverEvent.y));
10398
10354
  } else {
@@ -10405,7 +10361,7 @@
10405
10361
 
10406
10362
  gui.on('undo_path_extend', function(e) {
10407
10363
  var target = hit.getHitTarget();
10408
- if (drawing() && prevHoverEvent) {
10364
+ if (pathDrawing() && prevHoverEvent) {
10409
10365
  deleteLastVertex(target);
10410
10366
  updatePathEndpoint(pixToDataCoords(prevHoverEvent.x, prevHoverEvent.y));
10411
10367
  } else {
@@ -10434,7 +10390,6 @@
10434
10390
  var isMac = navigator.userAgent.includes('Mac');
10435
10391
  var undoKey = isMac ? '⌘' : '^';
10436
10392
  var drawKey = isMac ? '⌘' : 'Alt';
10437
- var pathStr = polygonMode() ? 'closed paths' : 'paths';
10438
10393
  var msg = `Instructions: Click to start a path or add a point. ${drawKey}-drag draws a path. Drag points to reshape. Type ${undoKey}Z/${undoKey}Y to undo/redo.`;
10439
10394
  alert = showPopupAlert(msg, null, {
10440
10395
  non_blocking: true, max_width: '388px'});
@@ -10497,7 +10452,7 @@
10497
10452
  }
10498
10453
 
10499
10454
  hit.on('contextmenu', function(e) {
10500
- if (!active() || drawing() || dragging()) return;
10455
+ if (!active() || pathDrawing() || vertexDragging()) return;
10501
10456
  var target = hit.getHitTarget();
10502
10457
  var vInfo = hoverVertexInfo;
10503
10458
  if (hoverVertexInfo?.type == 'vertex' && !vertexIsEndpoint(vInfo, target)) {
@@ -10510,7 +10465,7 @@
10510
10465
  });
10511
10466
 
10512
10467
  hit.on('dragstart', function(e) {
10513
- if (!active() || drawing() || !hoverVertexInfo) return;
10468
+ if (!active() || pathDrawing() || !hoverVertexInfo) return;
10514
10469
  hideInstructions();
10515
10470
  e.originalEvent.stopPropagation();
10516
10471
  _dragging = true;
@@ -10522,15 +10477,33 @@
10522
10477
  hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type);
10523
10478
  });
10524
10479
 
10480
+ gui.map.getMouse().on('dragend', function(e) {
10481
+ pencilPoints = []; // re-enable pencil after closing a path
10482
+ });
10483
+
10525
10484
  gui.map.getMouse().on('drag', function(e) {
10526
- if (!usingPencil()) return;
10527
- e.stopPropagation();
10485
+ if (!active() || !cmdKeyDown() || vertexDragging()) return;
10486
+ e.stopPropagation(); // prevent panning
10487
+ if (!pencilIsActive()) return;
10488
+ hoverVertexInfo = findPathStartInfo(e);
10528
10489
  var xy = [e.x, e.y];
10529
10490
  var p = pixToDataCoords(e.x, e.y);
10530
- if (!drawing()) {
10491
+ if (!pathDrawing()) {
10531
10492
  pencilPoints = [xy];
10532
10493
  startNewPath(p);
10533
- } else if (!pencilPoints || !pencilPointIsSkippable(xy, pencilPoints)) {
10494
+ } else if (pencilPoints.length == 0) {
10495
+ // start pencil-drawing when a path is started
10496
+ pencilPoints = [xy];
10497
+ extendCurrentPath(p);
10498
+ } else if (hoverVertexInfo && pencilPoints.length > 2) {
10499
+ // close path
10500
+ p = hoverVertexInfo.point;
10501
+ appendVertex$1(hit.getHitTarget(), p);
10502
+ extendCurrentPath(p);
10503
+ pencilPoints = null; // stop drawing
10504
+ } else if (pointExceedsTolerance(xy, pencilPoints, 1.5)) {
10505
+ xy = pencilPoints.pop();
10506
+ p = pixToDataCoords(xy[0], xy[1]);
10534
10507
  pencilPoints = [xy];
10535
10508
  extendCurrentPath(p);
10536
10509
  } else {
@@ -10541,7 +10514,9 @@
10541
10514
  }, null, 3); // higher priority than hit control
10542
10515
 
10543
10516
  hit.on('drag', function(e) {
10544
- if (!dragging() || drawing()) return;
10517
+ if (!vertexDragging() || pathDrawing()) {
10518
+ return;
10519
+ }
10545
10520
  e.originalEvent.stopPropagation();
10546
10521
  // dragging a vertex
10547
10522
  var target = hit.getHitTarget();
@@ -10556,7 +10531,7 @@
10556
10531
  });
10557
10532
 
10558
10533
  hit.on('dragend', function(e) {
10559
- if (!dragging()) return;
10534
+ if (!vertexDragging()) return;
10560
10535
  _dragging = false;
10561
10536
  var target = hit.getHitTarget();
10562
10537
  // kludge to get dataset to recalculate internal bounding boxes
@@ -10573,7 +10548,7 @@
10573
10548
  if (!active()) return;
10574
10549
  // double click finishes a path
10575
10550
  // note: if the preceding 'click' finished the path, this does not fire
10576
- if (drawing()) {
10551
+ if (pathDrawing()) {
10577
10552
  finishCurrentPath();
10578
10553
  e.originalEvent.stopPropagation(); // prevent dblclick zoom
10579
10554
  return;
@@ -10583,9 +10558,9 @@
10583
10558
  // hover event highlights the nearest point in close proximity to the pointer
10584
10559
  // ... or the closest point along the segment (for adding a new vertex)
10585
10560
  hit.on('hover', function(e) {
10586
- if (!active() || dragging()) return;
10561
+ if (!active() || vertexDragging()) return;
10587
10562
 
10588
- if (drawing()) {
10563
+ if (pathDrawing()) {
10589
10564
  if (!e.overMap) {
10590
10565
  finishCurrentPath();
10591
10566
  return;
@@ -10599,7 +10574,7 @@
10599
10574
  // highlight nearby snappable vertex (the closest vertex on a nearby line,
10600
10575
  // or the first vertex of the current drawing path if not near a line)
10601
10576
  hoverVertexInfo = e.id >= 0 && findDraggableVertices(e) ||
10602
- drawing() && findPathStartInfo(e) ||
10577
+ pathDrawing() && findPathStartInfo(e) ||
10603
10578
  e.id >= 0 && findInterpolatedPoint(e);
10604
10579
  if (hoverVertexInfo) {
10605
10580
  // hovering near a vertex: highlight the vertex
@@ -10616,10 +10591,13 @@
10616
10591
  if (!active()) return;
10617
10592
  if (detectDoubleClick(e)) return; // ignore second click of a dblclick
10618
10593
  var p = pixToDataCoords(e.x, e.y);
10619
- if (drawing()) {
10594
+ if (pathDrawing()) {
10620
10595
  extendCurrentPath(hoverVertexInfo?.point || p);
10621
10596
  } else if (gui.keyboard.shiftIsPressed()) {
10622
10597
  deleteActiveVertex(e);
10598
+ } else if (hoverVertexInfo?.type == 'interpolated') {
10599
+ // don't start new path if hovering along a segment -- this is
10600
+ // likely to be an attempt to add a new vertex, not start a new path
10623
10601
  } else {
10624
10602
  startNewPath(p);
10625
10603
  }
@@ -10647,7 +10625,7 @@
10647
10625
 
10648
10626
  function updateCursor() {
10649
10627
  gui.container.findChild('.map-layers').classed('drawing', active());
10650
- var useArrow = hoverVertexInfo && !hoverVertexInfo.extendable && !drawing();
10628
+ var useArrow = hoverVertexInfo && !hoverVertexInfo.extendable && !pathDrawing();
10651
10629
  gui.container.findChild('.map-layers').classed('dragging', useArrow);
10652
10630
  }
10653
10631
 
@@ -10713,7 +10691,7 @@
10713
10691
  }
10714
10692
 
10715
10693
  function finishCurrentPath() {
10716
- if (!drawing()) return;
10694
+ if (!pathDrawing()) return;
10717
10695
  var target = hit.getHitTarget();
10718
10696
  if (getLastArcLength(target) <= 2) { // includes hover point
10719
10697
  deleteLastPath(target);
@@ -10736,12 +10714,6 @@
10736
10714
  updateCursor();
10737
10715
  }
10738
10716
 
10739
- function pencilDraw(e) {
10740
- var p = pixToDataCoords(e.x, e.y);
10741
- extendCurrentPath(p);
10742
-
10743
- }
10744
-
10745
10717
  // p: [x, y] source data coordinates of new point on path
10746
10718
  function extendCurrentPath(p) {
10747
10719
  var target = hit.getHitTarget();
@@ -10794,6 +10766,7 @@
10794
10766
  }
10795
10767
 
10796
10768
  function findPathStartInfo(e) {
10769
+ if (!pathDrawing()) return false;
10797
10770
  var target = hit.getHitTarget();
10798
10771
  var arcId = target.gui.displayArcs.size() - 1;
10799
10772
  var p1 = ext.translatePixelCoords(e.x, e.y); // mouse coords
@@ -12571,9 +12544,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
12571
12544
 
12572
12545
  _basemap = new Basemap(gui, _ext);
12573
12546
 
12574
- if (gui.options.showMouseCoordinates) {
12575
- new CoordinatesDisplay(gui, _ext, _mouse);
12576
- }
12577
12547
  _mouse.disable(); // wait for gui.focus() to activate mouse events
12578
12548
 
12579
12549
  model.on('select', function(e) {
@@ -13148,6 +13118,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13148
13118
  if (e.ids?.length) {
13149
13119
  addMenuItem('Copy as GeoJSON', copyGeoJSON);
13150
13120
  }
13121
+ if (e.deleteFeature) {
13122
+ addMenuItem(getDeleteLabel(), e.deleteFeature);
13123
+ }
13124
+
13125
+ function getDeleteLabel() {
13126
+ return 'Delete ' + (lyr.geometry_type == 'point' ? 'point' : 'shape');
13127
+ }
13151
13128
 
13152
13129
  function addCoords(p) {
13153
13130
  var coordStr = p[0] + ',' + p[1];
@@ -13195,7 +13172,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13195
13172
  inspectorControl: true,
13196
13173
  saveControl: true,
13197
13174
  disableNavigation: false,
13198
- showMouseCoordinates: true,
13199
13175
  focus: true
13200
13176
  }, opts);
13201
13177
 
package/www/mapshaper.js CHANGED
@@ -45535,7 +45535,7 @@ ${svg}
45535
45535
  });
45536
45536
  }
45537
45537
 
45538
- var version = "0.6.80";
45538
+ var version = "0.6.81";
45539
45539
 
45540
45540
  // Parse command line args into commands and run them
45541
45541
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
package/www/page.css CHANGED
@@ -151,21 +151,6 @@ body.map-view {
151
151
  height: 29px;
152
152
  }
153
153
 
154
- .basemap-on .coordinate-info {
155
- left: 100px;
156
- }
157
-
158
- .coordinate-info {
159
- z-index: 1;
160
- position: absolute;
161
- bottom: 7px;
162
- left: 7px;
163
- padding: 2px 5px 2px 5px;
164
- font-size: 11px;
165
- pointer-events: none;
166
- background: rgba(255,255,255,0.4);
167
- }
168
-
169
154
  .mapshaper-logo {
170
155
  font-weight: bold;
171
156
  font-size: 17px;