mapshaper 0.6.109 → 0.6.111

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.
@@ -3227,18 +3227,20 @@
3227
3227
  }
3228
3228
 
3229
3229
  // p1, p2: two points in source data CRS coords.
3230
- function appendNewPath(lyr, p1, p2) {
3230
+ function appendNewPath(lyr, points) {
3231
3231
  var arcId = lyr.gui.displayArcs.size();
3232
3232
  internal.appendEmptyArc(lyr.gui.displayArcs);
3233
3233
  lyr.shapes.push([[arcId]]);
3234
3234
  if (isProjectedLayer(lyr)) {
3235
3235
  internal.appendEmptyArc(lyr.gui.source.dataset.arcs);
3236
3236
  }
3237
- appendVertex$1(lyr, p1);
3238
- appendVertex$1(lyr, p2);
3237
+ points.forEach(function(p) {
3238
+ appendVertex$1(lyr, p);
3239
+ });
3239
3240
  appendNewDataRecord(lyr);
3240
3241
  }
3241
3242
 
3243
+
3242
3244
  function deleteLastPath(lyr) {
3243
3245
  var arcId = lyr.gui.displayArcs.size() - 1;
3244
3246
  if (lyr.data) {
@@ -4174,13 +4176,6 @@
4174
4176
  flags.union || flags.mosaic || flags.snap || flags.clean || flags.drop || false;
4175
4177
  }
4176
4178
 
4177
- // check for operations that may change the number of self intersections in the
4178
- // target layer.
4179
- function intersectionsMayHaveChanged(flags) {
4180
- return arcsMayHaveChanged(flags) || flags.select || flags['merge-layers'] ||
4181
- flags.filter || flags.dissolve || flags.dissolve2;
4182
- }
4183
-
4184
4179
  // Test if an update allows hover popup to stay open
4185
4180
  function popupCanStayOpen(flags) {
4186
4181
  // keeping popup open after -drop geometry causes problems...
@@ -4205,7 +4200,7 @@
4205
4200
  return c;
4206
4201
  }
4207
4202
 
4208
- function RepairControl(gui) {
4203
+ function IntersectionControl(gui) {
4209
4204
  var map = gui.map,
4210
4205
  model = gui.model,
4211
4206
  el = gui.container.findChild(".intersection-display"),
@@ -4241,12 +4236,24 @@
4241
4236
  gui.session.simplificationRepair();
4242
4237
  });
4243
4238
 
4239
+ // check for operations that may change the number of self intersections in the
4240
+ // target layer.
4241
+ function intersectionsMayHaveChanged(flags) {
4242
+ return arcsMayHaveChanged(flags) || flags.select || flags.repair ||
4243
+ flags.clean || flags.filter || flags.dissolve || flags.dissolve2 ||
4244
+ flags['merge-layers'] || flags.simplify_method || flags.simplify ||
4245
+ flags.split;
4246
+ }
4247
+
4248
+
4244
4249
  model.on('update', function(e) {
4245
- var needRefresh = e.flags.simplify_method || e.flags.simplify ||
4246
- e.flags.repair || e.flags.clean || e.flags.select || intersectionsMayHaveChanged(e.flags);
4250
+ var needRefresh = intersectionsMayHaveChanged(e.flags);
4247
4251
  if (!intersectionsAreOn()) {
4248
4252
  reset();
4249
4253
  } else if (needRefresh) {
4254
+ // don't continue to show old intersections when map redraws
4255
+ map.setIntersectionLayer(null, null, false);
4256
+ // regenerate intersections and redraw map
4250
4257
  updateAsync();
4251
4258
  } else if (e.flags.simplify_amount) {
4252
4259
  // slider is being dragged - hide readout and dots, retain data
@@ -4254,7 +4261,7 @@
4254
4261
  } else {
4255
4262
  // keep displaying the current intersections
4256
4263
  }
4257
- });
4264
+ }, 10);
4258
4265
 
4259
4266
  function updateRepairBtn() {
4260
4267
  if (intersectionsAreOn() && gui.getMode() == 'simplify' &&
@@ -4310,7 +4317,9 @@
4310
4317
  if (_unsimplifiedXX && action == 'simplify_drag_end') {
4311
4318
  // re-use previously generated intersection data (optimization)
4312
4319
  } else {
4320
+ // console.time('xx');
4313
4321
  _unsimplifiedXX = internal.findSegmentIntersections(arcs, intersectionOpts);
4322
+ // console.timeEnd('xx');
4314
4323
  }
4315
4324
  }
4316
4325
  showIntersections(_simplifiedXX || _unsimplifiedXX, e.layer, arcs);
@@ -4336,7 +4345,7 @@
4336
4345
  }
