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 +29 -35
- package/package.json +1 -1
- package/www/mapshaper-gui.js +255 -174
- package/www/mapshaper.js +29 -35
- package/www/page.css +11 -3
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
|
|
5557
|
-
_bb =
|
|
5558
|
-
_allBounds =
|
|
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
|
-
|
|
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.
|
|
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
package/www/mapshaper-gui.js
CHANGED
|
@@ -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="
|
|
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 == '
|
|
2708
|
-
return getLineEditingStyle(
|
|
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(
|
|
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
|
-
}
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
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.
|
|
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', '
|
|
5424
|
-
rectangles: ['info', 'selection', 'box', 'rectangles', 'vertices'
|
|
5425
|
-
lines: ['info', 'selection', 'box' , '
|
|
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
|
-
|
|
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', '
|
|
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 == '
|
|
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 == '
|
|
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. '
|
|
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
|
|
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 == '
|
|
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
|
|
7954
|
-
triggerHitEvent(e.type, e
|
|
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.
|
|
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 =
|
|
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
|
|
9718
|
+
return !!alert;
|
|
9691
9719
|
}
|
|
9692
9720
|
|
|
9693
9721
|
function dragging() {
|
|
9694
|
-
return
|
|
9722
|
+
return _dragging;
|
|
9695
9723
|
}
|
|
9696
9724
|
|
|
9697
9725
|
function drawing() {
|
|
9698
9726
|
return drawingId > -1;
|
|
9699
9727
|
}
|
|
9700
9728
|
|
|
9701
|
-
function
|
|
9702
|
-
|
|
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('
|
|
9713
|
-
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
|
|
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
|
-
|
|
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
|
-
|
|
9860
|
+
hoverVertexInfo = null;
|
|
9769
9861
|
prevClickEvent = prevHoverEvent = null;
|
|
9770
9862
|
}
|
|
9771
9863
|
|
|
9772
9864
|
hit.on('dragstart', function(e) {
|
|
9773
|
-
if (!active()) return;
|
|
9774
|
-
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
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,
|
|
9881
|
+
internal.snapPointToArcEndpoint(p, hoverVertexInfo.ids, target.arcs);
|
|
9798
9882
|
}
|
|
9799
|
-
internal.snapVerticesToPoint(
|
|
9800
|
-
setHoverVertex(
|
|
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()
|
|
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
|
|
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
|
-
|
|
9858
|
-
|
|
9859
|
-
|
|
9860
|
-
|
|
9861
|
-
|
|
9862
|
-
|
|
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.
|
|
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
|
-
|
|
10051
|
+
// p: [x, y] source data coordinates
|
|
10052
|
+
function startPath(p2) {
|
|
9980
10053
|
var target = hit.getHitTarget();
|
|
9981
|
-
var p1 = hoverVertexInfo ?
|
|
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
|
-
|
|
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 =
|
|
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
|
|
10018
|
-
var x = data.xx[
|
|
10019
|
-
var y = data.yy[
|
|
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: [
|
|
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
|
-
|
|
10121
|
+
var displayPoint = target.arcs.getVertex2(ids[0]);
|
|
10122
|
+
return {target, ids, extendable, point, displayPoint, type: 'vertex'};
|
|
10053
10123
|
}
|
|
10054
10124
|
|
|
10055
|
-
function
|
|
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
|
|
10061
|
-
|
|
10062
|
-
|
|
10063
|
-
|
|
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
|
-
|
|
10069
|
-
|
|
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
|
-
|
|
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 :
|
|
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 *
|
|
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
|
|
5557
|
-
_bb =
|
|
5558
|
-
_allBounds =
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
1205
|
+
.map-layers.drawing {
|
|
1198
1206
|
cursor: crosshair;
|
|
1199
1207
|
}
|
|
1200
1208
|
|