mapshaper 0.6.108 → 0.6.110

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.6.108",
3
+ "version": "0.6.110",
4
4
  "description": "A tool for editing vector datasets for mapping and GIS.",
5
5
  "keywords": [
6
6
  "shapefile",
@@ -43,6 +43,7 @@
43
43
  "@tmcw/togeojson": "^5.6.0",
44
44
  "@xmldom/xmldom": "^0.8.6",
45
45
  "adm-zip": "^0.5.9",
46
+ "big.js": "^7.0.1",
46
47
  "commander": "7.0.0",
47
48
  "cookies": "^0.8.0",
48
49
  "d3-color": "3.1.0",
package/www/elements.css CHANGED
@@ -131,7 +131,7 @@ div.tip {
131
131
  .btn {
132
132
  text-align: center;
133
133
  /* padding: 4px 7px 5px 7px; */
134
- padding: 3px 6px 4px 6px;
134
+ padding: 5px 6px 4px 6px;
135
135
  border-radius: 4px;
136
136
  line-height: 1;
137
137
  display: inline-block;
package/www/index.html CHANGED
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html lang="en">
3
3
  <head>
4
4
  <title>mapshaper</title>
5
5
  <meta name="Description" content="A tool for topologically aware shape simplification. Reads and writes Shapefile, GeoJSON and TopoJSON formats.">
@@ -42,24 +42,6 @@
42
42
  <svg id="ribbon-icon" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="15" height="25" viewBox="0 1 15 20">
43
43
  <polygon points="8 14.5 13 19 13 4 3 4 3 19 8 14.5" fill="#30d4ef"/>
44
44
  </svg>
45
-
46
- <defs>
47
- <style>
48
- .cls-1 {
49
- fill: #0c0a0a;
50
- }
51
- </style>
52
- </defs>
53
- <g id="left_arrow">
54
- <polygon class="cls-1" points="0.5 6 6.5 11.5 6.5 0.5 0.5 6"/>
55
- </g>
56
- </svg>
57
-
58
- <svg id="info-menu-icon" xmlns="http://www.w3.org/2000/svg" width="8" height="12" viewBox="0 0 8 12">
59
- <g id="left_arrow">
60
- <polygon class="cls-1" points="0.5 6 6.5 11.5 6.5 0.5 0.5 6"/>
61
- </g>
62
- </svg>
63
45
 
64
46
  </div>
65
47
 
@@ -70,13 +52,15 @@
70
52
 
71
53
  <div class="simplify-control-wrapper"><div class="simplify-control"><div class="header-btn btn simplify-settings-btn">Settings</div>
72
54
  <div class="slider">
73
- <div class="handle"><img src="images/slider_handle_v1.png" alt=""/></div>
55
+ <div class="handle"><img src="images/slider_handle_v1.png" alt=""></div>
74
56
  <div class="track"></div>
75
57
  </div>
76
- <input type="text" value="label" class="clicktext" />
58
+ <input type="text" value="label" class="clicktext">
59
+ <!-- <div class="header-btn btn simplify-done-btn">Done</div> -->
77
60
  </div></div>
78
61
  <div id="mode-buttons" class="page-header-buttons">
79
- <span class="console-btn header-btn btn">Console</span><span class="display-btn header-btn btn">Display</span><span class="separator"></span><span class="separator"></span><span class="simplify-btn header-btn btn">Simplify</span><span class="separator"></span><span class="export-btn header-btn btn">Export</span>
62
+ <!-- <span class="project-btn header-btn btn">Project</span><span class="separator"> -->
63
+ <span class="console-btn header-btn btn">Console</span><span class="display-btn header-btn btn">Display</span><span class="separator"></span><span class="separator"></span></span><span class="simplify-btn header-btn btn">Simplify</span><span class="separator"></span><span class="export-btn header-btn btn">Export</span>
80
64
  </div>
81
65
  <div id="splash-buttons" class="page-header-buttons">
82
66
  <a href="https://github.com/mbloch/mapshaper/wiki"><span id="wiki-btn" class="header-btn btn">Wiki</span></a><span class="separator"></span><a href="https://github.com/mbloch/mapshaper"><span id="github-btn" class="header-btn btn">GitHub</span></a>
@@ -96,8 +80,8 @@
96
80
  <div class="layer-menu">
97
81
  <h3>Layers</h3>
98
82
  <div class="pin-all pinnable">
99
- <img class="eye-btn black-eye" src="images/eye.png">
100
- <img class="eye-btn green-eye" src="images/eye2.png">
83
+ <img class="eye-btn black-eye" src="images/eye.png" alt="">
84
+ <img class="eye-btn green-eye" src="images/eye2.png" alt="">
101
85
  </div>
102
86
  <div class="layer-list"></div>
103
87
  <!-- <h4>Sources</h4> -->
@@ -146,7 +130,7 @@
146
130
  <div class="info-box">
147
131
  <div class="close2-btn"></div>
148
132
  <h3>Export options</h3>
149
- <div class=export-layers>
133
+ <div class="export-layers">
150
134
  <h4 class="menu-title">Layers</h4>
151
135
  <div class="export-layer-list option-menu"></div>
152
136
  </div>
@@ -161,8 +145,8 @@
161
145
 
162
146
  <div style="height:11px"></div>
163
147
 
164
- <div class="option-menu"><input type="text" class="text-input advanced-options" placeholder="command line options" />
165
- <a href="https://github.com/mbloch/mapshaper/wiki/Command-Reference#-o-output" target="_mapshaper_output_docs">
148
+ <div class="option-menu"><input type="text" class="text-input advanced-options" placeholder="command line options">
149
+ <a href="https://github.com/mbloch/mapshaper/wiki/Command-Reference#-o-output" target="mapshaper_output_docs">
166
150
  <div class="tip-button">?<div class="tip-anchor">
167
151
  <div class="tip">Enter options from the command line interface for
168
152
  the -o command. Examples: bbox no-quantization
@@ -171,8 +155,8 @@ precision=0.001. Click to see all options.</div></div></div></a>
171
155
  <!-- <div class="option-menu">
172
156
  <input id="ofile-name" class="text-input" type="text" placeholder="output file name" />
173
157
  </div> -->
174
- <div><span id="save-preference" style="display: none;"><input type="checkbox"/>choose output directory</span></div>
175
- <div><span id="save-to-clipboard" style="display: inline-block;"><input type="checkbox"/>save to clipboard</span></div>
158
+ <div><span id="save-preference" style="display: none;"><input type="checkbox">choose output directory</span></div>
159
+ <div><span id="save-to-clipboard" style="display: inline-block;"><input type="checkbox">save to clipboard</span></div>
176
160
  </div>
177
161
  <div id="export-btn" class="btn dialog-btn" style="margin-top: 5px;">Export</div>
178
162
 
@@ -184,8 +168,8 @@ precision=0.001. Click to see all options.</div></div></div></a>
184
168
  <div class="close2-btn"></div>
185
169
  <h3>Display options</h3>
186
170
 
187
- <div class=""><label for="intersections-opt"><input type="checkbox" id="intersections-opt" class="checkbox intersections-opt"/>detect line intersections</label></div>
188
- <div class=""><label for="ghost-opt"><input type="checkbox" id="ghost-opt" class="checkbox ghost-opt"/>show reference lines</label></div>
171
+ <div class=""><label><input type="checkbox" id="intersections-opt" class="checkbox intersections-opt">detect line intersections</label></div>
172
+ <div class=""><label><input type="checkbox" id="ghost-opt" class="checkbox ghost-opt">show reference lines</label></div>
189
173
 
190
174
  <div class="basemap-opts">
191
175
  <h4>Basemaps</h4>
@@ -202,18 +186,33 @@ precision=0.001. Click to see all options.</div></div></div></a>
202
186
  </div>
203
187
  </div>
204
188
 
189
+ <div class="project-options main-area popup-dialog popup-align-left">
190
+ <div class="info-box">
191
+ <div class="close2-btn"></div>
192
+ <h3>Projections</h3>
193
+ <div class="option-menu">
194
+ <div id="proj-list"></div>
195
+ <div id="proj-option-list"></div>
196
+ </div>
197
+ <div>
198
+ <div class="preview-btn btn dialog-btn">Preview</div>
199
+ <div class="apply-btn btn dialog-btn">Apply</div>
200
+ </div>
201
+ </div>
202
+ </div>
203
+
205
204
  <div class="simplify-options main-area popup-dialog">
206
205
  <div class="info-box">
207
206
  <div class="close2-btn"></div>
208
207
  <h3>Simplification</h3>
209
208
  <div class="option-menu">
210
- <div><label for="import-retain-opt"><input type="checkbox" class="checkbox import-retain-opt"/>prevent shape removal</label>
209
+ <div><label><input type="checkbox" class="checkbox import-retain-opt" id="import-retain-opt">prevent shape removal</label>
211
210
  <div class="tip-button">?<div class="tip-anchor">
212
211
  <div class="tip">Prevent small polygon features from
213
212
  disappearing at high simplification. Keeps
214
213
  the largest ring of multi-ring features.
215
214
  </div></div></div></div>
216
- <div class="planar-opt-wrapper"><label for="planar-opt"><input type="checkbox" class="checkbox planar-opt"/>use planar geometry</label>
215
+ <div class="planar-opt-wrapper"><label><input type="checkbox" class="checkbox planar-opt" id="planar-opt">use planar geometry</label>
217
216
  <div class="tip-button">?<div class="tip-anchor">
218
217
  <div class="tip">Treat x, y values as Cartesian coordinates
219
218
  on a plane, rather than as longitude, latitude
@@ -229,7 +228,7 @@ coordinates on a sphere.
229
228
  distance of original lines. Good for
230
229
  thinning dense points, but spikes
231
230
  tend to form at high simplification.</div></div></div>
232
- </div>
231
+ </div>
233
232
 
234
233
  <div><label><input type="radio" name="method" value="visvalingam" class="radio">Visvalingam / effective area</label><div class="tip-button">?<div class="tip-anchor">
235
234
  <div class="tip">Lines are simplified by iteratively
@@ -258,7 +257,7 @@ a smoother appearance.</div></div></div></div>
258
257
  <div class="cancel-btn close2-btn"></div>
259
258
  <h3 class="list-header">Import files</h3>
260
259
  <div class="import-instructions">
261
- <span><input type="checkbox" class="advanced-import-options" />with advanced options</span>
260
+ <span><input type="checkbox" class="advanced-import-options">with advanced options</span>
262
261
  <div class="mini-drop-area">
263
262
  <div class="subtitle">Drop, paste or <span class="add-btn inline-btn btn"><span class="label-text">select</span></span> files to import.</div>
264
263
  <div class="subtitle">Shapefile, GeoJSON, TopoJSON, KML and CSV formats are supported. Files can be zipped or gzipped.</div>
@@ -267,29 +266,24 @@ a smoother appearance.</div></div></div></div>
267
266
  <div class="queued-file-section">
268
267
  <!-- <h4>Files</h4> -->
269
268
  <div class="dropped-file-list"></div>
270
-
271
269
  <div class="option-menu">
272
-
273
- <div id="path-import-options">
274
- <!-- <h4>Options</h4> -->
270
+ <div id="path-import-options">
275
271
  </div>
276
-
277
- <div style="margin-top: 10px"><input type="text" class="text-input advanced-options" placeholder="import options" />
278
- <a href="https://github.com/mbloch/mapshaper/wiki/Command-Reference#-i-input" target="_mapshaper_import_docs">
272
+ <div style="margin-top: 10px"><input type="text" class="text-input advanced-options" placeholder="import options">
273
+ <a href="https://github.com/mbloch/mapshaper/wiki/Command-Reference#-i-input" target="mapshaper_import_docs">
279
274
  <div class="tip-button">?<div class="tip-anchor">
280
275
  <div class="tip">Enter options from the command line
281
276
  interface. Examples: <span id="import-option-examples">snap no-topology
282
- encoding=big5</span>. Click to see all options.</div></div></div></div>
277
+ encoding=big5</span>. Click to see all options.</div></div></div>
283
278
  </a>
284
-
285
279
  </div>
286
280
 
287
281
  <!-- <div class="cancel-btn btn dialog-btn">Cancel</div>
288
282
  <div class="add-btn btn dialog-btn">Select</div> -->
289
283
  <div class="submit-btn btn dialog-btn default-btn disabled">Submit</div>
290
284
 
285
+ </div>
291
286
  </div>
292
-
293
287
  </div> <!-- .info-box -->
294
288
  </div> <!-- import-options -->
295
289
 
@@ -310,14 +304,14 @@ encoding=big5</span>. Click to see all options.</div></div></div></div>
310
304
  </div>
311
305
  </div>
312
306
 
313
- <div id="import-options-drop-area" class="main-area drop-area-wrapper hidden">
307
+ <div id="import-options-drop-area" class="main-area drop-area-wrapper hidden">
314
308
  <div class="drop-area"></div>
315
309
  </div>
316
310
 
317
- <script src="basemap.js" type="text/javascript"></script>
318
- <script src="modules.js" type="text/javascript"></script>
319
- <script src="mapshaper.js" type="text/javascript"></script>
320
- <script src="manifest.js" type="text/javascript"></script>
321
- <script src="mapshaper-gui.js" type="text/javascript"></script>
311
+ <script src="basemap.js"></script>
312
+ <script src="modules.js"></script>
313
+ <script src="mapshaper.js"></script>
314
+ <script src="manifest.js"></script>
315
+ <script src="mapshaper-gui.js"></script>
322
316
  </body>
323
317
  </html>
@@ -2726,11 +2726,12 @@
2726
2726
  // p1: [x, y] coords
2727
2727
  // p2: [x, y] coords offset by 1x1 pixel
2728
2728
  function formatCoordsForDisplay(p1, p2) {
2729
+ var maxD = 13;
2729
2730
  var dx = Math.abs(p1[0] - p2[0]);
2730
2731
  var dy = Math.abs(p1[1] - p2[1]);
2731
2732
  var offs = (dx + dy) / 2;
2732
2733
  var decimals = 0;
2733
- while (offs < 1 && decimals < 6) {
2734
+ while (offs < 1 && decimals <= maxD) {
2734
2735
  offs *= 10;
2735
2736
  decimals++;
2736
2737
  }
@@ -3226,18 +3227,20 @@
3226
3227
  }
3227
3228
 
3228
3229
  // p1, p2: two points in source data CRS coords.
3229
- function appendNewPath(lyr, p1, p2) {
3230
+ function appendNewPath(lyr, points) {
3230
3231
  var arcId = lyr.gui.displayArcs.size();
3231
3232
  internal.appendEmptyArc(lyr.gui.displayArcs);
3232
3233
  lyr.shapes.push([[arcId]]);
3233
3234
  if (isProjectedLayer(lyr)) {
3234
3235
  internal.appendEmptyArc(lyr.gui.source.dataset.arcs);
3235
3236
  }
3236
- appendVertex$1(lyr, p1);
3237
- appendVertex$1(lyr, p2);
3237
+ points.forEach(function(p) {
3238
+ appendVertex$1(lyr, p);
3239
+ });
3238
3240
  appendNewDataRecord(lyr);
3239
3241
  }
3240
3242
 
3243
+
3241
3244
  function deleteLastPath(lyr) {
3242
3245
  var arcId = lyr.gui.displayArcs.size() - 1;
3243
3246
  if (lyr.data) {
@@ -4309,7 +4312,9 @@
4309
4312
  if (_unsimplifiedXX && action == 'simplify_drag_end') {
4310
4313
  // re-use previously generated intersection data (optimization)
4311
4314
  } else {
4315
+ // console.time('xx');
4312
4316
  _unsimplifiedXX = internal.findSegmentIntersections(arcs, intersectionOpts);
4317
+ // console.timeEnd('xx');
4313
4318
  }
4314
4319
  }
4315
4320
  showIntersections(_simplifiedXX || _unsimplifiedXX, e.layer, arcs);
@@ -4757,6 +4762,7 @@
4757
4762
  if (_open) close();
4758
4763
  menu.empty();
4759
4764
 
4765
+
4760
4766
  if (openMenu && openMenu != this) {
4761
4767
  openMenu.close();
4762
4768
  }
@@ -5838,7 +5844,7 @@
5838
5844
  empty: ['edit_polygons', 'edit_lines', 'edit_points', 'box'],
5839
5845
  polygons: ['info', 'selection', 'box', 'edit_polygons'],
5840
5846
  rectangles: ['info', 'selection', 'box', 'rectangles', 'edit_polygons'],
5841
- lines: ['info', 'selection', 'box' , 'edit_lines'],
5847
+ lines: ['info', 'selection', 'box', 'edit_lines'], // 'snip_lines'
5842
5848
  table: ['info', 'selection'],
5843
5849
  labels: ['info', 'selection', 'box', 'labels', 'edit_points'],
5844
5850
  points: ['info', 'selection', 'box', 'edit_points'] // , 'add-points'
@@ -5859,6 +5865,7 @@
5859
5865
  edit_points: 'add/drag points',
5860
5866
  edit_lines: 'draw/edit polylines',
5861
5867
  edit_polygons: 'draw/edit polygons',
5868
+ snip_lines: 'snip polylines',
5862
5869
  vertices: 'edit vertices',
5863
5870
  selection: 'selection tool',
5864
5871
  'add-points': 'add points',
@@ -5922,7 +5929,7 @@
5922
5929
  };
5923
5930
 
5924
5931
  this.modeUsesHitDetection = function(mode) {
5925
- return ['info', 'selection', 'data', 'labels', 'edit_points', 'vertices', 'rectangles', 'edit_lines', 'edit_polygons'].includes(mode);
5932
+ return ['info', 'selection', 'data', 'labels', 'edit_points', 'vertices', 'rectangles', 'edit_lines', 'edit_polygons', 'snip_lines'].includes(mode);
5926
5933
  };
5927
5934
 
5928
5935
  this.modeUsesPopup = function(mode) {
@@ -6268,13 +6275,21 @@
6268
6275
 
6269
6276
  function verbose() {
6270
6277
  // verbose can be set globally with the -verbose command or separately for each command
6271
- if (getStashedVar('VERBOSE')) {
6278
+ if (useVerbose()) {
6272
6279
  message.apply(null, arguments);
6273
6280
  }
6274
6281
  }
6275
6282
 
6283
+ function useVerbose() {
6284
+ return getStashedVar('VERBOSE');
6285
+ }
6286
+
6287
+ function useDebug() {
6288
+ return getStashedVar('DEBUG');
6289
+ }
6290
+
6276
6291
  function debug() {
6277
- if (getStashedVar('DEBUG')) {
6292
+ if (useDebug()) {
6278
6293
  logArgs(arguments);
6279
6294
  }
6280
6295
  }
@@ -9952,7 +9967,7 @@
9952
9967
 
9953
9968
  hit.on('contextmenu', function(e) {
9954
9969
  if (!e.overMap || e.mode == 'edit_lines' || e.mode == 'edit_polygons' ||
9955
- e.mode == 'edit_points') {
9970
+ e.mode == 'edit_points' || e.mode == 'snip_lines') {
9956
9971
  return;
9957
9972
  }
9958
9973
  var target = hit.getHitTarget();
@@ -10080,7 +10095,8 @@
10080
10095
  return [lyr];
10081
10096
  }
10082
10097
  if (styleOpts.interactionMode == 'edit_lines' ||
10083
- styleOpts.interactionMode == 'edit_polygons') {
10098
+ styleOpts.interactionMode == 'edit_polygons' ||
10099
+ styleOpts.interactionMode == 'snip_lines') {
10084
10100
  // special overlay: shape editing mode
10085
10101
  lyr = getOverlayLayer(activeLyr, hitData.ids);
10086
10102
  lyr.gui.style = getLineEditingStyle(hitData);
@@ -10581,7 +10597,7 @@
10581
10597
  }
10582
10598
 
10583
10599
  // pixel distance threshold for hovering near a vertex or segment midpoint
10584
- var HOVER_THRESHOLD = 10;
10600
+ var HOVER_THRESHOLD$1 = 10;
10585
10601
 
10586
10602
  function initLineEditing(gui, ext, hit) {
10587
10603
  var hoverVertexInfo;
@@ -10643,7 +10659,7 @@
10643
10659
  gui.on('redo_path_add', function(e) {
10644
10660
  var target = hit.getHitTarget();
10645
10661
  clearDrawingInfo();
10646
- appendNewPath(target, e.p1, e.p2);
10662
+ appendNewPath(target, [e.p1, e.p2]);
10647
10663
  deleteLastVertex(target); // second vertex is a placeholder
10648
10664
  gui.undo.redo(); // add next vertex in the path
10649
10665
  fullRedraw();
@@ -11042,7 +11058,7 @@
11042
11058
  function startNewPath(p2) {
11043
11059
  var target = hit.getHitTarget();
11044
11060
  var p1 = hoverVertexInfo?.point || p2;
11045
- appendNewPath(target, p1, p2);
11061
+ appendNewPath(target, [p1, p2]);
11046
11062
  gui.dispatchEvent('path_add', {target, p1, p2});
11047
11063
  drawingId = target.shapes.length - 1;
11048
11064
  hit.setDrawingId(drawingId);
@@ -11118,7 +11134,7 @@
11118
11134
  var i = data.ii[arcId];
11119
11135
  var pathLen = data.nn[arcId];
11120
11136
  var pixelDist = dist / ext.getPixelSize();
11121
- if (pixelDist > HOVER_THRESHOLD || pathLen < 4) {
11137
+ if (pixelDist > HOVER_THRESHOLD$1 || pathLen < 4) {
11122
11138
  return null;
11123
11139
  }
11124
11140
  return {
@@ -11137,7 +11153,7 @@
11137
11153
  var p2 = target.gui.displayArcs.getVertex2(ids[0]);
11138
11154
  var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
11139
11155
  var pixelDist = dist / ext.getPixelSize();
11140
- if (pixelDist > HOVER_THRESHOLD) {
11156
+ if (pixelDist > HOVER_THRESHOLD$1) {
11141
11157
  return null;
11142
11158
  }
11143
11159
  var point = getVertexCoords(target, ids[0]); // data coordinates
@@ -11175,7 +11191,7 @@
11175
11191
  }
11176
11192
  });
11177
11193
 
11178
- if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD) {
11194
+ if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD$1) {
11179
11195
  return null;
11180
11196
  }
11181
11197
  closest.point = translateDisplayPoint(target, closest.displayPoint);
@@ -11225,10 +11241,154 @@
11225
11241
  }
11226
11242
  }
11227
11243
 
11244
+ function snipLineAtVertex(lyr, fid, vid) {
11245
+ // find the feature part and arc containing the vertex
11246
+ // divide the one feature into two features
11247
+ // divide the arc into two new arcs
11248
+ var arc1, arc2;
11249
+ // divide the feature into two parts
11250
+ }
11251
+
11252
+ function mergeLinesAtVertex(lyr) {
11253
+
11254
+ }
11255
+
11256
+ // TODO: support snipping rings (by snipping in two places)
11257
+
11258
+
11259
+ // pixel distance threshold for hovering near a vertex or segment midpoint
11260
+ var HOVER_THRESHOLD = 10;
11261
+
11262
+ function initSnipTool(gui, ext, hit) {
11263
+ var _active = true;
11264
+ var hoverVertexInfo;
11265
+ var prevHoverEvent;
11266
+
11267
+ gui.on('interaction_mode_change', function(e) {
11268
+ if (active()) {
11269
+ turnOff();
11270
+ }
11271
+ // updateCursor();
11272
+ }, null, 10); // higher priority than hit control, so turnOff() has correct hit target
11273
+
11274
+
11275
+ // hover event highlights the nearest point in close proximity to the pointer
11276
+ // ... or the closest point along the segment (for adding a new vertex)
11277
+ hit.on('hover', function(e) {
11278
+ if (!active()) return;
11279
+
11280
+ // highlight nearby snappable vertex (the closest vertex on a nearby line,
11281
+ // or the first vertex of the current drawing path if not near a line)
11282
+ hoverVertexInfo = e.id >= 0 && findDraggableVertices(e) ||
11283
+ e.id >= 0 && findInterpolatedPoint(e);
11284
+ if (hoverVertexInfo) {
11285
+ // hovering near a vertex: highlight the vertex
11286
+ hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type);
11287
+ } else {
11288
+ clearHoverVertex();
11289
+ }
11290
+ // updateCursor();
11291
+ prevHoverEvent = e;
11292
+ }, null, 100);
11293
+
11294
+ hit.on('click', function(e) {
11295
+ if (!active() || !hoverVertexInfo) return;
11296
+ var target = hit.getHitTarget();
11297
+ if (vertexIsEndpoint(hoverVertexInfo, target)) {
11298
+ // TODO: don't allow hovering on endpoints
11299
+ return;
11300
+ }
11301
+
11302
+ if (hoverVertexInfo.type == 'interpolated') {
11303
+ insertVertex$1(target, hoverVertexInfo.i, hoverVertexInfo.point);
11304
+ hoverVertexInfo.ids = [hoverVertexInfo.i];
11305
+ }
11306
+
11307
+ snipLineAtVertex(target, e.id, hoverVertexInfo.ids[0]);
11308
+
11309
+ hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type);
11310
+
11311
+ });
11312
+
11313
+ // return data on the nearest vertex (or identical vertices) to the pointer
11314
+ // (if within a distance threshold)
11315
+ //
11316
+ function findDraggableVertices(e) {
11317
+ var target = hit.getHitTarget();
11318
+ var shp = target.shapes[e.id];
11319
+ var p = ext.pixCoordsToMapCoords(e.x, e.y);
11320
+ var ids = internal.findNearestVertices(p, shp, target.gui.displayArcs);
11321
+ var p2 = target.gui.displayArcs.getVertex2(ids[0]);
11322
+ var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
11323
+ var pixelDist = dist / ext.getPixelSize();
11324
+ if (pixelDist > HOVER_THRESHOLD) {
11325
+ return null;
11326
+ }
11327
+ var point = getVertexCoords(target, ids[0]); // data coordinates
11328
+ var displayPoint = target.gui.displayArcs.getVertex2(ids[0]);
11329
+ return {target, ids, point, displayPoint, type: 'vertex'};
11330
+ }
11331
+
11332
+ function findInterpolatedPoint(e) {
11333
+ var target = hit.getHitTarget();
11334
+ //// vertex insertion not supported with simplification
11335
+ // if (!target.arcs.isFlat()) return null;
11336
+ var p = ext.pixCoordsToMapCoords(e.x, e.y);
11337
+ var minDist = Infinity;
11338
+ var shp = target.shapes[e.id];
11339
+ var closest;
11340
+ internal.forEachSegmentInShape(shp, target.gui.displayArcs, function(i, j, xx, yy) {
11341
+ var x1 = xx[i],
11342
+ y1 = yy[i],
11343
+ x2 = xx[j],
11344
+ y2 = yy[j],
11345
+ p2 = internal.findClosestPointOnSeg(p[0], p[1], x1, y1, x2, y2, 0),
11346
+ dist = geom.distance2D(p2[0], p2[1], p[0], p[1]);
11347
+ if (dist < minDist) {
11348
+ minDist = dist;
11349
+ closest = {
11350
+ i: (i < j ? i : j) + 1, // insertion vertex id
11351
+ displayPoint: p2,
11352
+ distance: dist
11353
+ };
11354
+ }
11355
+ });
11356
+
11357
+ if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD) {
11358
+ return null;
11359
+ }
11360
+ closest.point = translateDisplayPoint(target, closest.displayPoint);
11361
+ closest.type = 'interpolated';
11362
+ closest.target = target;
11363
+ return closest;
11364
+ }
11365
+
11366
+ function vertexIsEndpoint(info, target) {
11367
+ var vId = info.ids[0];
11368
+ return internal.vertexIsArcStart(vId, target.gui.displayArcs) ||
11369
+ internal.vertexIsArcEnd(vId, target.gui.displayArcs);
11370
+ }
11371
+
11372
+ function clearHoverVertex() {
11373
+ hit.clearHoverVertex();
11374
+ hoverVertexInfo = null;
11375
+ }
11376
+
11377
+ function active() {
11378
+ return _active && gui.interaction.getMode() == 'snip_lines';
11379
+ }
11380
+
11381
+ function turnOff() {
11382
+
11383
+ }
11384
+
11385
+ }
11386
+
11228
11387
  function initInteractiveEditing(gui, ext, hit) {
11229
11388
  initLabelDragging(gui, ext, hit);
11230
11389
  initPointEditing(gui, ext, hit);
11231
11390
  initLineEditing(gui, ext, hit);
11391
+ initSnipTool(gui, ext, hit);
11232
11392
  }
11233
11393
 
11234
11394
  var darkStroke = "#334",
@@ -11560,11 +11720,13 @@
11560
11720
  // stop zooming before rounding errors become too obvious
11561
11721
  function maxScale() {
11562
11722
  var minPixelScale = 1e-16;
11723
+ // var minPixelScale = 1e-17; // gets jumpy
11563
11724
  var xmax = maxAbs(_fullBounds.xmin, _fullBounds.xmax, _fullBounds.centerX());
11564
11725
  var ymax = maxAbs(_fullBounds.ymin, _fullBounds.ymax, _fullBounds.centerY());
11565
11726
  var xscale = _fullBounds.width() / _position.width() / xmax / minPixelScale;
11566
11727
  var yscale = _fullBounds.height() / _position.height() / ymax / minPixelScale;
11567
- return Math.min(xscale, yscale);
11728
+ // return Math.min(xscale, yscale);
11729
+ return Math.max(xscale, yscale);
11568
11730
  }
11569
11731
 
11570
11732
  function maxAbs() {
@@ -11906,9 +12068,8 @@
11906
12068
  var iter = new internal.ShapeIter(arcs);
11907
12069
  var t = getScaledTransform(_ext);
11908
12070
  var bounds = _ext.getBounds();
11909
- var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 1.8) * GUI.getPixelRatio() * getScaledLineScale(_ext, style);
12071
+ var radius = (style.strokeWidth > 2 ? style.strokeWidth * 1 : 2.2) * GUI.getPixelRatio() * getScaledLineScale(_ext, style);
11910
12072
  var color = style.strokeColor || 'black';
11911
-
11912
12073
  var i, j, p;
11913
12074
  _ctx.beginPath();
11914
12075
  _ctx.fillStyle = color;
@@ -12167,8 +12328,8 @@
12167
12328
  s = 1;
12168
12329
  if (mapScale < 0.5) {
12169
12330
  s *= Math.pow(mapScale + 0.5, 0.35);
12170
- } else if (mapScale > 100) {
12171
- s *= Math.pow(mapScale - 99, 0.10);
12331
+ } else if (mapScale > 30) {
12332
+ s *= Math.pow(mapScale - 29, 0.065);
12172
12333
  }
12173
12334
  return s;
12174
12335
  }
@@ -12994,6 +13155,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
12994
13155
  var fullBounds;
12995
13156
  var needReset;
12996
13157
 
13158
+ if (!updated) {
13159
+ return; // e.g. if command is run in console before data is loaded
13160
+ }
13161
+
12997
13162
  if (arcsMayHaveChanged(e.flags)) {
12998
13163
  // regenerate filtered arcs the next time they are needed for rendering
12999
13164
  // delete e.dataset.gui.displayArcs
@@ -13099,15 +13264,17 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13099
13264
  // add margin
13100
13265
  // use larger margin for small sizes
13101
13266
  var widthPx = _ext.width();
13102
- var marginPct = widthPx < 700 && 3.5 || widthPx < 800 && 3 || 2.5;
13267
+ var marginPct = widthPx < 700 && 4.5 || widthPx < 800 && 4 || 3.5;
13103
13268
  if (isTableView()) {
13104
13269
  var n = internal.getFeatureCount(_activeLyr);
13105
13270
  marginPct = n < 5 && 20 || n < 100 && 10 || 4;
13106
13271
  }
13107
13272
  b.scale(1 + marginPct / 100 * 2);
13108
13273
 
13109
- // Inflate display bounding box by a tiny amount (gives extent to single-point layers and collapsed shapes)
13110
- b.padBounds(1e-4, 1e-4, 1e-4, 1e-4);
13274
+ // Inflate display bounding box of single-point layers and collapsed shapes a bit
13275
+ if (b.width() === 0 || b.height() === 0) {
13276
+ b.padBounds(1e-4, 1e-4, 1e-4, 1e-4);
13277
+ }
13111
13278
  return b;
13112
13279
  }
13113
13280
 
@@ -13604,7 +13771,11 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13604
13771
  }
13605
13772
  }
13606
13773
 
13607
- return {refresh, show: onUpdate};
13774
+ function isOn() {
13775
+ return !!activeStyle;
13776
+ }
13777
+
13778
+ return {refresh, show: onUpdate, isOn};
13608
13779
  }
13609
13780
 
13610
13781
  function DisplayOptions(gui) {
@@ -13665,6 +13836,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13665
13836
  };
13666
13837
  }
13667
13838
 
13839
+ // import { ProjectOptions } from './gui-project-control';
13840
+
13841
+
13668
13842
  function GuiInstance(container, opts) {
13669
13843
  var gui = new ModeSwitcher();
13670
13844
  opts = utils$1.extend({
@@ -13688,6 +13862,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13688
13862
  gui.contextMenu = new ContextMenu();
13689
13863
  gui.undo = new Undo(gui);
13690
13864
  gui.map = new MshpMap(gui);
13865
+ // gui.project = new ProjectOptions(gui);
13691
13866
 
13692
13867
 
13693
13868
  gui.state = {};