mapshaper 0.6.72 → 0.6.74

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
@@ -3208,13 +3208,13 @@
3208
3208
  // Used by mapshaper-undershoots.js
3209
3209
  // TODO: make more robust, make sure result is compatible with segmentIntersection()
3210
3210
  // (rounding errors currently must be handled downstream)
3211
- function findClosestPointOnSeg(px, py, ax, ay, bx, by) {
3211
+ function findClosestPointOnSeg(px, py, ax, ay, bx, by, snapArg) {
3212
3212
  var dx = bx - ax,
3213
3213
  dy = by - ay,
3214
3214
  dotp = (px - ax) * dx + (py - ay) * dy,
3215
3215
  abSq = dx * dx + dy * dy,
3216
3216
  k = abSq === 0 ? -1 : dotp / abSq,
3217
- eps = 0.1, // 1e-6, // snap to endpoint
3217
+ eps = snapArg >= 0 ? snapArg : 0.1, // 1e-6, // snap to endpoint
3218
3218
  p;
3219
3219
  if (k <= eps) {
3220
3220
  p = [ax, ay];
@@ -5553,43 +5553,35 @@
5553
5553
  }
5554
5554
 
5555
5555
  function initBounds() {
5556
- var data = calcArcBounds2(_xx, _yy, _nn);
5557
- _bb = data.bb;
5558
- _allBounds = data.bounds;
5559
- }
5560
-
5561
- function calcArcBounds2(xx, yy, nn) {
5562
- var numArcs = nn.length,
5563
- bb = new Float64Array(numArcs * 4),
5564
- bounds = new Bounds(),
5565
- arcOffs = 0,
5566
- arcLen,
5567
- j, b;
5556
+ var numArcs = _nn.length;
5557
+ _bb = new Float64Array(numArcs * 4);
5558
+ _allBounds = new Bounds();
5568
5559
  for (var i=0; i<numArcs; i++) {
5569
- arcLen = nn[i];
5570
- if (arcLen > 0) {
5571
- j = i * 4;
5572
- b = calcArcBounds(xx, yy, arcOffs, arcLen);
5573
- bb[j++] = b[0];
5574
- bb[j++] = b[1];
5575
- bb[j++] = b[2];
5576
- bb[j] = b[3];
5577
- arcOffs += arcLen;
5578
- bounds.mergeBounds(b);
5579
- }
5560
+ initArcBounds(i);
5580
5561
  }
5581
- return {
5582
- bb: bb,
5583
- bounds: bounds
5584
- };
5585
5562
  }
5586
5563
 
5564
+ function initArcBounds(i) {
5565
+ var arcLen = _nn[i];
5566
+ var arcOffs = _ii[i];
5567
+ var j = i * 4;
5568
+ var b = calcArcBounds(_xx, _yy, arcOffs, arcLen);
5569
+ _bb[j++] = b[0];
5570
+ _bb[j++] = b[1];
5571
+ _bb[j++] = b[2];
5572
+ _bb[j] = b[3];
5573
+ _allBounds.mergeBounds(b);
5574
+ }
5575
+
5576
+ this.updateArcBounds = function(arcId) {
5577
+ initArcBounds(arcId);
5578
+ };
5579
+
5587
5580
  this.updateVertexData = function(nn, xx, yy, zz) {
5588
5581
  initXYData(nn, xx, yy);
5589
5582
  initZData(zz || null);
5590
5583
  };
5591
5584
 
5592
-
5593
5585
  this.getCopy = function() {
5594
5586
  var copy = new ArcCollection(new Int32Array(_nn), new Float64Array(_xx),
5595
5587
  new Float64Array(_yy));
@@ -13194,13 +13186,14 @@
13194
13186
 
13195
13187
 
13196
13188
  function snapVerticesToPoint(ids, p, arcs, final) {
13189
+ var data = arcs.getVertexData();
13197
13190
  ids.forEach(function(idx) {
13191
+ if (final) {
13192
+ // recalculate bounding box for arc
13193
+ arcs.updateArcBounds(findArcIdFromVertexId(idx, data.ii));
13194
+ }
13198
13195
  setVertexCoords(p[0], p[1], idx, arcs);
13199
13196
  });
13200
- if (final) {
13201
- // kludge to get dataset to recalculate internal bounding boxes
13202
- arcs.transformPoints(function() {});
13203
- }
13204
13197
  }
13205
13198
 
13206
13199
 
@@ -45492,7 +45485,7 @@ ${svg}
45492
45485
  });
45493
45486
  }
45494
45487
 
45495
- var version = "0.6.72";
45488
+ var version = "0.6.74";
45496
45489
 
45497
45490
  // Parse command line args into commands and run them
45498
45491
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
@@ -46238,6 +46231,7 @@ ${svg}
46238
46231
  Rounding,
46239
46232
  RunCommands,
46240
46233
  Scalebar,
46234
+ SegmentGeom,
46241
46235
  SegmentIntersection,
46242
46236
  ShapeIter$1,
46243
46237
  ShapeUtils,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mapshaper",
3
- "version": "0.6.72",
3
+ "version": "0.6.74",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -1092,16 +1092,21 @@
1092
1092
  return _el;
1093
1093
  }
1094
1094
 