4337
4346
  }
4338
4347
 
4339
- utils$1.inherit(RepairControl, EventDispatcher);
4348
+ utils$1.inherit(IntersectionControl, EventDispatcher);
4340
4349
 
4341
4350
  async function saveFileContentToClipboard(content) {
4342
4351
  var str = utils$1.isString(content) ? content : content.toString();
@@ -5840,7 +5849,7 @@
5840
5849
  empty: ['edit_polygons', 'edit_lines', 'edit_points', 'box'],
5841
5850
  polygons: ['info', 'selection', 'box', 'edit_polygons'],
5842
5851
  rectangles: ['info', 'selection', 'box', 'rectangles', 'edit_polygons'],
5843
- lines: ['info', 'selection', 'box' , 'edit_lines'],
5852
+ lines: ['info', 'selection', 'box', 'edit_lines'], // 'snip_lines'
5844
5853
  table: ['info', 'selection'],
5845
5854
  labels: ['info', 'selection', 'box', 'labels', 'edit_points'],
5846
5855
  points: ['info', 'selection', 'box', 'edit_points'] // , 'add-points'
@@ -5861,6 +5870,7 @@
5861
5870
  edit_points: 'add/drag points',
5862
5871
  edit_lines: 'draw/edit polylines',
5863
5872
  edit_polygons: 'draw/edit polygons',
5873
+ snip_lines: 'snip polylines',
5864
5874
  vertices: 'edit vertices',
5865
5875
  selection: 'selection tool',
5866
5876
  'add-points': 'add points',
@@ -5924,7 +5934,7 @@
5924
5934
  };
5925
5935
 
5926
5936
  this.modeUsesHitDetection = function(mode) {
5927
- return ['info', 'selection', 'data', 'labels', 'edit_points', 'vertices', 'rectangles', 'edit_lines', 'edit_polygons'].includes(mode);
5937
+ return ['info', 'selection', 'data', 'labels', 'edit_points', 'vertices', 'rectangles', 'edit_lines', 'edit_polygons', 'snip_lines'].includes(mode);
5928
5938
  };
5929
5939
 
