mapshaper 0.5.93 → 0.5.96

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.5.93",
3
+ "version": "0.5.96",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -3728,24 +3728,36 @@
3728
3728
  this.addHistoryState(stashedUndo, redo);
3729
3729
  }, this);
3730
3730
 
3731
- // undo/redo vertex dragging
3732
- gui.on('vertex_dragstart', function(e) {
3733
- stashedUndo = this.makeVertexSetter(e.FID, e.vertex_ids);
3734
- }, this);
3735
-
3736
3731
  gui.on('vertex_dragend', function(e) {
3737
- var redo = this.makeVertexSetter(e.FID, e.vertex_ids);
3738
- this.addHistoryState(stashedUndo, redo);
3732
+ var target = gui.model.getActiveLayer();
3733
+ var arcs = target.dataset.arcs;
3734
+ var startPoint = e.points[0];
3735
+ var endPoint = internal.getVertexCoords(e.ids[0], arcs);
3736
+ var undo = function() {
3737
+ if (e.insertion) {
3738
+ internal.deleteVertex(arcs, e.ids[0]);
3739
+ } else {
3740
+ snapVerticesToPoint(e.ids, startPoint, arcs, true);
3741
+ }
3742
+ };
3743
+ var redo = function() {
3744
+ if (e.insertion) {
3745
+ internal.insertVertex(arcs, e.ids[0], e.points[0]);
3746
+ }
3747
+ snapVerticesToPoint(e.ids, endPoint, arcs, true);
3748
+ };
3749
+ this.addHistoryState(undo, redo);
3739
3750
  }, this);
3740
3751
 