1095
- function showPopupAlert(msg, title) {
1095
+ function showPopupAlert(msg, title, optsArg) {
1096
+ var opts = optsArg || {};
1096
1097
  var self = {}, html = '';
1097
1098
  var _cancel, _close;
1098
1099
  var warningRxp = /^Warning: /;
1099
- var el = El('div').appendTo('body').addClass('alert-wrapper');
1100
+ var el = El('div').appendTo('body').addClass('alert-wrapper')
1101
+ .classed('non-blocking', opts.non_blocking);
1100
1102
  var infoBox = El('div').appendTo(el).addClass('alert-box info-box selectable');
1101
1103
  El('div').appendTo(infoBox).addClass('close2-btn').on('click', function() {
1102
1104
  if (_cancel) _cancel();
1103
1105
  self.close();
1104
1106
  });
1107
+ if (opts.max_width) {
1108
+ infoBox.node().style.maxWidth = opts.max_width;
1109
+ }
1105
1110
  var container = El('div').appendTo(infoBox);
1106
1111
  if (!title && warningRxp.test(msg)) {
1107
1112
  title = 'Warning';
@@ -1112,7 +1117,7 @@
1112
1117
  }
1113
1118
  var content = El('div').appendTo(infoBox);
1114
1119
  if (msg) {
1115
- content.html(`<p class="error-message">${msg}</p>`);
1120
+ content.html(`<p class="alert-message">${msg}</p>`);
1116
1121
  }
1117
1122
 
1118
1123
  self.container = function() { return content; };
@@ -2704,8 +2709,8 @@
2704
2709
  if (opts.interactionMode == 'vertices') {
2705
2710
  return getVertexStyle(baseLyr, o);
2706
2711
  }
2707
- if (opts.interactionMode == 'edit-lines') {
2708
- return getLineEditingStyle(baseLyr, o);
2712
+ if (opts.interactionMode == 'drawing') {
2713
+ return getLineEditingStyle(o);
2709
2714
  }
2710
2715
  var geomType = baseLyr.geometry_type;
2711
2716
  var topId = o.id; // pinned id (if pinned) or hover id
@@ -2787,7 +2792,6 @@
2787
2792
  strokeColor: black,
2788
2793
  strokeWidth: 1.5,
2789
2794
  vertices: true,
2790
- vertex_overlay_color: violet,
2791
2795
  vertex_overlay: o.hit_coordinates || null,
2792
2796
  selected_points: o.selected_points || null,
2793
2797
  fillColor: null
@@ -2795,14 +2799,15 @@
2795
2799
  }
2796
2800
 
2797
2801
  // style for vertex edit mode
2798
- function getLineEditingStyle(lyr, o) {
2802
+ function getLineEditingStyle(o) {
2799
2803
  return {
2800
2804
  ids: o.ids,
2801
2805
  overlay: true,
2802
2806
  strokeColor: 'black',
2803
2807
  strokeWidth: 1.2,
2804
2808
  vertices: true,
2805
- vertex_overlay_color: violet,
2809
+ vertex_overlay_color: o.hit_type == 'vertex' ? violet : black,
2810
+ vertex_overlay_scale: o.hit_type == 'vertex' ? 2.4 : 1.7,
2806
2811
  vertex_overlay: o.hit_coordinates || null,
2807
2812
  selected_points: o.selected_points || null,
2808
2813
  fillColor: null
@@ -2942,10 +2947,15 @@
2942
2947
  d['label-text'] = 'TBD'; // without text, new labels will be invisible
2943
2948
  } else if (layer.geometry_type == 'point' && fields.includes('r')) {
2944
2949
  d.r = 3; // show a black circle if layer is styled
2945
- } else if (true || layer.geometry_type == 'polyline' && fields.includes('stroke')) {
2946
- d.stroke = 'black';
2947
- } else if (layer.geometry_type == 'polygon' && fields.includes('stroke')) {
2948
- d.stroke = 'black';
2950
+ }
2951
+ if (layer.geometry_type == 'polyline' || layer.geometry_type == 'polygon') {
2952
+ if (fields.includes('stroke')) d.stroke = 'black';
2953
+ if (fields.includes('stroke-width')) d['stroke-width'] = 1;
2954
+ }
2955
+ if (layer.geometry_type == 'polygon') {
2956
+ if (fields.includes('fill')) {
2957
+ d.fill = 'rgba(0,0,0,0.10)'; // 'rgba(249,120,249,0.20)';
2958
+ }
2949
2959
  }
2950
2960
  // TODO: better styling
2951
2961
  layer.data.getRecords().push(d);
@@ -5156,7 +5166,7 @@
5156
5166
  var startPoint = e.point; // in data coords
5157
5167
  var endPoint = getVertexCoords(target, e.ids[0]);
5158
5168
  var undo = function() {
5159
- if (e.insertion) {
5169
+ if (e.data.type == 'interpolated') {
5160
5170
  deleteVertex$1(target, e.ids[0]);
5161
5171
  } else {
5162
5172
  setVertexCoords(target, e.ids, startPoint);
@@ -5420,9 +5430,9 @@
5420
5430
 
5421
5431
  var menus = {
5422
5432
  standard: ['info', 'selection', 'box'],
5423
- polygons: ['info', 'selection', 'box', 'vertices'],
5424
- rectangles: ['info', 'selection', 'box', 'rectangles', 'vertices'],
5425
- lines: ['info', 'selection', 'box' , 'edit-lines'],
5433
+ polygons: ['info', 'selection', 'box', 'drawing'],
5434
+ rectangles: ['info', 'selection', 'box', 'rectangles'], // 'vertices'
5435
+ lines: ['info', 'selection', 'box' , 'drawing'],
5426
5436
  table: ['info', 'selection'],
5427
5437
  labels: ['info', 'selection', 'box', 'labels', 'location', 'add-points'],
5428
5438
  points: ['info', 'selection', 'box', 'location', 'add-points']
@@ -5444,8 +5454,7 @@
5444
5454
  vertices: 'edit vertices',
5445
5455
  selection: 'select features',
5446
5456
  'add-points': 'add points',
5447
- 'draw-lines': 'draw lines',
5448
- 'edit-lines': 'draw/modify lines',
5457
+ drawing: 'draw/reshape tool',
5449
5458
  rectangles: 'drag-to-resize',
5450
5459
  off: 'turn off'
5451
5460
  };
@@ -5501,7 +5510,7 @@
5501
5510
  };
5502
5511
 
5503
5512
  this.modeUsesHitDetection = function(mode) {
5504
- return ['info', 'selection', 'data', 'labels', 'location', 'vertices', 'rectangles', 'edit-lines'].includes(mode);
5513
+ return ['info', 'selection', 'data', 'labels', 'location', 'vertices', 'rectangles', 'drawing'].includes(mode);
5505
5514
  };
5506
5515
 
5507
5516
  this.modeUsesPopup = function(mode) {
@@ -7242,7 +7251,11 @@
7242
7251
  test = getGraduatedCircleTest(getRadiusFunction(displayLayer.style));
7243
7252
  } else if (geoType == 'point') {
7244
7253
  test = pointTest;
7245
- } else if (interactionMode == 'vertices' || interactionMode == 'edit-lines') {
7254
+ } else if (interactionMode == 'drawing' && geoType == 'polygon') {
7255
+ test = polygonVertexTest;
7256
+ } else if (
7257
+ interactionMode == 'vertices' ||
7258
+ interactionMode == 'drawing') {
7246
7259
  test = vertexTest;
7247
7260
  } else if (geoType == 'polyline') {
7248
7261
  test = polylineTest;
@@ -7289,6 +7302,30 @@
7289
7302
  };
7290
7303
  }
7291
7304
 
7305
+ function polygonVertexTest(x, y) {
7306
+ var a = polygonTest(x, y);
7307
+ var b = polylineTest(x, y, 5);
7308
+ return {
7309
+ ids: utils$1.uniq(b.ids.concat(a.ids))
7310
+ };
7311
+ }
7312
+
7313
+ function vertexTest(x, y) {
7314
+ return polylineTest(x, y, 0);
7315
+ }
7316
+
7317
+ function polylineTest(x, y, bufArg) {
7318
+ var maxDist = getZoomAdjustedHitBuffer(15, 2),
7319
+ bufPix = bufArg >= 0 ? bufArg : 0.05, // tiny threshold for hitting almost-identical lines
7320
+ bufDist = getZoomAdjustedHitBuffer(bufPix),
7321
+ cands = findHitCandidates(x, y, maxDist);
7322
+ sortByDistance(x, y, cands, displayLayer.arcs);
7323
+ cands = pickNearestCandidates(cands, bufDist, maxDist);
7324
+ return {
7325
+ ids: utils$1.pluck(cands, 'id')
7326
+ };
7327
+ }
7328
+
7292
7329
  function pickNearestCandidates(sorted, bufDist, maxDist) {
7293
7330
  var hits = [],
7294
7331
  cand, minDist;
@@ -7306,28 +7343,6 @@
7306
7343
  return hits;
7307
7344
  }
7308
7345
 
7309
- function vertexTest(x, y) {
7310
- var bufferPix = 15; // 25;
7311
- var maxDist = getZoomAdjustedHitBuffer(bufferPix, 2),
7312
- cands = findHitCandidates(x, y, maxDist);
7313
- sortByDistance(x, y, cands, displayLayer.arcs);
7314
- cands = pickNearestCandidates(cands, 0, maxDist);
7315
- return {
7316
- ids: utils$1.pluck(cands, 'id')
7317
- };
7318
- }
7319
-
7320
- function polylineTest(x, y) {
7321
- var maxDist = getZoomAdjustedHitBuffer(15, 2),
7322
- bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
7323
- cands = findHitCandidates(x, y, maxDist);
7324
- sortByDistance(x, y, cands, displayLayer.arcs);
7325
- cands = pickNearestCandidates(cands, bufDist, maxDist);
7326
- return {
7327
- ids: utils$1.pluck(cands, 'id')
7328
- };
7329
- }
7330
-
7331
7346
  function sortByDistance(x, y, cands, arcs) {
7332
7347
  var cand;
7333
7348
  for (var i=0; i<cands.length; i++) {
@@ -7417,6 +7432,7 @@
7417
7432
  };
7418
7433
  }
7419
7434
 
7435
+ // Returns array of shape ids for shapes that pass a buffered bounding-box test
7420
7436
  function findHitCandidates(x, y, dist) {
7421
7437
  var arcs = displayLayer.arcs,
7422
7438
  index = {},
@@ -7667,13 +7683,12 @@
7667
7683
 
7668
7684
  function draggable() {
7669
7685
  return interactionMode == 'vertices' || interactionMode == 'location' ||
7670
- interactionMode == 'labels' || interactionMode == 'edit-lines';
7686
+ interactionMode == 'labels' || interactionMode == 'drawing';
7671
7687
  }
7672
7688
 
7673
7689
  function clickable() {
7674
7690
  // click used to pin popup and select features
7675
7691
  return interactionMode == 'data' || interactionMode == 'info' ||
7676
- // interactionMode == 'edit-lines';
7677
7692
  interactionMode == 'selection' || interactionMode == 'rectangles';
7678
7693
  }
7679
7694
 
@@ -7710,7 +7725,7 @@
7710
7725
  };
7711
7726
 
7712
7727
  // manually set the selected feature id(s)
7713
- // used when hit detection is turned off, e.g. 'edit-lines' mode
7728
+ // used when hit detection is turned off, e.g. 'drawing' mode
7714
7729
  self.setDrawingId = function(id) {
7715
7730
  if (id == drawingId) return;
7716
7731
  drawingId = id >= 0 ? id : -1;
@@ -7733,12 +7748,14 @@
7733
7748
  if (!active || !p) return;
7734
7749
  if (p2 && p2[0] == p[0] && p2[1] == p[1]) return;
7735
7750
  storedData.hit_coordinates = p;
7751
+ storedData.hit_type = type || '';
7736
7752
  triggerHitEvent('change');
7737
7753
  };
7738
7754
 
7739
7755
  self.clearHoverVertex = function() {
7740
7756
  if (!storedData.hit_coordinates) return;
7741
7757
  delete storedData.hit_coordinates;
7758
+ delete storedData.hit_type;
7742
7759
  triggerHitEvent('change');
7743
7760
  };
7744
7761
 
@@ -7820,7 +7837,7 @@
7820
7837
  if (clickable()) {
7821
7838
  updateSelectionState(convertClickDataToSelectionData(hitTest(e)));
7822
7839
  }
7823
- triggerHitEvent('click', e.data);
7840
+ triggerHitEvent('click', e);
7824
7841
  }, null, priority);
7825
7842
 
7826
7843
  // Hits are re-detected on 'hover' (if hit detection is active)
@@ -7926,7 +7943,7 @@
7926
7943
  // check if an event is used in the current interaction mode
7927
7944
  function eventIsEnabled(type) {
7928
7945
  if (!active) return false;
7929
- if (interactionMode == 'edit-lines' && (type == 'hover' || type == 'dblclick')) {
7946
+ if (interactionMode == 'drawing' && (type == 'hover' || type == 'dblclick')) {
7930
7947
  return true; // special case -- using hover for line drawing animation
7931
7948
  }
7932
7949
 
@@ -7948,10 +7965,18 @@
7948
7965
  return e.x >= 0 && e.y >= 0 && e.x < ext.width() && e.y < ext.height();
7949
7966
  }
7950
7967
 
7968
+ function possiblyStopPropagation(e) {
7969
+ if (interactionMode == 'drawing') {
7970
+ // handled conditionally in the control
7971
+ return;
7972
+ }
7973
+ e.stopPropagation();
7974
+ }
7975
+
7951
7976
  function handlePointerEvent(e) {
7952
7977
  if (eventIsEnabled(e.type)) {
7953
- e.stopPropagation(); // block navigation
7954
- triggerHitEvent(e.type, e.data);
7978
+ possiblyStopPropagation(e);
7979
+ triggerHitEvent(e.type, e);
7955
7980
  }
7956
7981
  }
7957
7982
 
@@ -7959,10 +7984,12 @@
7959
7984
  function triggerHitEvent(type, evt) {
7960
7985
  var eventData = {
7961
7986
  mode: interactionMode,
7962
- overMap: evt ? isOverMap(evt) : null
7987
+ overMap: evt ? isOverMap(evt) : null,
7988
+ originalEvent: evt ? evt : null
7963
7989
  };
7964
7990
  // Merge stored hit data into the event data
7965
- utils$1.extend(eventData, evt || {}, storedData);
7991
+ utils$1.defaults(eventData, evt && evt.data || {}, storedData);
7992
+ // utils.extend(eventData, storedData);
7966
7993
  if (transientIds.length) {
7967
7994
  // add transient ids to any other hit ids
7968
7995
  eventData.ids = utils$1.uniq(transientIds.concat(eventData.ids || []));
@@ -9235,6 +9262,7 @@
9235
9262
  } else {
9236
9263
  rec = getMultiRecord(recIds, table);
9237
9264
  }
9265
+ rec = rec || {};
9238
9266
  utils$1.forEachProperty(rec, function(v, k) {
9239
9267
  // missing GeoJSON fields are set to undefined on import; skip these
9240
9268
  if (v === undefined) return;
@@ -9675,32 +9703,31 @@
9675
9703
  }
9676
9704
 
9677
9705
  // pointer thresholds for hovering near a vertex or segment midpoint
9678
- var HOVER_THRESHOLD$1 = 8;
9679
- var MIDPOINT_THRESHOLD$1 = 11;
9706
+ var HOVER_THRESHOLD$1 = 10;
9680
9707
 
9681
9708
  function initLineEditing(gui, ext, hit) {
9682
- var insertionPoint; // not used in this mode
9683
- var dragVertexInfo;
9684
9709
  var hoverVertexInfo;
9685
9710
  var prevClickEvent;
9686
9711
  var prevHoverEvent;
9712
+ var initialArcCount = -1;
9687
9713
  var drawingId = -1; // feature id of path being drawn
9714
+ var alert;
9715
+ var _dragging = false;
9688
9716
 
9689
9717
  function active() {
9690
- return gui.interaction.getMode() == 'edit-lines';
9718
+ return !!alert;
9691
9719
  }
9692
9720
 
9693
9721
  function dragging() {
9694
- return active() && !!dragVertexInfo;
9722
+ return _dragging;
9695
9723
  }
9696
9724
 
9697
9725
  function drawing() {
9698
9726
  return drawingId > -1;
9699
9727
  }
9700
9728
 
9701
- function setHoverVertex(id) {
9702
- var target = hit.getHitTarget();
9703
- hit.setHoverVertex(target.arcs.getVertex2(id));
9729
+ function polygonMode() {
9730
+ return active() && hit.getHitTarget().layer.geometry_type == 'polygon';
9704
9731
  }
9705
9732
 
9706
9733
  function clearHoverVertex() {
@@ -9708,12 +9735,15 @@
9708
9735
  hoverVertexInfo = null;
9709
9736
  }
9710
9737
 
9738
+ gui.addMode('drawing_tool', turnOn, turnOff);
9739
+
9711
9740
  gui.on('interaction_mode_change', function(e) {
9712
- gui.container.findChild('.map-layers').classed('edit-lines', e.mode == 'edit-lines');
9713
- if (e.mode == 'edit-lines') {
9714
- turnOn();
9715
- } else {
9716
- turnOff();
9741
+ gui.container.findChild('.map-layers').classed('drawing', e.mode == 'drawing');
9742
+ var prevMode = gui.getMode();
9743
+ if (e.mode == 'drawing') {
9744
+ gui.enterMode('drawing_tool');
9745
+ } else if (active()) {
9746
+ gui.clearMode();
9717
9747
  }
9718
9748
  }, null, 10); // higher priority than hit control, so turnOff() has correct hit target
9719
9749
 
@@ -9754,63 +9784,119 @@
9754
9784
  }
9755
9785
  });
9756
9786
 
9757
- function turnOn() {}
9787
+ function turnOn() {
9788
+ var target = hit.getHitTarget();
9789
+ var pathStr = polygonMode() ? 'closed paths' : 'paths';
9790
+ var isMac = navigator.userAgent.includes('Mac');
9791
+ var symbol = isMac ? '⌘' : '^';
9792
+ var msg = `Instructions: Click on the map to draw ${pathStr}. Drag vertices to reshape a path. Type ${symbol}Z/${symbol}Y to undo/redo.`;
9793
+ initialArcCount = hit.getHitTarget().arcs.size();
9794
+ alert = showPopupAlert(msg, null, {non_blocking: true, max_width: '360px'});
9795
+ }
9758
9796
 
9759
9797
  function turnOff() {
9760
9798
  finishPath();
9799
+ if (polygonMode()) {
9800
+ finishPolygons();
9801
+ }
9761
9802
  clearDrawingInfo();
9762
- insertionPoint = null;
9803
+ alert.close();
9804
+ alert = null;
9805
+ initialArcCount = -1;
9806
+ if (gui.interaction.getMode() == 'drawing') {
9807
+ // mode change was not initiated by interactive menu -- turn off interactivity
9808
+ gui.interaction.turnOff();
9809
+ }
9810
+ }
9811
+
9812
+ function finish() {
9813
+ if (polygonMode()) {
9814
+ finishPolygons();
9815
+ }
9816
+ }
9817
+
9818
+ function finishPolygons() {
9819
+ // step1: make a polyline layer containing just newly drawn paths
9820
+ var target = hit.getHitTarget();
9821
+ var newShapeCount = target.arcs.size() - initialArcCount;
9822
+ if (newShapeCount <= 0) return; // no paths added
9823
+ var polygonLyr = target.source.layer;
9824
+ var polygonRecords = polygonLyr.data ? polygonLyr.data.getRecords() : null;
9825
+ var initialShapeCount = polygonLyr.shapes.length - newShapeCount;
9826
+ var templateRecord;
9827
+ if (polygonRecords) {
9828
+ // use one of the newly created records as a template (they should all be the same)
9829
+ templateRecord = polygonRecords.pop();
9830
+ polygonRecords.splice(initialShapeCount); // remove new records
9831
+ }
9832
+ var polylineLyr = {
9833
+ geometry_type: 'polyline',
9834
+ shapes: polygonLyr.shapes.splice(initialShapeCount) // move new shapes to polyline layer
9835
+ };
9836
+
9837
+ // step2: convert polylines to polygons
9838
+ //
9839
+ // create a temp dataset containing both layers (so original arcs are preserved)
9840
+ var tmp = Object.assign({}, target.source.dataset);
9841
+ tmp.layers = tmp.layers.concat(polylineLyr);
9842
+ var outputLayers = mapshaper.cmd.polygons([polylineLyr], tmp, {});
9843
+
9844
+ // step3: add new polygons to the original polygons
9845
+ outputLayers[0].shapes.forEach(function(shp) {
9846
+ var rec = polygonRecords ? internal.copyRecord(templateRecord) : null;
9847
+ polygonLyr.shapes.push(shp);
9848
+ if (polygonRecords) {
9849
+ polygonRecords.push(rec);
9850
+ }
9851
+ });
9852
+
9853
+ // step4: update map
9854
+ gui.model.updated({arc_count: true});
9763
9855
  }
9764
9856
 
9765
9857
  function clearDrawingInfo() {
9766
9858
  hit.clearDrawingId();
9767
9859
  drawingId = -1;
9768
- dragVertexInfo = hoverVertexInfo = null;
9860
+ hoverVertexInfo = null;
9769
9861
  prevClickEvent = prevHoverEvent = null;
9770
9862
  }
9771
9863
 
9772
9864
  hit.on('dragstart', function(e) {
9773
- if (!active()) return;
9774
- if (insertionPoint) {
9775
- var target = hit.getHitTarget();
9776
- insertVertex$1(target, insertionPoint.i, insertionPoint.point);
9777
- dragVertexInfo = {
9778
- target: target,
9779
- insertion: true,
9780
- point: insertionPoint.point,
9781
- ids: [insertionPoint.i]
9782
- };
9783
- insertionPoint = null;
9784
- } else if (!drawing()) {
9785
- dragVertexInfo = findDraggableVertices(e);
9786
- }
9787
- if (dragVertexInfo) {
9788
- setHoverVertex(dragVertexInfo.ids[0]);
9865
+ if (!active() || drawing() || !hoverVertexInfo) return;
9866
+ e.originalEvent.stopPropagation();
9867
+ _dragging = true;
9868
+ if (hoverVertexInfo.type == 'interpolated') {
9869
+ insertVertex$1(hit.getHitTarget(), hoverVertexInfo.i, hoverVertexInfo.point);
9870
+ hoverVertexInfo.ids = [hoverVertexInfo.i];
9789
9871
  }
9872
+ hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type);
9790
9873
  });
9791
9874
 
9792
9875
  hit.on('drag', function(e) {
9793
9876
  if (!dragging() || drawing()) return;
9877
+ e.originalEvent.stopPropagation();
9794
9878
  var target = hit.getHitTarget();
9795
9879
  var p = ext.translatePixelCoords(e.x, e.y);
9796
9880
  if (gui.keyboard.shiftIsPressed()) {
9797
- internal.snapPointToArcEndpoint(p, dragVertexInfo.ids, target.arcs);
9881
+ internal.snapPointToArcEndpoint(p, hoverVertexInfo.ids, target.arcs);
9798
9882
  }
9799
- internal.snapVerticesToPoint(dragVertexInfo.ids, p, target.arcs);
9800
- setHoverVertex(dragVertexInfo.ids[0]);
9883
+ internal.snapVerticesToPoint(hoverVertexInfo.ids, p, target.arcs);
9884
+ hit.setHoverVertex(p, '');
9885
+
9801
9886
  // redrawing the whole map updates the data layer as well as the overlay layer
9802
9887
  // gui.dispatchEvent('map-needs-refresh');
9803
9888
  });
9804
9889
 
9805
9890
  hit.on('dragend', function(e) {
9806
9891
  if (!dragging()) return;
9892
+ _dragging = false;
9807
9893
  // kludge to get dataset to recalculate internal bounding boxes
9808
- hit.getHitTarget().arcs.transformPoints(function() {});
9894
+ var target = hit.getHitTarget();
9895
+ target.arcs.transformPoints(function() {});
9896
+ updateVertexCoords(target, hoverVertexInfo.ids);
9897
+ gui.dispatchEvent('vertex_dragend', hoverVertexInfo);
9898
+ gui.dispatchEvent('map-needs-refresh'); // redraw basemap
9809
9899
  clearHoverVertex();
9810
- updateVertexCoords(dragVertexInfo.target, dragVertexInfo.ids);
9811
- gui.dispatchEvent('vertex_dragend', dragVertexInfo);
9812
- gui.dispatchEvent('map-needs-refresh');
9813
- dragVertexInfo = null;
9814
9900
  });
9815
9901
 
9816
9902
  // shift + double-click deletes a vertex (when not drawing)
@@ -9823,53 +9909,38 @@
9823
9909
  // now: second click is suppressed
9824
9910
  // deleteLastVertex(hit.getHitTarget());
9825
9911
  finishPath();
9826
- e.stopPropagation(); // prevent dblclick zoom
9912
+ e.originalEvent.stopPropagation(); // prevent dblclick zoom
9827
9913
  return;
9828
9914
  }
9829
9915
  });
9830
9916
 
9831
9917
  // hover event highlights the nearest point in close proximity to the pointer
9832
- // ... or the closest segment midpoint (for adding a new vertex)
9918
+ // ... or the closest point along the segment (for adding a new vertex)
9833
9919
  hit.on('hover', function(e) {
9834
9920
  if (!active() || dragging()) return;
9835
- if (drawing() && !e.overMap) {
9836
- finishPath();
9837
- return;
9838
- }
9839
9921
  if (drawing()) {
9922
+ if (!e.overMap) {
9923
+ finishPath();
9924
+ return;
9925
+ }
9840
9926
  if (gui.keyboard.shiftIsPressed()) {
9841
9927
  alignPointerPosition(e, prevClickEvent);
9842
9928
  }
9843
9929
  updatePathEndpoint(pixToDataCoords(e.x, e.y));
9844
-
9845
- // highlight nearby snappable vertex (the closest vertex on a nearby line,
9846
- // or the first vertex of the current drawing path if not near a line)
9847
- hoverVertexInfo = e.id >= 0 && findDraggableVertices(e) || findPathStartInfo(e);
9848
- if (hoverVertexInfo) {
9849
- // hovering near a vertex: highlight the vertex
9850
- setHoverVertex(hoverVertexInfo.ids[0]);
9851
- } else {
9852
- clearHoverVertex();
9853
- }
9854
- prevHoverEvent = e;
9855
- return;
9856
9930
  }
9857
- if (e.id >= 0 === false) {
9858
- // pointer is not near a path
9859
- return;
9860
- }
9861
- hoverVertexInfo = findDraggableVertices(e);
9862
- insertionPoint = hoverVertexInfo ? null : findMidpointInsertionPoint(e);
9931
+
9932
+ // highlight nearby snappable vertex (the closest vertex on a nearby line,
9933
+ // or the first vertex of the current drawing path if not near a line)
9934
+ hoverVertexInfo = e.id >= 0 && findDraggableVertices(e) ||
9935
+ drawing() && findPathStartInfo(e) ||
9936
+ e.id >= 0 && findInterpolatedPoint(e);
9863
9937
  if (hoverVertexInfo) {
9864
9938
  // hovering near a vertex: highlight the vertex
9865
- setHoverVertex(hoverVertexInfo.ids[0]);
9866
- } else if (insertionPoint) {
9867
- // hovering near a segment midpoint: highlight the midpoint
9868
- hit.setHoverVertex(insertionPoint.displayPoint);
9939
+ hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type);
9869
9940
  } else {
9870
- // pointer is not over a vertex: clear any hover effect
9871
9941
  clearHoverVertex();
9872
9942
  }
9943
+ prevHoverEvent = e;
9873
9944
  }, null, 100);
9874
9945
 
9875
9946
  // click starts or extends a new path
@@ -9899,6 +9970,7 @@
9899
9970
  }
9900
9971
  });