5930
5940
  this.modeUsesPopup = function(mode) {
@@ -6270,13 +6280,21 @@
6270
6280
 
6271
6281
  function verbose() {
6272
6282
  // verbose can be set globally with the -verbose command or separately for each command
6273
- if (getStashedVar('VERBOSE')) {
6283
+ if (useVerbose()) {
6274
6284
  message.apply(null, arguments);
6275
6285
  }
6276
6286
  }
6277
6287
 
6288
+ function useVerbose() {
6289
+ return getStashedVar('VERBOSE');
6290
+ }
6291
+
6292
+ function useDebug() {
6293
+ return getStashedVar('DEBUG');
6294
+ }
6295
+
6278
6296
  function debug() {
6279
- if (getStashedVar('DEBUG')) {
6297
+ if (useDebug()) {
6280
6298
  logArgs(arguments);
6281
6299
  }
6282
6300
  }
@@ -9954,7 +9972,7 @@
9954
9972
 
9955
9973
  hit.on('contextmenu', function(e) {
9956
9974
  if (!e.overMap || e.mode == 'edit_lines' || e.mode == 'edit_polygons' ||
9957
- e.mode == 'edit_points') {
9975
+ e.mode == 'edit_points' || e.mode == 'snip_lines') {
9958
9976
  return;
9959
9977
  }
9960
9978
  var target = hit.getHitTarget();
@@ -10082,10 +10100,14 @@
10082
10100
  return [lyr];
10083
10101
  }
10084
10102
  if (styleOpts.interactionMode == 'edit_lines' ||
10085
- styleOpts.interactionMode == 'edit_polygons') {
10103
+ styleOpts.interactionMode == 'edit_polygons' ||
10104
+ styleOpts.interactionMode == 'snip_lines') {
10086
10105
  // special overlay: shape editing mode
10087
10106
  lyr = getOverlayLayer(activeLyr, hitData.ids);
10088
10107
  lyr.gui.style = getLineEditingStyle(hitData);
10108
+ if (activeLyr.geometry_type == 'polygon') {
10109
+ lyr.gui.style.fillColor = hoverFill;
10110
+ }
10089
10111
  return [lyr];
10090
10112
  }
10091
10113
  layers = [];
@@ -10583,7 +10605,7 @@
10583
10605
  }
10584
10606
 
10585
10607
  // pixel distance threshold for hovering near a vertex or segment midpoint
10586
- var HOVER_THRESHOLD = 10;
10608
+ var HOVER_THRESHOLD$1 = 10;
10587
10609
 
10588
10610
  function initLineEditing(gui, ext, hit) {
10589
10611
  var hoverVertexInfo;
@@ -10645,7 +10667,7 @@
10645
10667
  gui.on('redo_path_add', function(e) {
10646
10668
  var target = hit.getHitTarget();
10647
10669
  clearDrawingInfo();
10648
- appendNewPath(target, e.p1, e.p2);
10670
+ appendNewPath(target, [e.p1, e.p2]);
10649
10671
  deleteLastVertex(target); // second vertex is a placeholder
10650
10672
  gui.undo.redo(); // add next vertex in the path
10651
10673
  fullRedraw();
@@ -11044,7 +11066,7 @@
11044
11066
  function startNewPath(p2) {
11045
11067
  var target = hit.getHitTarget();
11046
11068
  var p1 = hoverVertexInfo?.point || p2;
11047
- appendNewPath(target, p1, p2);
11069
+ appendNewPath(target, [p1, p2]);
11048
11070
  gui.dispatchEvent('path_add', {target, p1, p2});
11049
11071
  drawingId = target.shapes.length - 1;
11050
11072
  hit.setDrawingId(drawingId);
@@ -11120,7 +11142,7 @@
11120
11142
  var i = data.ii[arcId];
11121
11143
  var pathLen = data.nn[arcId];
11122
11144
  var pixelDist = dist / ext.getPixelSize();
11123
- if (pixelDist > HOVER_THRESHOLD || pathLen < 4) {
11145
+ if (pixelDist > HOVER_THRESHOLD$1 || pathLen < 4) {
11124
11146
  return null;
11125
11147
  }
11126
11148
  return {
@@ -11139,7 +11161,7 @@
11139
11161
  var p2 = target.gui.displayArcs.getVertex2(ids[0]);
11140
11162
  var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
11141
11163
  var pixelDist = dist / ext.getPixelSize();
11142
- if (pixelDist > HOVER_THRESHOLD) {
11164
+ if (pixelDist > HOVER_THRESHOLD$1) {
11143
11165
  return null;
11144
11166
  }
11145
11167
  var point = getVertexCoords(target, ids[0]); // data coordinates
@@ -11177,7 +11199,7 @@
11177
11199
  }
11178
11200
  });
11179
11201
 
11180
- if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD) {
11202
+ if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD$1) {
11181
11203
  return null;
11182
11204
  }
11183
11205
  closest.point = translateDisplayPoint(target, closest.displayPoint);
@@ -11227,10 +11249,154 @@
11227
11249
  }
11228
11250
  }
11229
11251
 
11252
+ function snipLineAtVertex(lyr, fid, vid) {
11253
+ // find the feature part and arc containing the vertex
11254
+ // divide the one feature into two features
11255
+ // divide the arc into two new arcs
11256
+ var arc1, arc2;
11257
+ // divide the feature into two parts
11258
+ }
11259
+
11260
+ function mergeLinesAtVertex(lyr) {
11261
+
11262
+ }
11263
+
11264
+ // TODO: support snipping rings (by snipping in two places)
11265
+
11266
+
11267
+ // pixel distance threshold for hovering near a vertex or segment midpoint
11268
+ var HOVER_THRESHOLD = 10;
11269
+
11270
+ function initSnipTool(gui, ext, hit) {
11271
+ var _active = true;
11272
+ var hoverVertexInfo;
11273
+ var prevHoverEvent;
11274
+
11275
+ gui.on('interaction_mode_change', function(e) {
11276
+ if (active()) {
11277
+ turnOff();
11278
+ }
11279
+ // updateCursor();
11280
+ }, null, 10); // higher priority than hit control, so turnOff() has correct hit target
11281
+
11282
+
11283
+ // hover event highlights the nearest point in close proximity to the pointer
11284
+ // ... or the closest point along the segment (for adding a new vertex)
11285
+ hit.on('hover', function(e) {
11286
+ if (!active()) return;
11287
+
11288
+ // highlight nearby snappable vertex (the closest vertex on a nearby line,
11289
+ // or the first vertex of the current drawing path if not near a line)
11290
+ hoverVertexInfo = e.id >= 0 && findDraggableVertices(e) ||
11291
+ e.id >= 0 && findInterpolatedPoint(e);
11292
+ if (hoverVertexInfo) {
11293
+ // hovering near a vertex: highlight the vertex
11294
+ hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type);
11295
+ } else {
11296
+ clearHoverVertex();
11297
+ }
11298
+ // updateCursor();
11299
+ prevHoverEvent = e;
11300
+ }, null, 100);
11301
+
11302
+ hit.on('click', function(e) {
11303
+ if (!active() || !hoverVertexInfo) return;
11304
+ var target = hit.getHitTarget();
11305
+ if (vertexIsEndpoint(hoverVertexInfo, target)) {
11306
+ // TODO: don't allow hovering on endpoints
11307
+ return;
11308
+ }
11309
+
11310
+ if (hoverVertexInfo.type == 'interpolated') {
11311
+ insertVertex$1(target, hoverVertexInfo.i, hoverVertexInfo.point);
11312
+ hoverVertexInfo.ids = [hoverVertexInfo.i];
11313
+ }
11314
+
11315
+ snipLineAtVertex(target, e.id, hoverVertexInfo.ids[0]);
11316
+
11317
+ hit.setHoverVertex(hoverVertexInfo.displayPoint, hoverVertexInfo.type);
11318
+
11319
+ });
11320
+
11321
+ // return data on the nearest vertex (or identical vertices) to the pointer
11322
+ // (if within a distance threshold)
11323
+ //
11324
+ function findDraggableVertices(e) {
11325
+ var target = hit.getHitTarget();
11326
+ var shp = target.shapes[e.id];
11327
+ var p = ext.pixCoordsToMapCoords(e.x, e.y);
11328
+ var ids = internal.findNearestVertices(p, shp, target.gui.displayArcs);
11329
+ var p2 = target.gui.displayArcs.getVertex2(ids[0]);
11330
+ var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
11331
+ var pixelDist = dist / ext.getPixelSize();
11332
+ if (pixelDist > HOVER_THRESHOLD) {
11333
+ return null;
11334
+ }
11335
+ var point = getVertexCoords(target, ids[0]); // data coordinates
11336
+ var displayPoint = target.gui.displayArcs.getVertex2(ids[0]);
11337
+ return {target, ids, point, displayPoint, type: 'vertex'};
11338
+ }
11339
+
11340
+ function findInterpolatedPoint(e) {
11341
+ var target = hit.getHitTarget();
11342
+ //// vertex insertion not supported with simplification
11343
+ // if (!target.arcs.isFlat()) return null;
11344
+ var p = ext.pixCoordsToMapCoords(e.x, e.y);
11345
+ var minDist = Infinity;
11346
+ var shp = target.shapes[e.id];
11347
+ var closest;
11348
+ internal.forEachSegmentInShape(shp, target.gui.displayArcs, function(i, j, xx, yy) {
11349
+ var x1 = xx[i],
11350
+ y1 = yy[i],
11351
+ x2 = xx[j],
11352
+ y2 = yy[j],
11353
+ p2 = internal.findClosestPointOnSeg(p[0], p[1], x1, y1, x2, y2, 0),
11354
+ dist = geom.distance2D(p2[0], p2[1], p[0], p[1]);
11355
+ if (dist < minDist) {
11356
+ minDist = dist;
11357
+ closest = {
11358
+ i: (i < j ? i : j) + 1, // insertion vertex id
11359
+ displayPoint: p2,
11360
+ distance: dist
11361
+ };
11362
+ }
11363
+ });
11364
+
11365
+ if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD) {
11366
+ return null;
11367
+ }
11368
+ closest.point = translateDisplayPoint(target, closest.displayPoint);
11369
+ closest.type = 'interpolated';
11370
+ closest.target = target;
11371
+ return closest;
11372
+ }
11373
+
11374
+ function vertexIsEndpoint(info, target) {
11375
+ var vId = info.ids[0];
11376
+ return internal.vertexIsArcStart(vId, target.gui.displayArcs) ||
11377
+ internal.vertexIsArcEnd(vId, target.gui.displayArcs);
11378
+ }
11379
+
11380
+ function clearHoverVertex() {
11381
+ hit.clearHoverVertex();
11382
+ hoverVertexInfo = null;
11383
+ }
11384
+
11385
+ function active() {
11386
+ return _active && gui.interaction.getMode() == 'snip_lines';
11387
+ }
11388
+
11389
+ function turnOff() {
11390
+
11391
+ }
11392
+
11393
+ }
11394
+
11230
11395
  function initInteractiveEditing(gui, ext, hit) {
11231
11396
  initLabelDragging(gui, ext, hit);
11232
11397
  initPointEditing(gui, ext, hit);
11233
11398
  initLineEditing(gui, ext, hit);
11399
+ initSnipTool(gui, ext, hit);
11234
11400
  }
11235
11401
 
11236
11402
  var darkStroke = "#334",
@@ -11567,7 +11733,8 @@
11567
11733
  var ymax = maxAbs(_fullBounds.ymin, _fullBounds.ymax, _fullBounds.centerY());
11568
11734
  var xscale = _fullBounds.width() / _position.width() / xmax / minPixelScale;
11569
11735
  var yscale = _fullBounds.height() / _position.height() / ymax / minPixelScale;
11570
- return Math.min(xscale, yscale);
11736
+ // return Math.min(xscale, yscale);
11737
+ return Math.max(xscale, yscale);
11571
11738
  }
11572
11739
 
11573
11740
  function maxAbs() {
@@ -12169,8 +12336,8 @@
12169
12336
  s = 1;
12170
12337
  if (mapScale < 0.5) {
12171
12338
  s *= Math.pow(mapScale + 0.5, 0.35);
12172
- } else if (mapScale > 100) {
12173
- s *= Math.pow(mapScale - 99, 0.10);
12339
+ } else if (mapScale > 30) {
12340
+ s *= Math.pow(mapScale - 29, 0.065);
12174
12341
  }
12175
12342
  return s;
12176
12343
  }
@@ -12855,7 +13022,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
12855
13022
  });