3741
- gui.on('vertex_insert', function(e) {
3752
+ gui.on('vertex_delete', function(e) {
3742
3753
  var target = gui.model.getActiveLayer();
3743
3754
  var arcs = target.dataset.arcs;
3744
- var undo = function() {
3755
+ var p = arcs.getVertex2(e.vertex_id);
3756
+ var redo = function() {
3745
3757
  internal.deleteVertex(arcs, e.vertex_id);
3746
3758
  };
3747
- var redo = function() {
3748
- internal.insertVertex(arcs, e.vertex_id, e.coordinates);
3759
+ var undo = function() {
3760
+ internal.insertVertex(arcs, e.vertex_id, p);
3749
3761
  };
3750
3762
  this.addHistoryState(undo, redo);
3751
3763
  }, this);
@@ -3771,7 +3783,7 @@
3771
3783
  };
3772
3784
  };
3773
3785
 
3774
- this.makeVertexSetter = function(fid, ids) {
3786
+ this.makeVertexSetter = function(ids) {
3775
3787
  var target = gui.model.getActiveLayer();
3776
3788
  var arcs = target.dataset.arcs;
3777
3789
  var p = internal.getVertexCoords(ids[0], arcs);
@@ -5611,14 +5623,11 @@
5611
5623
  }
5612
5624
 
5613
5625
  function vertexTest(x, y) {
5614
- var maxDist = getZoomAdjustedHitBuffer(20, 2),
5615
- bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
5626
+ var maxDist = getZoomAdjustedHitBuffer(25, 2),
5616
5627
  cands = findHitCandidates(x, y, maxDist);
5617
5628
  sortByDistance(x, y, cands, displayLayer.arcs);
5618
- cands = pickNearestCandidates(cands, bufDist, maxDist);
5619
- var arcs = cands.map(function(cand) { return absArcId(cand.info.arcId); });
5629
+ cands = pickNearestCandidates(cands, 0, maxDist);
5620
5630
  return {
5621
- arcs: utils$1.uniq(arcs),
5622
5631
  ids: utils$1.pluck(cands, 'id')
5623
5632
  };
5624
5633
  }
@@ -6170,9 +6179,11 @@
6170
6179
  newData = noHitData();
6171
6180
  selectionIds = [];
6172
6181
  }
6182
+
6173
6183
  if (!testHitChange(storedData, newData)) {
6174
6184
  return;
6175
6185
  }
6186
+
6176
6187
  storedData = newData;
6177
6188
  gui.container.findChild('.map-layers').classed('symbol-hit', nonEmpty);
6178
6189
  if (active) {
@@ -7522,25 +7533,20 @@
7522
7533
  }
7523
7534
  }
7524
7535
 
7536
+ // pointer thresholds for hovering near a vertex or segment midpoint
7525
7537
  var HOVER_THRESHOLD = 8;
7526
- var MIDPOINT_THRESHOLD = 12;
7527
-
7538
+ var MIDPOINT_THRESHOLD = 11;
7528
7539
 
7529
7540
  function initVertexDragging(gui, ext, hit) {
7530
- var activeShapeId = -1;
7531
- var draggedVertexIds = null;
7532
- var selectedVertexIds = null;
7533
- var activeMidpoint; // {point, segment}
7541
+ var insertionPoint;
7542
+ var dragInfo;
7534
7543
 
7535
- function active(e) {
7536
- return e.id > -1 && gui.interaction.getMode() == 'vertices';
7544
+ function active() {
7545
+ return gui.interaction.getMode() == 'vertices';
7537
7546
  }
7538
7547
 
7539
- function fire(type) {
7540
- gui.dispatchEvent(type, {
7541
- FID: activeShapeId,
7542
- vertex_ids: draggedVertexIds
7543
- });
7548
+ function dragging() {
7549
+ return active() && !!dragInfo;
7544
7550
  }
7545
7551
 
7546
7552
  function setHoverVertex(id) {
@@ -7550,7 +7556,6 @@
7550
7556
 
7551
7557
  function clearHoverVertex() {
7552
7558
  hit.clearVertexOverlay();
7553
- // gui.state.vertex_overlay = null;
7554
7559
  }
7555
7560
 
7556
7561
  function findDraggableVertices(e) {
@@ -7562,90 +7567,103 @@
7562
7567
  var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
7563
7568
  var pixelDist = dist / ext.getPixelSize();
7564
7569
  if (pixelDist > HOVER_THRESHOLD) {
7565
- draggedVertexIds = null;
7566
7570
  return null;
7567
7571
  }
7568
- return nearestIds;
7572
+ var points = nearestIds.map(function(i) {return target.arcs.getVertex2(i);});
7573
+ return {
7574
+ ids: nearestIds,
7575
+ points: points
7576
+ };
7569
7577
  }
7570
7578
 
7571
- function insertMidpoint(v) {
7579
+ function findVertexInsertionPoint(e) {
7572
7580
  var target = hit.getHitTarget();
7573
- internal.insertVertex(target.arcs, v.i, v.point);
7581
+ if (!target.arcs.isFlat()) return null; // vertex insertion not supported with simplification
7582
+ var p = ext.translatePixelCoords(e.x, e.y);
7583
+ var shp = target.layer.shapes[e.id];
7584
+ var midpoint = findNearestMidpoint(p, shp, target.arcs);
7585
+ if (!midpoint ||
7586
+ midpoint.distance / ext.getPixelSize() > MIDPOINT_THRESHOLD) return null;
7587
+ return midpoint;
7574
7588
  }
7575
7589
 
7576
7590
  hit.on('dragstart', function(e) {
7577
- if (!active(e)) return;
7578
- if (activeMidpoint) {
7579
- insertMidpoint(activeMidpoint);
7580
- draggedVertexIds = [activeMidpoint.i];
7581
- // TODO: combine vertex insertion undo/redo actions with
7582
- // vertex_dragend undo/redo actions
7583
- gui.dispatchEvent('vertex_insert', {
7584
- FID: activeShapeId,
7585
- vertex_id: activeMidpoint.i,
7586
- coordinates: activeMidpoint.point
7587
- });
7588
- activeMidpoint = null;
7591
+ if (!active()) return;
7592
+ if (insertionPoint) {
7593
+ var target = hit.getHitTarget();
7594
+ internal.insertVertex(target.arcs, insertionPoint.i, insertionPoint.point);
7595
+ dragInfo = {
7596
+ insertion: true,
7597
+ ids: [insertionPoint.i],
7598
+ points: [insertionPoint.point]
7599
+ };
7600
+ insertionPoint = null;
7589
7601
  } else {
7590
- draggedVertexIds = findDraggableVertices(e);
7602
+ dragInfo = findDraggableVertices(e);
7603
+ }
7604
+ if (dragInfo) {
7605
+ setHoverVertex(dragInfo.ids[0]);
7591
7606
  }
7592
- if (!draggedVertexIds) return;
7593
- setHoverVertex(draggedVertexIds[0]);
7594
- activeShapeId = e.id;
7595
- fire('vertex_dragstart');
7596
7607
  });
7597
7608
 
7598
7609
  hit.on('drag', function(e) {
7599
- if (!active(e) || !draggedVertexIds) return;
7610
+ if (!dragging()) return;
7600
7611
  var target = hit.getHitTarget();
7601
7612
  var p = ext.translatePixelCoords(e.x, e.y);
7602
7613
  if (gui.keyboard.shiftIsPressed()) {
7603
- internal.snapPointToArcEndpoint(p, draggedVertexIds, target.arcs);
7614
+ internal.snapPointToArcEndpoint(p, dragInfo.ids, target.arcs);
7604
7615
  }
7605
- internal.snapVerticesToPoint(draggedVertexIds, p, target.arcs);
7606
- setHoverVertex(draggedVertexIds[0]);
7616
+ internal.snapVerticesToPoint(dragInfo.ids, p, target.arcs);
7617
+ setHoverVertex(dragInfo.ids[0]);
7607
7618
  // redrawing the whole map updates the data layer as well as the overlay layer
7608
7619
  // gui.dispatchEvent('map-needs-refresh');
7609
7620
  });
7610
7621
 
7611
7622
  hit.on('dragend', function(e) {
7612
- if (!active(e) || !draggedVertexIds) return;
7623
+ if (!dragging()) return;
7613
7624
  // kludge to get dataset to recalculate internal bounding boxes
7614
7625
  hit.getHitTarget().arcs.transformPoints(function() {});
7615
7626
  clearHoverVertex();
7616
- fire('vertex_dragend');
7617
- draggedVertexIds = null;
7618
- activeShapeId = -1;
7619
- // redraw data layer
7627
+ gui.dispatchEvent('vertex_dragend', dragInfo);
7620
7628
  gui.dispatchEvent('map-needs-refresh');
7629
+ dragInfo = null;
7621
7630
  });
7622
7631
 
7623
- // select clicked vertices
7624
- hit.on('click', function(e) {
7625
- if (!active(e)) return;
7626
- var vertices = findDraggableVertices(e); // same selection criteria as for dragging
7627
- // TODO
7632
+ hit.on('dblclick', function(e) {
7633
+ if (!active()) return;
7634
+ var info = findDraggableVertices(e); // same selection criteria as for dragging
7635
+ if (!info) return;
7636
+ var target = hit.getHitTarget();
7637
+ var vId = info.ids[0];
7638
+ if (internal.vertexIsArcStart(vId, target.arcs) ||
7639
+ internal.vertexIsArcEnd(vId, target.arcs)) {
7640
+ // TODO: support removing arc endpoints
7641
+ return;
7642
+ }
7643
+ gui.dispatchEvent('vertex_delete', {
7644
+ vertex_id: vId
7645
+ });
7646
+ internal.deleteVertex(target.arcs, vId);
7647
+ clearHoverVertex();
7648
+ gui.dispatchEvent('map-needs-refresh');
7628
7649
  });
7629
7650
 
7630
7651
  // highlight hit vertex in path edit mode
7631
7652
  hit.on('hover', function(e) {
7632
- activeMidpoint = null;
7633
- if (!active(e) || draggedVertexIds) return; // no hover effect while dragging
7634
- var vertexIds = findDraggableVertices(e);
7635
- if (vertexIds) {
7636
- setHoverVertex(vertexIds[0]);
7653
+ insertionPoint = null;
7654
+ if (!active() || dragging()) return; // no hover effect while dragging
7655
+ var info = findDraggableVertices(e);
7656
+ if (info) {
7657
+ // hovering near a vertex: highlight the vertex
7658
+ setHoverVertex(info.ids[0]);
7637
7659
  return;
7638
7660
  }
7639
- var target = hit.getHitTarget();
7640
- // vertex insertion doesn't work yet with simplification applied
7641
- if (!target.arcs.isFlat()) return;
7642
- var shp = target.layer.shapes[e.id];
7643
- var p = ext.translatePixelCoords(e.x, e.y);
7644
- var midpoint = findNearestMidpoint(p, shp, target.arcs);
7645
- if (midpoint && midpoint.distance / ext.getPixelSize() < MIDPOINT_THRESHOLD) {
7646
- hit.setHoverVertex(midpoint.point);
7647
- activeMidpoint = midpoint;
7661
+ // if hovering near a segment midpoint: show the midpoint and save midpoint info
7662
+ insertionPoint = findVertexInsertionPoint(e);
7663
+ if (insertionPoint) {
7664
+ hit.setHoverVertex(insertionPoint.point);
7648
7665
  } else {
7666
+ // pointer is not over a vertex: clear any hover effect
7649
7667
  clearHoverVertex();
7650
7668
  }
7651
7669
  }, null, 100);
@@ -7653,15 +7671,8 @@
7653
7671
 
7654
7672
 
7655
7673
  // Given a location @p (e.g. corresponding to the mouse pointer location),
7656
- // find the midpoint of two vertices on @shp suitable for inserting a new vertex,
7657
- // but only if:
7658
- // 1. point @p is closer to the midpoint than either adjacent vertex
7659
- // 2. the segment containing @p is longer than a minimum distance in pixels.
7660
- //
7674
+ // find the midpoint of two vertices on @shp suitable for inserting a new vertex
7661
7675
  function findNearestMidpoint(p, shp, arcs) {
7662
- // var v1 = internal.findNearestVertex(p[0], p[1], shp, arcs);
7663
- // var v0 = internal.findAdjacentVertex(v1, shp, arcs, -1);
7664
- // var v2 = internal.findAdjacentVertex(v1, shp, arcs, 1);
7665
7676
  var minDist = Infinity, v;
7666
7677
  internal.forEachSegmentInShape(shp, arcs, function(i, j, xx, yy) {
7667
7678
  var x1 = xx[i],
@@ -7676,6 +7687,7 @@
7676
7687
  v = {
7677
7688
  i: (i < j ? i : j) + 1, // insertion point
7678
7689
  segment: [i, j],
7690
+ segmentLen: geom.distance2D(x1, y1, x2, y2),
7679
7691
  point: [cx, cy],
7680
7692
  distance: dist
7681
7693
  };
@@ -7858,6 +7870,20 @@
7858
7870
  return style;
7859
7871
  }
7860
7872
 
7873
+ // style for vertex edit mode
7874
+ function getVertexStyle(lyr, o) {
7875
+ return {
7876
+ ids: o.ids,
7877
+ overlay: true,
7878
+ strokeColor: black,
7879
+ strokeWidth: 1.5,
7880
+ vertices: true,
7881
+ vertex_overlay: o.hit_coordinates || null,
7882
+ selected_points: o.selected_points || null,
7883
+ fillColor: null
7884
+ };
7885
+ }
7886
+
7861
7887
  // Returns a display style for the overlay layer.
7862
7888
  // The overlay layer renders several kinds of feature, each of which is displayed
7863
7889
  // with a different style.
@@ -7867,40 +7893,45 @@
7867
7893
  // * pinned shapes
7868
7894
  //
7869
7895
  function getOverlayStyle(lyr, o) {
7896
+ if (o.mode == 'vertices') {
7897
+ return getVertexStyle(lyr, o);
7898
+ }
7870
7899
  var geomType = lyr.geometry_type;
7871
7900
  var topId = o.id; // pinned id (if pinned) or hover id
7872
7901
  var topIdx = -1;
7873
7902
  var styler = function(style, i) {
7874
7903
  utils$1.extend(style, i === topIdx ? topStyle: baseStyle);
7875
- // kludge to show vertices when editing path shapes
7876
- if (o.mode == 'vertices') {
7877
- style.vertices = true;
7878
- style.vertex_overlay = o.hit_coordinates || null;
7879
- style.fillColor = null;
7880
- }
7881
7904
  };
7882
7905
  var baseStyle = getDefaultStyle(lyr, selectionStyles[geomType]);
7883
7906
  var topStyle;
7884
7907
  var ids = o.ids.filter(function(i) {
7885
7908
  return i != o.id; // move selected id to the end
7886
7909
  });
7887
- if (o.id > -1) {
7910
+ if (o.id > -1) { // pinned or hover style
7888
7911
  topStyle = getSelectedFeatureStyle(lyr, o);
7889
7912
  topIdx = ids.length;
7890
7913
  ids.push(o.id); // put the pinned/hover feature last in the render order
7891
7914
  }
7892
- var overlayStyle = {
7915
+ var style = {
7893
7916
  styler: styler,
7894
7917
  ids: ids,
7895
7918
  overlay: true
7896
7919
  };
7920
+ // kludge to show vertices when editing path shapes
7921
+ if (o.mode == 'vertices') {
7922
+ style.vertices = true;
7923
+ style.vertex_overlay = o.hit_coordinates || null;
7924
+ style.selected_points = o.selected_points || null;
7925
+ style.fillColor = null;
7926
+ }
7927
+
7897
7928
  if (layerHasCanvasDisplayStyle(lyr)) {
7898
7929
  if (geomType == 'point') {
7899
- overlayStyle.styler = getOverlayPointStyler(getCanvasDisplayStyle(lyr).styler, styler);
7930
+ style.styler = getOverlayPointStyler(getCanvasDisplayStyle(lyr).styler, styler);
7900
7931
  }
7901
- overlayStyle.type = 'styled';
7932
+ style.type = 'styled';
7902
7933
  }
7903
- return ids.length > 0 ? overlayStyle : null;
7934
+ return ids.length > 0 ? style : null;
7904
7935
  }
7905
7936
 
7906
7937
  function getSelectedFeatureStyle(lyr, o) {
@@ -8348,24 +8379,28 @@
8348
8379
  _self.drawVertices = function(shapes, arcs, style, filter) {
8349
8380
  var iter = new internal.ShapeIter(arcs);
8350
8381
  var t = getScaledTransform(_ext);
8382
+ var bounds = _ext.getBounds();
8351
8383
  var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext);
8352
8384
  var color = style.strokeColor || 'black';
8353
- var radius2 = radius * 1.7;
8385
+
8386
+ var i, j, p;
8354
8387
  _ctx.beginPath();
8355
8388
  _ctx.fillStyle = color;
8356
- for (var i=0; i<shapes.length; i++) {
8389
+ for (i=0; i<shapes.length; i++) {
8357
8390
  var shp = shapes[i];
8358
8391
  if (!shp || filter && !filter(shp)) continue;
8359
- for (var j=0; j<shp.length; j++) {
8392
+ for (j=0; j<shp.length; j++) {
8360
8393
  iter.init(shp[j]);
8361
8394
  while (iter.hasNext()) {
8395
+ if (!bounds.containsPoint(iter.x, iter.y)) continue;
8362
8396
  drawCircle(iter.x * t.mx + t.bx, iter.y * t.my + t.by, radius, _ctx);
8363
8397
  }
8364
8398
  }
8365
8399
  }
8400
+
8366
8401
  if (style.vertex_overlay) {
8367
- var p = style.vertex_overlay;
8368
- drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius2, _ctx);
8402
+ p = style.vertex_overlay;
8403
+ drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius * 1.5, _ctx);
8369
8404
  }
8370
8405
  _ctx.fill();
8371
8406
  _ctx.closePath();