9901
9972
 
9973
+ // detect second 'click' event of a double-click action
9902
9974
  function detectDoubleClick(evt) {
9903
9975
  if (!prevClickEvent) return false;
9904
9976
  var elapsed = evt.time - prevClickEvent.time;
@@ -9939,8 +10011,8 @@
9939
10011
  var x0 = prevEvt.x;
9940
10012
  var y0 = prevEvt.y;
9941
10013
  var dist = geom.distance2D(thisEvt.x, thisEvt.y, x0, y0);
9942
- var dist2 = dist / Math.sqrt(2);
9943
10014
  if (dist < 1) return;
10015
+ var dist2 = dist / Math.sqrt(2);
9944
10016
  var minDist = Infinity;
9945
10017
  var cands = [
9946
10018
  {x: x0, y: y0 + dist},
@@ -9976,23 +10048,20 @@
9976
10048
  gui.model.updated({arc_count: true});
9977
10049
  }
9978
10050
 
9979
- function startPath(p) {
10051
+ // p: [x, y] source data coordinates
10052
+ function startPath(p2) {
9980
10053
  var target = hit.getHitTarget();
9981
- var p1 = hoverVertexInfo ? getVertexCoords(target, hoverVertexInfo.ids[0]) : p;
9982
- var p2 = p;
10054
+ var p1 = hoverVertexInfo ? hoverVertexInfo.point : p2;
9983
10055
  appendNewPath(target, p1, p2);
9984
10056
  gui.dispatchEvent('path_add', {target, p1, p2});
9985
10057
  drawingId = target.layer.shapes.length - 1;
9986
10058
  hit.setDrawingId(drawingId);
9987
10059
  }
9988
10060
 
10061
+ // p: [x, y] source data coordinates
9989
10062
  function extendPath(p) {
9990
10063
  var target = hit.getHitTarget();
9991
- var len = getLastArcLength(target);
9992
- if (false && len == 2) {
9993
- var pathCoords = getLastArcCoords(target);
9994
- gui.dispatchEvent('path_add', {target, p1: pathCoords[0], p2: pathCoords[1]});
9995
- } else if (len >= 2) {
10064
+ if (getLastArcLength(target) >= 2) {
9996
10065
  gui.dispatchEvent('path_extend', {target, p});
9997
10066
  }
9998
10067
  appendVertex$1(target, p);
@@ -10004,7 +10073,7 @@
10004
10073
  var target = hit.getHitTarget();
10005
10074
  var i = target.arcs.getPointCount() - 1;
10006
10075
  if (hoverVertexInfo) {
10007
- p = getVertexCoords(target, hoverVertexInfo.ids[0]); // snap to selected point
10076
+ p = hoverVertexInfo.point; // snap to selected point
10008
10077
  }
10009
10078
  setVertexCoords(target, [i], p);
10010
10079
  hit.triggerChangeEvent();
@@ -10014,9 +10083,9 @@
10014
10083
  var target = hit.getHitTarget();
10015
10084
  var arcId = target.arcs.size() - 1;
10016
10085
  var data = target.arcs.getVertexData();
10017
- var id = data.ii[arcId];
10018
- var x = data.xx[id];
10019
- var y = data.yy[id];
10086
+ var i = data.ii[arcId];
10087
+ var x = data.xx[i];
10088
+ var y = data.yy[i];
10020
10089
  var p = ext.translatePixelCoords(e.x, e.y);
10021
10090
  var dist = geom.distance2D(p[0], p[1], x, y);
10022
10091
  var pathLen = data.nn[arcId];
@@ -10026,7 +10095,7 @@
10026
10095
  }
10027
10096
  var point = translateDisplayPoint(target, [x, y]);
10028
10097
  return {
10029
- target, ids: [id], extendable: false, point
10098
+ target, ids: [i], extendable: false, point, displayPoint: [x, y], type: 'vertex'
10030
10099
  };
10031
10100
  }
10032
10101
 
@@ -10049,50 +10118,48 @@
10049
10118
  // (which could be extended by a newly drawn path)
10050
10119
  var extendable = ids.length == 1 &&
10051
10120
  internal.vertexIsArcEndpoint(ids[0], target.arcs);
10052
- return {target, ids, extendable, point};
10121
+ var displayPoint = target.arcs.getVertex2(ids[0]);
10122
+ return {target, ids, extendable, point, displayPoint, type: 'vertex'};
10053
10123
  }
10054
10124
 
10055
- function findMidpointInsertionPoint(e) {
10125
+ function findInterpolatedPoint(e) {
10056
10126
  var target = hit.getHitTarget();
10057
10127
  //// vertex insertion not supported with simplification
10058
10128
  // if (!target.arcs.isFlat()) return null;
10059
10129
  var p = ext.translatePixelCoords(e.x, e.y);
10060
- var midpoint = findNearestMidpoint$1(p, e.id, target);
10061
- if (!midpoint ||
10062
- midpoint.distance / ext.getPixelSize() > MIDPOINT_THRESHOLD$1) return null;
10063
- return midpoint;
10064
- }
10065
- }
10066
-
10130
+ var minDist = Infinity;
10131
+ var shp = target.layer.shapes[e.id];
10132
+ var closest;
10133
+ internal.forEachSegmentInShape(shp, target.arcs, function(i, j, xx, yy) {
10134
+ var x1 = xx[i],
10135
+ y1 = yy[i],
10136
+ x2 = xx[j],
10137
+ y2 = yy[j],
10138
+ // switching from midpoint to nearest point to the mouse
10139
+ // cx = (x1 + x2) / 2,
10140
+ // cy = (y1 + y2) / 2,
10141
+ // p2 = [cx, cy],
10142
+ p2 = internal.findClosestPointOnSeg(p[0], p[1], x1, y1, x2, y2, 0),
10143
+ dist = geom.distance2D(p2[0], p2[1], p[0], p[1]);
10144
+ if (dist < minDist) {
10145
+ minDist = dist;
10146
+ closest = {
10147
+ i: (i < j ? i : j) + 1, // insertion vertex id
10148
+ displayPoint: p2,
10149
+ distance: dist
10150
+ };
10151
+ }
10152
+ });
10067
10153
 
10068
- // Given a location @p (e.g. corresponding to the mouse pointer location),
10069
- // find the midpoint of two vertices on @shp suitable for inserting a new vertex
10070
- function findNearestMidpoint$1(p, fid, target) {
10071
- var arcs = target.arcs;
10072
- var shp = target.layer.shapes[fid];
10073
- var minDist = Infinity, v;
10074
- internal.forEachSegmentInShape(shp, arcs, function(i, j, xx, yy) {
10075
- var x1 = xx[i],
10076
- y1 = yy[i],
10077
- x2 = xx[j],
10078
- y2 = yy[j],
10079
- cx = (x1 + x2) / 2,
10080
- cy = (y1 + y2) / 2,
10081
- midpoint = [cx, cy],
10082
- dist = geom.distance2D(cx, cy, p[0], p[1]);
10083
- if (dist < minDist) {
10084
- minDist = dist;
10085
- v = {
10086
- i: (i < j ? i : j) + 1, // insertion point
10087
- segment: [i, j],
10088
- segmentLen: geom.distance2D(x1, y1, x2, y2),
10089
- displayPoint: midpoint,
10090
- point: translateDisplayPoint(target, midpoint),
10091
- distance: dist
10092
- };
10154
+ if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD$1) {
10155
+ return null;
10093
10156
  }
10094
- });
10095
- return v || null;
10157
+ closest.point = translateDisplayPoint(target, closest.displayPoint);
10158
+ closest.type = 'interpolated';
10159
+ closest.target = target;
10160
+ return closest;
10161
+ }
10162
+
10096
10163
  }