12856
13023
 
12857
13024
  // Update display of segment intersections
12858
- this.setIntersectionLayer = function(lyr, dataset) {
13025
+ this.setIntersectionLayer = function(lyr, dataset, redraw) {
12859
13026
  if (lyr == _intersectionLyr) return; // no change
12860
13027
  if (lyr) {
12861
13028
  enhanceLayerForDisplay(lyr, dataset, getDisplayOptions());
@@ -12865,7 +13032,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
12865
13032
  _intersectionLyr = null;
12866
13033
  }
12867
13034
  // TODO: try to avoid redrawing layers twice (in some situations)
12868
- drawLayers();
13035
+ if (redraw !== false) {
13036
+ drawLayers();
13037
+ }
12869
13038
  };
12870
13039
 
12871
13040
  this.pixelCoordsToLngLatCoords = function(x, y) {
@@ -13612,7 +13781,11 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13612
13781
  }
13613
13782
  }
13614
13783
 
13615
- return {refresh, show: onUpdate};
13784
+ function isOn() {
13785
+ return !!activeStyle;
13786
+ }
13787
+
13788
+ return {refresh, show: onUpdate, isOn};
13616
13789
  }
13617
13790
 
13618
13791
  function DisplayOptions(gui) {
@@ -13673,6 +13846,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13673
13846
  };
13674
13847
  }
13675
13848
 
13849
+ // import { ProjectOptions } from './gui-project-control';
13850
+
13851
+
13676
13852
  function GuiInstance(container, opts) {
13677
13853
  var gui = new ModeSwitcher();
13678
13854
  opts = utils$1.extend({
@@ -13696,6 +13872,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13696
13872
  gui.contextMenu = new ContextMenu();
13697
13873
  gui.undo = new Undo(gui);
13698
13874
  gui.map = new MshpMap(gui);
13875
+ // gui.project = new ProjectOptions(gui);
13699
13876
 
13700
13877
 
13701
13878
  gui.state = {};
@@ -13829,7 +14006,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
13829
14006
  // }
13830
14007
 
13831
14008
  new AlertControl(gui);
13832
- new RepairControl(gui);
14009
+ new IntersectionControl(gui);
13833
14010
  new SimplifyControl(gui);
13834
14011
  new ImportControl(gui, importOpts);
13835
14012
  new ExportControl(gui);