10097
10164
 
10098
10165
  function initPointDrawing(gui, ext, hit) {
@@ -10839,7 +10906,7 @@
10839
10906
  var iter = new internal.ShapeIter(arcs);
10840
10907
  var t = getScaledTransform(_ext);
10841
10908
  var bounds = _ext.getBounds();
10842
- var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext, style);
10909
+ var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 1.8) * GUI.getPixelRatio() * getScaledLineScale(_ext, style);
10843
10910
  var color = style.strokeColor || 'black';
10844
10911
 
10845
10912
  var i, j, p;
@@ -10863,7 +10930,8 @@
10863
10930
  _ctx.beginPath();
10864
10931
  _ctx.fillStyle = style.vertex_overlay_color || 'black';
10865
10932
  p = style.vertex_overlay;
10866
- drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius * 2, _ctx);
10933
+ drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius *
10934
+ (style.vertex_overlay_scale || 2), _ctx);
10867
10935
  _ctx.fill();
10868
10936
  _ctx.closePath();
10869
10937
  }
@@ -11696,6 +11764,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
11696
11764
 
11697
11765
  // Only generate low-detail arcs for larger datasets
11698
11766
  if (size > 5e5) {
11767
+ update();
11768
+ }
11769
+
11770
+ function update() {
11699
11771
  if (unfilteredArcs.getVertexData().zz) {
11700
11772
  // Use precalculated simplification data for vertex filtering, if available
11701
11773
  filteredArcs = initFilteredArcs(unfilteredArcs);
@@ -11719,6 +11791,14 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
11719
11791
 
11720
11792
  // TODO: better job of detecting arc change... e.g. revision number
11721
11793
  unfilteredArcs.getScaledArcs = function(ext) {
11794
+ // check for changes in the number of arcs (probably due to editing)
11795
+ if (filteredArcs && filteredArcs.size() != unfilteredArcs.size()) {
11796
+ // arc count has changed... probably due to editing
11797
+ update();
11798
+ if (filteredArcs.size() != unfilteredArcs.size()) {
11799
+ throw Error('Internal error');
11800
+ }
11801
+ }
11722
11802
  if (filteredArcs) {
11723
11803
  // match simplification of unfiltered arcs
11724
11804
  filteredArcs.setRetainedInterval(unfilteredArcs.getRetainedInterval());
@@ -12426,7 +12506,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
12426
12506
  }
12427
12507
 
12428
12508
  function getStrictBounds() {
12429
- if (internal.isWebMercator(map.getDisplayCRS())) {
12509
+ // if (internal.isWebMercator(map.getDisplayCRS())) {
12510
+ if (_dynamicCRS && internal.isWebMercator(map.getDisplayCRS())) {
12430
12511
  return getMapboxBounds();
12431
12512
  }
12432
12513
  return null;
package/www/mapshaper.js CHANGED
@@ -3208,13 +3208,13 @@
3208
3208
  // Used by mapshaper-undershoots.js
3209
3209
  // TODO: make more robust, make sure result is compatible with segmentIntersection()
3210
3210
  // (rounding errors currently must be handled downstream)
3211
- function findClosestPointOnSeg(px, py, ax, ay, bx, by) {
3211
+ function findClosestPointOnSeg(px, py, ax, ay, bx, by, snapArg) {
3212
3212
  var dx = bx - ax,
3213
3213
  dy = by - ay,
3214
3214
  dotp = (px - ax) * dx + (py - ay) * dy,
3215
3215
  abSq = dx * dx + dy * dy,
3216
3216
  k = abSq === 0 ? -1 : dotp / abSq,
3217
- eps = 0.1, // 1e-6, // snap to endpoint
3217
+ eps = snapArg >= 0 ? snapArg : 0.1, // 1e-6, // snap to endpoint
3218
3218
  p;
3219
3219
  if (k <= eps) {
3220
3220
  p = [ax, ay];
@@ -5553,43 +5553,35 @@
5553
5553
  }
5554
5554
 
5555
5555
  function initBounds() {
5556
- var data = calcArcBounds2(_xx, _yy, _nn);
5557
- _bb = data.bb;
5558
- _allBounds = data.bounds;
5559
- }
5560
-
5561
- function calcArcBounds2(xx, yy, nn) {
5562
- var numArcs = nn.length,
5563
- bb = new Float64Array(numArcs * 4),
5564
- bounds = new Bounds(),
5565
- arcOffs = 0,
5566
- arcLen,
5567
- j, b;
5556
+ var numArcs = _nn.length;
5557
+ _bb = new Float64Array(numArcs * 4);
5558
+ _allBounds = new Bounds();
5568
5559
  for (var i=0; i<numArcs; i++) {
5569
- arcLen = nn[i];
5570
- if (arcLen > 0) {
5571
- j = i * 4;
5572
- b = calcArcBounds(xx, yy, arcOffs, arcLen);
5573
- bb[j++] = b[0];
5574
- bb[j++] = b[1];
5575
- bb[j++] = b[2];
5576
- bb[j] = b[3];
5577
- arcOffs += arcLen;
5578
- bounds.mergeBounds(b);
5579
- }
5560
+ initArcBounds(i);
5580
5561
  }
5581
- return {
5582
- bb: bb,
5583
- bounds: bounds
5584
- };
5585
5562
  }
5586
5563
 
5564
+ function initArcBounds(i) {
5565
+ var arcLen = _nn[i];
5566
+ var arcOffs = _ii[i];
5567
+ var j = i * 4;
5568
+ var b = calcArcBounds(_xx, _yy, arcOffs, arcLen);
5569
+ _bb[j++] = b[0];
5570
+ _bb[j++] = b[1];
5571
+ _bb[j++] = b[2];
5572
+ _bb[j] = b[3];
5573
+ _allBounds.mergeBounds(b);
5574
+ }
5575
+
5576
+ this.updateArcBounds = function(arcId) {
5577
+ initArcBounds(arcId);
5578
+ };
5579
+
5587
5580
  this.updateVertexData = function(nn, xx, yy, zz) {
5588
5581
  initXYData(nn, xx, yy);
5589
5582
  initZData(zz || null);
5590
5583
  };
5591
5584
 
5592
-
5593
5585
  this.getCopy = function() {
5594
5586
  var copy = new ArcCollection(new Int32Array(_nn), new Float64Array(_xx),
5595
5587
  new Float64Array(_yy));
@@ -13194,13 +13186,14 @@
13194
13186
 
13195
13187
 
13196
13188
  function snapVerticesToPoint(ids, p, arcs, final) {
13189
+ var data = arcs.getVertexData();
13197
13190
  ids.forEach(function(idx) {
13191
+ if (final) {
13192
+ // recalculate bounding box for arc
13193
+ arcs.updateArcBounds(findArcIdFromVertexId(idx, data.ii));
13194
+ }
13198
13195
  setVertexCoords(p[0], p[1], idx, arcs);
13199
13196
  });
13200
- if (final) {
13201
- // kludge to get dataset to recalculate internal bounding boxes
13202
- arcs.transformPoints(function() {});
13203
- }
13204
13197
  }
13205
13198
 
13206
13199
 
@@ -45492,7 +45485,7 @@ ${svg}
45492
45485
  });
45493
45486
  }
45494
45487
 
45495
- var version = "0.6.72";
45488
+ var version = "0.6.74";
45496
45489
 
45497
45490
  // Parse command line args into commands and run them
45498
45491
  // Function takes an optional Node-style callback. A Promise is returned if no callback is given.
@@ -46238,6 +46231,7 @@ ${svg}
46238
46231
  Rounding,
46239
46232
  RunCommands,
46240
46233
  Scalebar,
46234
+ SegmentGeom,
46241
46235
  SegmentIntersection,
46242
46236
  ShapeIter$1,
46243
46237
  ShapeUtils,
package/www/page.css CHANGED
@@ -276,7 +276,15 @@ body {
276
276
  left: 0;
277
277
  }
278
278
 
279
- .alert-wrapper p.error-message {
279
+ .alert-wrapper.non-blocking {
280
+ pointer-events: none;
281
+ }
282
+
283
+ .non-blocking > div {
284
+ pointer-events: auto;
285
+ }
286
+
287
+ .alert-wrapper p.alert-message {
280
288
  margin: 1px 0 0 0;
281
289
  }
282
290
 
@@ -286,7 +294,7 @@ body {
286
294
  margin-bottom: 7px;
287
295
  }
288
296
 
289
- div.alert-title, div.error-message {
297
+ div.alert-title, div.alert-message {
290
298
  font-size: 16px;
291
299
  }
292
300
 
@@ -1194,7 +1202,7 @@ div.basemap-style-btn.active img {
1194
1202
  }
1195
1203
 
1196
1204
  .map-layers.add-points,
1197
- .map-layers.edit-lines {
1205
+ .map-layers.drawing {
1198
1206
  cursor: crosshair;
1199
1207
  }
1200
1208