mapshaper 0.6.75 → 0.6.76
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 +5 -8
- package/package.json +1 -1
- package/www/index.html +21 -25
- package/www/mapshaper-gui.js +545 -553
- package/www/mapshaper.js +5 -8
- package/www/page.css +105 -51
package/www/mapshaper-gui.js
CHANGED
|
@@ -760,10 +760,7 @@
|
|
|
760
760
|
//
|
|
761
761
|
//El.prototype.__domevents = utils.arrayToIndex("click,mousedown,mousemove,mouseup".split(','));
|
|
762
762
|
El.prototype.__on = El.prototype.on;
|
|
763
|
-
El.prototype.on = function(type, func
|
|
764
|
-
if (ctx) {
|
|
765
|
-
error$1("[El#on()] Third argument no longer supported.");
|
|
766
|
-
}
|
|
763
|
+
El.prototype.on = function(type, func) {
|
|
767
764
|
if (this.constructor == El) {
|
|
768
765
|
this.el.addEventListener(type, func);
|
|
769
766
|
} else {
|
|
@@ -1369,10 +1366,12 @@
|
|
|
1369
1366
|
init();
|
|
1370
1367
|
|
|
1371
1368
|
async function init() {
|
|
1372
|
-
var enabled = await isStorageEnabled();
|
|
1373
|
-
if (!enabled) return;
|
|
1374
|
-
|
|
1375
1369
|
btn = gui.buttons.addButton('#ribbon-icon').addClass('menu-btn save-btn');
|
|
1370
|
+
var enabled = await isStorageEnabled();
|
|
1371
|
+
if (!enabled) {
|
|
1372
|
+
btn.remove();
|
|
1373
|
+
return;
|
|
1374
|
+
}
|
|
1376
1375
|
menu = El('div').addClass('nav-sub-menu save-menu').appendTo(btn.node());
|
|
1377
1376
|
await initialCleanup();
|
|
1378
1377
|
|
|
@@ -1444,14 +1443,6 @@
|
|
|
1444
1443
|
renderMenu();
|
|
1445
1444
|
}).text('remove');
|
|
1446
1445
|
});
|
|
1447
|
-
|
|
1448
|
-
// if (snapshots.length >= 1) {
|
|
1449
|
-
// addMenuLink({
|
|
1450
|
-
// slug: 'clear',
|
|
1451
|
-
// label: 'remove all',
|
|
1452
|
-
// action: clearData
|
|
1453
|
-
// });
|
|
1454
|
-
// }
|
|
1455
1446
|
}
|
|
1456
1447
|
|
|
1457
1448
|
function addMenuLink(item) {
|
|
@@ -2554,7 +2545,7 @@
|
|
|
2554
2545
|
// Convert a point from display CRS coordinates to data coordinates.
|
|
2555
2546
|
// These are only different when using dynamic reprojection (basemap view).
|
|
2556
2547
|
function translateDisplayPoint(lyr, p) {
|
|
2557
|
-
return isProjectedLayer(lyr) ? lyr.invertPoint(p[0], p[1]) : p;
|
|
2548
|
+
return isProjectedLayer(lyr) ? lyr.gui.invertPoint(p[0], p[1]) : p;
|
|
2558
2549
|
}
|
|
2559
2550
|
|
|
2560
2551
|
// bbox: display coords
|
|
@@ -2571,7 +2562,7 @@
|
|
|
2571
2562
|
|
|
2572
2563
|
function isProjectedLayer(lyr) {
|
|
2573
2564
|
// TODO: could do some validation on the layer's contents
|
|
2574
|
-
return !!
|
|
2565
|
+
return !!lyr.gui.invertPoint;
|
|
2575
2566
|
}
|
|
2576
2567
|
|
|
2577
2568
|
var darkStroke = "#334",
|
|
@@ -2933,22 +2924,22 @@
|
|
|
2933
2924
|
}
|
|
2934
2925
|
|
|
2935
2926
|
function flattenArcs(lyr) {
|
|
2936
|
-
lyr.source.dataset.arcs.flatten();
|
|
2927
|
+
lyr.gui.source.dataset.arcs.flatten();
|
|
2937
2928
|
if (isProjectedLayer(lyr)) {
|
|
2938
|
-
lyr.
|
|
2929
|
+
lyr.gui.displayArcs.flatten();
|
|
2939
2930
|
}
|
|
2940
2931
|
}
|
|
2941
2932
|
|
|
2942
2933
|
function setZ(lyr, z) {
|
|
2943
|
-
lyr.source.dataset.arcs.setRetainedInterval(z);
|
|
2934
|
+
lyr.gui.source.dataset.arcs.setRetainedInterval(z);
|
|
2944
2935
|
if (isProjectedLayer(lyr)) {
|
|
2945
|
-
lyr.
|
|
2936
|
+
lyr.gui.displayArcs.setRetainedInterval(z);
|
|
2946
2937
|
}
|
|
2947
2938
|
}
|
|
2948
2939
|
|
|
2949
2940
|
function updateZ(lyr) {
|
|
2950
|
-
if (isProjectedLayer(lyr) && !lyr.source.dataset.arcs.isFlat()) {
|
|
2951
|
-
lyr.
|
|
2941
|
+
if (isProjectedLayer(lyr) && !lyr.gui.source.dataset.arcs.isFlat()) {
|
|
2942
|
+
lyr.gui.displayArcs.setThresholds(lyr.gui.source.dataset.arcs.getVertexData().zz);
|
|
2952
2943
|
}
|
|
2953
2944
|
}
|
|
2954
2945
|
|
|
@@ -2984,108 +2975,107 @@
|
|
|
2984
2975
|
}
|
|
2985
2976
|
|
|
2986
2977
|
function deleteLastPath(lyr) {
|
|
2987
|
-
var arcId = lyr.
|
|
2988
|
-
if (lyr.
|
|
2989
|
-
lyr.
|
|
2978
|
+
var arcId = lyr.gui.displayArcs.size() - 1;
|
|
2979
|
+
if (lyr.data) {
|
|
2980
|
+
lyr.data.getRecords().pop();
|
|
2990
2981
|
}
|
|
2991
|
-
var shp = lyr.
|
|
2992
|
-
internal.deleteLastArc(lyr.
|
|
2982
|
+
var shp = lyr.shapes.pop();
|
|
2983
|
+
internal.deleteLastArc(lyr.gui.displayArcs);
|
|
2993
2984
|
if (isProjectedLayer(lyr)) {
|
|
2994
|
-
internal.deleteLastArc(lyr.source.dataset.arcs);
|
|
2985
|
+
internal.deleteLastArc(lyr.gui.source.dataset.arcs);
|
|
2995
2986
|
}
|
|
2996
2987
|
}
|
|
2997
2988
|
|
|
2998
2989
|
// p1, p2: two points in source data CRS coords.
|
|
2999
2990
|
function appendNewPath(lyr, p1, p2) {
|
|
3000
|
-
var arcId = lyr.
|
|
3001
|
-
internal.appendEmptyArc(lyr.
|
|
3002
|
-
lyr.
|
|
2991
|
+
var arcId = lyr.gui.displayArcs.size();
|
|
2992
|
+
internal.appendEmptyArc(lyr.gui.displayArcs);
|
|
2993
|
+
lyr.shapes.push([[arcId]]);
|
|
3003
2994
|
if (isProjectedLayer(lyr)) {
|
|
3004
|
-
|
|
3005
|
-
internal.appendEmptyArc(lyr.source.dataset.arcs);
|
|
2995
|
+
internal.appendEmptyArc(lyr.gui.source.dataset.arcs);
|
|
3006
2996
|
}
|
|
3007
2997
|
appendVertex$1(lyr, p1);
|
|
3008
2998
|
appendVertex$1(lyr, p2);
|
|
3009
|
-
appendNewDataRecord(lyr
|
|
2999
|
+
appendNewDataRecord(lyr);
|
|
3010
3000
|
}
|
|
3011
3001
|
|
|
3012
3002
|
// p: point in source data CRS coords.
|
|
3013
3003
|
function insertVertex$1(lyr, id, p) {
|
|
3014
|
-
internal.insertVertex(lyr.source.dataset.arcs, id, p);
|
|
3004
|
+
internal.insertVertex(lyr.gui.source.dataset.arcs, id, p);
|
|
3015
3005
|
if (isProjectedLayer(lyr)) {
|
|
3016
|
-
internal.insertVertex(lyr.
|
|
3006
|
+
internal.insertVertex(lyr.gui.displayArcs, id, lyr.gui.projectPoint(p[0], p[1]));
|
|
3017
3007
|
}
|
|
3018
3008
|
}
|
|
3019
3009
|
|
|
3020
3010
|
function appendVertex$1(lyr, p) {
|
|
3021
|
-
var n = lyr.source.dataset.arcs.getPointCount();
|
|
3011
|
+
var n = lyr.gui.source.dataset.arcs.getPointCount();
|
|
3022
3012
|
insertVertex$1(lyr, n, p);
|
|
3023
3013
|
}
|
|
3024
3014
|
|
|
3025
3015
|
// TODO: make sure we're not also removing an entire arc
|
|
3026
3016
|
function deleteLastVertex(lyr) {
|
|
3027
|
-
deleteVertex$1(lyr, lyr.
|
|
3017
|
+
deleteVertex$1(lyr, lyr.gui.displayArcs.getPointCount() - 1);
|
|
3028
3018
|
}
|
|
3029
3019
|
|
|
3030
3020
|
function deleteVertex$1(lyr, id) {
|
|
3031
|
-
internal.deleteVertex(lyr.
|
|
3021
|
+
internal.deleteVertex(lyr.gui.displayArcs, id);
|
|
3032
3022
|
if (isProjectedLayer(lyr)) {
|
|
3033
|
-
internal.deleteVertex(lyr.source.dataset.arcs, id);
|
|
3023
|
+
internal.deleteVertex(lyr.gui.source.dataset.arcs, id);
|
|
3034
3024
|
}
|
|
3035
3025
|
}
|
|
3036
3026
|
|
|
3037
3027
|
function getLastArcCoords(target) {
|
|
3038
|
-
var arcId = target.source.dataset.arcs.size() - 1;
|
|
3039
|
-
return internal.getUnfilteredArcCoords(arcId, target.source.dataset.arcs);
|
|
3028
|
+
var arcId = target.gui.source.dataset.arcs.size() - 1;
|
|
3029
|
+
return internal.getUnfilteredArcCoords(arcId, target.gui.source.dataset.arcs);
|
|
3040
3030
|
}
|
|
3041
3031
|
|
|
3042
3032
|
function getLastVertexCoords(target) {
|
|
3043
|
-
var arcs = target.source.dataset.arcs;
|
|
3033
|
+
var arcs = target.gui.source.dataset.arcs;
|
|
3044
3034
|
return internal.getVertexCoords(arcs.getPointCount() - 1, arcs);
|
|
3045
3035
|
}
|
|
3046
3036
|
|
|
3047
3037
|
function getLastArcLength(target) {
|
|
3048
|
-
var arcId = target.source.dataset.arcs.size() - 1;
|
|
3049
|
-
return internal.getUnfilteredArcLength(arcId, target.source.dataset.arcs);
|
|
3038
|
+
var arcId = target.gui.source.dataset.arcs.size() - 1;
|
|
3039
|
+
return internal.getUnfilteredArcLength(arcId, target.gui.source.dataset.arcs);
|
|
3050
3040
|
}
|
|
3051
3041
|
|
|
3052
3042
|
function getPointCoords(lyr, fid) {
|
|
3053
|
-
return internal.cloneShape(lyr.
|
|
3043
|
+
return internal.cloneShape(lyr.shapes[fid]);
|
|
3054
3044
|
}
|
|
3055
3045
|
|
|
3056
3046
|
function getVertexCoords(lyr, id) {
|
|
3057
|
-
return lyr.source.dataset.arcs.getVertex2(id);
|
|
3047
|
+
return lyr.gui.source.dataset.arcs.getVertex2(id);
|
|
3058
3048
|
}
|
|
3059
3049
|
|
|
3060
3050
|
// set data coords (not display coords) of one or more vertices.
|
|
3061
3051
|
function setVertexCoords(lyr, ids, dataPoint) {
|
|
3062
|
-
internal.snapVerticesToPoint(ids, dataPoint, lyr.source.dataset.arcs
|
|
3052
|
+
internal.snapVerticesToPoint(ids, dataPoint, lyr.gui.source.dataset.arcs);
|
|
3063
3053
|
if (isProjectedLayer(lyr)) {
|
|
3064
|
-
var p = lyr.projectPoint(dataPoint[0], dataPoint[1]);
|
|
3065
|
-
internal.snapVerticesToPoint(ids, p, lyr.
|
|
3054
|
+
var p = lyr.gui.projectPoint(dataPoint[0], dataPoint[1]);
|
|
3055
|
+
internal.snapVerticesToPoint(ids, p, lyr.gui.displayArcs);
|
|
3066
3056
|
}
|
|
3067
3057
|
}
|
|
3068
3058
|
|
|
3069
3059
|
// coords: [x, y] point in data CRS (not display CRS)
|
|
3070
3060
|
function setPointCoords(lyr, fid, coords) {
|
|
3071
|
-
lyr.
|
|
3061
|
+
lyr.shapes[fid] = coords;
|
|
3072
3062
|
if (isProjectedLayer(lyr)) {
|
|
3073
|
-
lyr.
|
|
3063
|
+
lyr.shapes[fid] = projectPointCoords(coords, lyr.gui.projectPoint);
|
|
3074
3064
|
}
|
|
3075
3065
|
}
|
|
3076
3066
|
|
|
3077
3067
|
function updateVertexCoords(lyr, ids) {
|
|
3078
3068
|
if (!isProjectedLayer(lyr)) return;
|
|
3079
|
-
var p = lyr.
|
|
3080
|
-
internal.snapVerticesToPoint(ids, lyr.invertPoint(p[0], p[1]), lyr.source.dataset.arcs
|
|
3069
|
+
var p = lyr.gui.displayArcs.getVertex2(ids[0]);
|
|
3070
|
+
internal.snapVerticesToPoint(ids, lyr.gui.invertPoint(p[0], p[1]), lyr.gui.source.dataset.arcs);
|
|
3081
3071
|
}
|
|
3082
3072
|
|
|
3083
3073
|
function setRectangleCoords(lyr, ids, coords) {
|
|
3084
3074
|
ids.forEach(function(id, i) {
|
|
3085
3075
|
var p = coords[i];
|
|
3086
|
-
internal.snapVerticesToPoint([id], p, lyr.source.dataset.arcs
|
|
3076
|
+
internal.snapVerticesToPoint([id], p, lyr.gui.source.dataset.arcs);
|
|
3087
3077
|
if (isProjectedLayer(lyr)) {
|
|
3088
|
-
internal.snapVerticesToPoint([id], lyr.projectPoint(p[0], p[1]), lyr.
|
|
3078
|
+
internal.snapVerticesToPoint([id], lyr.gui.projectPoint(p[0], p[1]), lyr.gui.displayArcs);
|
|
3089
3079
|
}
|
|
3090
3080
|
});
|
|
3091
3081
|
}
|
|
@@ -3093,8 +3083,8 @@
|
|
|
3093
3083
|
// Update source data coordinates by projecting display coordinates
|
|
3094
3084
|
function updatePointCoords(lyr, fid) {
|
|
3095
3085
|
if (!isProjectedLayer(lyr)) return;
|
|
3096
|
-
var displayShp = lyr.
|
|
3097
|
-
lyr.
|
|
3086
|
+
var displayShp = lyr.shapes[fid];
|
|
3087
|
+
lyr.shapes[fid] = projectPointCoords(displayShp, lyr.gui.invertPoint);
|
|
3098
3088
|
}
|
|
3099
3089
|
|
|
3100
3090
|
function projectPointCoords(src, proj) {
|
|
@@ -4231,6 +4221,11 @@
|
|
|
4231
4221
|
return layers.reverse();
|
|
4232
4222
|
}
|
|
4233
4223
|
|
|
4224
|
+
async function saveFileContentToClipboard(content) {
|
|
4225
|
+
var str = utils$1.isString(content) ? content : content.toString();
|
|
4226
|
+
await navigator.clipboard.writeText(str);
|
|
4227
|
+
}
|
|
4228
|
+
|
|
4234
4229
|
// Export buttons and their behavior
|
|
4235
4230
|
var ExportControl = function(gui) {
|
|
4236
4231
|
var model = gui.model;
|
|
@@ -4374,12 +4369,6 @@
|
|
|
4374
4369
|
} else {
|
|
4375
4370
|
await utils$1.promisify(internal.writeFiles)(files, opts);
|
|
4376
4371
|
}
|
|
4377
|
-
|
|
4378
|
-
}
|
|
4379
|
-
|
|
4380
|
-
async function saveFileContentToClipboard(content) {
|
|
4381
|
-
var str = utils$1.isString(content) ? content : content.toString();
|
|
4382
|
-
await navigator.clipboard.writeText(str);
|
|
4383
4372
|
}
|
|
4384
4373
|
|
|
4385
4374
|
function initLayerItem(o, i) {
|
|
@@ -5397,19 +5386,23 @@
|
|
|
5397
5386
|
function KeyboardEvents(gui) {
|
|
5398
5387
|
var self = this;
|
|
5399
5388
|
var shiftDown = false;
|
|
5389
|
+
var ctrlDown = false;
|
|
5400
5390
|
document.addEventListener('keyup', function(e) {
|
|
5401
5391
|
if (!GUI.isActiveInstance(gui)) return;
|
|
5402
5392
|
if (e.keyCode == 16) shiftDown = false;
|
|
5393
|
+
if (e.keyCode == 17) ctrlDown = false;
|
|
5403
5394
|
self.dispatchEvent('keyup', getEventData(e));
|
|
5404
5395
|
});
|
|
5405
5396
|
|
|
5406
5397
|
document.addEventListener('keydown', function(e) {
|
|
5407
5398
|
if (!GUI.isActiveInstance(gui)) return;
|
|
5408
5399
|
if (e.keyCode == 16) shiftDown = true;
|
|
5400
|
+
if (e.keyCode == 17) ctrlDown = true;
|
|
5409
5401
|
self.dispatchEvent('keydown', getEventData(e));
|
|
5410
5402
|
});
|
|
5411
5403
|
|
|
5412
5404
|
this.shiftIsPressed = function() { return shiftDown; };
|
|
5405
|
+
this.ctrlIsPressed = function() { return ctrlDown; };
|
|
5413
5406
|
|
|
5414
5407
|
this.onMenuSubmit = function(menuEl, cb) {
|
|
5415
5408
|
gui.on('enter_key', function(e) {
|
|
@@ -5426,6 +5419,7 @@
|
|
|
5426
5419
|
9: 'tab',
|
|
5427
5420
|
13: 'enter',
|
|
5428
5421
|
16: 'shift',
|
|
5422
|
+
17: 'ctrl',
|
|
5429
5423
|
27: 'esc',
|
|
5430
5424
|
32: 'space',
|
|
5431
5425
|
37: 'left',
|
|
@@ -5447,7 +5441,7 @@
|
|
|
5447
5441
|
var menus = {
|
|
5448
5442
|
standard: ['info', 'selection', 'box'],
|
|
5449
5443
|
polygons: ['info', 'selection', 'box', 'drawing'],
|
|
5450
|
-
rectangles: ['info', 'selection', 'box', 'rectangles'],
|
|
5444
|
+
rectangles: ['info', 'selection', 'box', 'rectangles'],
|
|
5451
5445
|
lines: ['info', 'selection', 'box' , 'drawing'],
|
|
5452
5446
|
table: ['info', 'selection'],
|
|
5453
5447
|
labels: ['info', 'selection', 'box', 'labels', 'location', 'add-points'],
|
|
@@ -5468,7 +5462,7 @@
|
|
|
5468
5462
|
labels: 'position labels',
|
|
5469
5463
|
location: 'drag points',
|
|
5470
5464
|
vertices: 'edit vertices',
|
|
5471
|
-
selection: '
|
|
5465
|
+
selection: 'selection tool',
|
|
5472
5466
|
'add-points': 'add points',
|
|
5473
5467
|
drawing: 'draw/reshape tool',
|
|
5474
5468
|
rectangles: 'drag-to-resize',
|
|
@@ -7261,11 +7255,11 @@
|
|
|
7261
7255
|
|
|
7262
7256
|
// featureFilter: optional test function, accepts feature id
|
|
7263
7257
|
//
|
|
7264
|
-
function getShapeHitTest(
|
|
7265
|
-
var geoType = displayLayer.
|
|
7258
|
+
function getShapeHitTest(layer, ext, interactionMode, featureFilter) {
|
|
7259
|
+
var geoType = layer.gui.displayLayer.geometry_type;
|
|
7266
7260
|
var test;
|
|
7267
|
-
if (geoType == 'point' &&
|
|
7268
|
-
test = getGraduatedCircleTest(getRadiusFunction(
|
|
7261
|
+
if (geoType == 'point' && layer.gui.style.type == 'styled') {
|
|
7262
|
+
test = getGraduatedCircleTest(getRadiusFunction(layer.gui.style));
|
|
7269
7263
|
} else if (geoType == 'point') {
|
|
7270
7264
|
test = pointTest;
|
|
7271
7265
|
} else if (interactionMode == 'drawing' && geoType == 'polygon') {
|
|
@@ -7305,13 +7299,13 @@
|
|
|
7305
7299
|
cand, hitId;
|
|
7306
7300
|
for (var i=0; i<cands.length; i++) {
|
|
7307
7301
|
cand = cands[i];
|
|
7308
|
-
if (geom.testPointInPolygon(x, y, cand.shape,
|
|
7302
|
+
if (geom.testPointInPolygon(x, y, cand.shape, layer.gui.displayArcs)) {
|
|
7309
7303
|
hits.push(cand);
|
|
7310
7304
|
}
|
|
7311
7305
|
}
|
|
7312
7306
|
if (cands.length > 0 && hits.length === 0) {
|
|
7313
7307
|
// secondary detection: proximity, if not inside a polygon
|
|
7314
|
-
sortByDistance(x, y, cands,
|
|
7308
|
+
sortByDistance(x, y, cands, layer.gui.displayArcs);
|
|
7315
7309
|
hits = pickNearestCandidates(cands, 0, maxDist);
|
|
7316
7310
|
}
|
|
7317
7311
|
return {
|
|
@@ -7336,7 +7330,7 @@
|
|
|
7336
7330
|
bufPix = bufArg >= 0 ? bufArg : 0.05, // tiny threshold for hitting almost-identical lines
|
|
7337
7331
|
bufDist = getZoomAdjustedHitBuffer(bufPix),
|
|
7338
7332
|
cands = findHitCandidates(x, y, maxDist);
|
|
7339
|
-
sortByDistance(x, y, cands,
|
|
7333
|
+
sortByDistance(x, y, cands, layer.gui.displayArcs);
|
|
7340
7334
|
cands = pickNearestCandidates(cands, bufDist, maxDist);
|
|
7341
7335
|
return {
|
|
7342
7336
|
ids: utils$1.pluck(cands, 'id')
|
|
@@ -7377,7 +7371,7 @@
|
|
|
7377
7371
|
hits = [];
|
|
7378
7372
|
|
|
7379
7373
|
// inlining forEachPoint() does not not appreciably speed this up
|
|
7380
|
-
internal.forEachPoint(displayLayer.
|
|
7374
|
+
internal.forEachPoint(layer.gui.displayLayer.shapes, function(p, id) {
|
|
7381
7375
|
var dist = geom.distance2D(x, y, p[0], p[1]) * toPx;
|
|
7382
7376
|
if (dist > hitThreshold) return;
|
|
7383
7377
|
if (dist < hitThreshold && hitThreshold > bullseyeDist) {
|
|
@@ -7411,7 +7405,7 @@
|
|
|
7411
7405
|
directHit = false,
|
|
7412
7406
|
hitRadius = 0,
|
|
7413
7407
|
hitDist;
|
|
7414
|
-
internal.forEachPoint(displayLayer.
|
|
7408
|
+
internal.forEachPoint(layer.gui.displayLayer.shapes, function(p, id) {
|
|
7415
7409
|
var distSq = geom.distanceSq(x, y, p[0], p[1]);
|
|
7416
7410
|
var isHit = false;
|
|
7417
7411
|
var isOver, isNear, r, d, rpix;
|
|
@@ -7451,11 +7445,11 @@
|
|
|
7451
7445
|
|
|
7452
7446
|
// Returns array of shape ids for shapes that pass a buffered bounding-box test
|
|
7453
7447
|
function findHitCandidates(x, y, dist) {
|
|
7454
|
-
var arcs =
|
|
7448
|
+
var arcs = layer.gui.displayArcs,
|
|
7455
7449
|
index = {},
|
|
7456
7450
|
cands = [],
|
|
7457
7451
|
bbox = [];
|
|
7458
|
-
displayLayer.
|
|
7452
|
+
layer.gui.displayLayer.shapes.forEach(function(shp, shpId) {
|
|
7459
7453
|
var cand;
|
|
7460
7454
|
if (featureFilter && !featureFilter(shpId)) {
|
|
7461
7455
|
return;
|
|
@@ -7587,7 +7581,7 @@
|
|
|
7587
7581
|
|
|
7588
7582
|
function getPointerHitTest(mapLayer, ext, interactionMode, featureFilter) {
|
|
7589
7583
|
var shapeTest, targetLayer;
|
|
7590
|
-
if (!mapLayer || !internal.layerHasGeometry(mapLayer.
|
|
7584
|
+
if (!mapLayer || !internal.layerHasGeometry(mapLayer.gui?.displayLayer)) {
|
|
7591
7585
|
return function() {return {ids: []};};
|
|
7592
7586
|
}
|
|
7593
7587
|
shapeTest = getShapeHitTest(mapLayer, ext, interactionMode, featureFilter);
|
|
@@ -7626,6 +7620,13 @@
|
|
|
7626
7620
|
// pan navigation
|
|
7627
7621
|
var priority = 2;
|
|
7628
7622
|
|
|
7623
|
+
mouse.on('contextmenu', function(e) {
|
|
7624
|
+
if (isOverMap(e)) {
|
|
7625
|
+
e.originalEvent.preventDefault();
|
|
7626
|
+
}
|
|
7627
|
+
triggerHitEvent('contextmenu', e);
|
|
7628
|
+
}, false);
|
|
7629
|
+
|
|
7629
7630
|
// init keyboard controls for pinned features
|
|
7630
7631
|
gui.keyboard.on('keydown', function(evt) {
|
|
7631
7632
|
var e = evt.originalEvent;
|
|
@@ -7653,7 +7654,7 @@
|
|
|
7653
7654
|
// to help protect against inadvertent deletion, don't delete
|
|
7654
7655
|
// when console is open or a popup menu is open
|
|
7655
7656
|
if (!gui.getMode() && !gui.consoleIsOpen()) {
|
|
7656
|
-
internal.deleteFeatureById(targetLayer
|
|
7657
|
+
internal.deleteFeatureById(targetLayer, pinnedId());
|
|
7657
7658
|
self.clearSelection();
|
|
7658
7659
|
gui.model.updated({flags: 'filter'}); // signal map to update
|
|
7659
7660
|
}
|
|
@@ -7696,6 +7697,7 @@
|
|
|
7696
7697
|
|
|
7697
7698
|
function pinnable() {
|
|
7698
7699
|
return clickable() && !selectable();
|
|
7700
|
+
// return clickable();
|
|
7699
7701
|
}
|
|
7700
7702
|
|
|
7701
7703
|
function draggable() {
|
|
@@ -7790,7 +7792,7 @@
|
|
|
7790
7792
|
|
|
7791
7793
|
self.getTargetDataTable = function() {
|
|
7792
7794
|
var targ = self.getHitTarget();
|
|
7793
|
-
return targ
|
|
7795
|
+
return targ?.data || null;
|
|
7794
7796
|
};
|
|
7795
7797
|
|
|
7796
7798
|
// get function for selecting next or prev feature within the current set of
|
|
@@ -7803,7 +7805,7 @@
|
|
|
7803
7805
|
|
|
7804
7806
|
// diff: 1 or -1
|
|
7805
7807
|
function advanceSelectedFeature(diff) {
|
|
7806
|
-
var n = internal.getFeatureCount(targetLayer
|
|
7808
|
+
var n = internal.getFeatureCount(targetLayer);
|
|
7807
7809
|
if (n < 2 || pinnedId() == -1) return;
|
|
7808
7810
|
storedData.id = (pinnedId() + n + diff) % n;
|
|
7809
7811
|
storedData.ids = [storedData.id];
|
|
@@ -7848,12 +7850,15 @@
|
|
|
7848
7850
|
|
|
7849
7851
|
mouse.on('click', function(e) {
|
|
7850
7852
|
if (!hitTest || !active) return;
|
|
7853
|
+
if (!eventIsEnabled('click')) return;
|
|
7854
|
+
|
|
7851
7855
|
e.stopPropagation();
|
|
7852
7856
|
|
|
7853
7857
|
// TODO: move pinning to inspection control?
|
|
7854
7858
|
if (clickable()) {
|
|
7855
7859
|
updateSelectionState(convertClickDataToSelectionData(hitTest(e)));
|
|
7856
7860
|
}
|
|
7861
|
+
|
|
7857
7862
|
triggerHitEvent('click', e);
|
|
7858
7863
|
}, null, priority);
|
|
7859
7864
|
|
|
@@ -7872,6 +7877,7 @@
|
|
|
7872
7877
|
}
|
|
7873
7878
|
}, null, priority);
|
|
7874
7879
|
|
|
7880
|
+
|
|
7875
7881
|
function targetIsRollover(target) {
|
|
7876
7882
|
while (target.parentNode && target != target.parentNode) {
|
|
7877
7883
|
if (target.className && String(target.className).indexOf('rollover') > -1) {
|
|
@@ -7910,6 +7916,19 @@
|
|
|
7910
7916
|
return hitData;
|
|
7911
7917
|
}
|
|
7912
7918
|
|
|
7919
|
+
function mergeSelectionModeHoverData(hitData) {
|
|
7920
|
+
if (hitData.ids.length === 0 || selectionIds.includes(hitData.ids[0])) {
|
|
7921
|
+
hitData.ids = selectionIds;
|
|
7922
|
+
hitData.pinned = storedData.pinned;
|
|
7923
|
+
} else {
|
|
7924
|
+
//
|
|
7925
|
+
}
|
|
7926
|
+
|
|
7927
|
+
// kludge to inhibit hover effect while dragging a box
|
|
7928
|
+
if (gui.keydown) hitData.id = -1;
|
|
7929
|
+
return hitData;
|
|
7930
|
+
}
|
|
7931
|
+
|
|
7913
7932
|
function mergeHoverData(hitData) {
|
|
7914
7933
|
if (storedData.pinned) {
|
|
7915
7934
|
hitData.id = storedData.id;
|
|
@@ -7964,14 +7983,21 @@
|
|
|
7964
7983
|
return true; // special case -- using hover for line drawing animation
|
|
7965
7984
|
}
|
|
7966
7985
|
|
|
7986
|
+
if (type == 'click' && gui.keyboard.ctrlIsPressed()) {
|
|
7987
|
+
return false; // don't fire if context menu might open
|
|
7988
|
+
}
|
|
7989
|
+
if (type == 'click' && gui.contextMenu.isOpen()) {
|
|
7990
|
+
return false;
|
|
7991
|
+
}
|
|
7992
|
+
if (type == 'click' && interactionMode == 'drawing') {
|
|
7993
|
+
return true; // click events are triggered even if no shape is hit
|
|
7994
|
+
}
|
|
7995
|
+
|
|
7967
7996
|
// ignore pointer events when no features are being hit
|
|
7968
7997
|
// (don't block pan and other navigation when events aren't being used for editing)
|
|
7969
7998
|
var hitId = self.getHitId();
|
|
7970
7999
|
if (hitId == -1) return false;
|
|
7971
8000
|
|
|
7972
|
-
if (type == 'click' && !clickable()) {
|
|
7973
|
-
return false;
|
|
7974
|
-
}
|
|
7975
8001
|
if ((type == 'drag' || type == 'dragstart' || type == 'dragend') && !draggable()) {
|
|
7976
8002
|
return false;
|
|
7977
8003
|
}
|
|
@@ -8000,10 +8026,13 @@
|
|
|
8000
8026
|
// evt: event data (may be a pointer event object, an ordinary object or null)
|
|
8001
8027
|
function triggerHitEvent(type, evt) {
|
|
8002
8028
|
var eventData = {
|
|
8003
|
-
mode: interactionMode
|
|
8004
|
-
overMap: evt ? isOverMap(evt) : null,
|
|
8005
|
-
originalEvent: evt ? evt : null
|
|
8029
|
+
mode: interactionMode
|
|
8006
8030
|
};
|
|
8031
|
+
if (evt) {
|
|
8032
|
+
eventData.coordinates = translateDisplayPoint(targetLayer, ext.translatePixelCoords(evt.x, evt.y));
|
|
8033
|
+
eventData.originalEvent = evt;
|
|
8034
|
+
eventData.overMap = isOverMap(evt);
|
|
8035
|
+
}
|
|
8007
8036
|
// Merge stored hit data into the event data
|
|
8008
8037
|
utils$1.defaults(eventData, evt && evt.data || {}, storedData);
|
|
8009
8038
|
// utils.extend(eventData, storedData);
|
|
@@ -8050,7 +8079,7 @@
|
|
|
8050
8079
|
|
|
8051
8080
|
function enabled() {
|
|
8052
8081
|
var lyr = gui.map.getActiveLayer();
|
|
8053
|
-
return !!(lyr && lyr.
|
|
8082
|
+
return !!(lyr && lyr.gui.displayLayer.geometry_type);
|
|
8054
8083
|
}
|
|
8055
8084
|
|
|
8056
8085
|
gui.model.on('update', function(e) {
|
|
@@ -8095,7 +8124,7 @@
|
|
|
8095
8124
|
var p2 = gui.map.translatePixelCoords(ext.width(), 0);
|
|
8096
8125
|
var bbox = p1.concat(p2);
|
|
8097
8126
|
var decimals = internal.getBoundsPrecisionForDisplay(bbox);
|
|
8098
|
-
|
|
8127
|
+
var str = internal.getRoundedCoordString(p, decimals);
|
|
8099
8128
|
readout.text(str).show();
|
|
8100
8129
|
}
|
|
8101
8130
|
|
|
@@ -8376,6 +8405,9 @@
|
|
|
8376
8405
|
element.addEventListener('mouseout', onAreaOut);
|
|
8377
8406
|
element.addEventListener('mousedown', onAreaDown);
|
|
8378
8407
|
element.addEventListener('dblclick', onAreaDblClick);
|
|
8408
|
+
document.addEventListener('contextmenu', function(e) {
|
|
8409
|
+
_self.dispatchEvent('contextmenu', procMouseEvent(e));
|
|
8410
|
+
});
|
|
8379
8411
|
|
|
8380
8412
|
this.enable = function() {
|
|
8381
8413
|
if (!_disabled) return;
|
|
@@ -8943,8 +8975,8 @@
|
|
|
8943
8975
|
gui.on('interaction_mode_change', function(e) {
|
|
8944
8976
|
if (e.mode === 'selection') {
|
|
8945
8977
|
gui.enterMode('selection_tool');
|
|
8946
|
-
} else if (
|
|
8947
|
-
|
|
8978
|
+
} else if (_on) {
|
|
8979
|
+
turnOff();
|
|
8948
8980
|
}
|
|
8949
8981
|
});
|
|
8950
8982
|
|
|
@@ -9410,8 +9442,17 @@
|
|
|
9410
9442
|
}
|
|
9411
9443
|
});
|
|
9412
9444
|
|
|
9445
|
+
hit.on('contextmenu', function(e) {
|
|
9446
|
+
var target = hit.getHitTarget();
|
|
9447
|
+
if (!e.overMap || !target) return;
|
|
9448
|
+
|
|
9449
|
+
if (e.mode == 'drawing') return; // TODO: make special menu for this mode
|
|
9450
|
+
gui.contextMenu.open(e, hit.getHitTarget());
|
|
9451
|
+
});
|
|
9452
|
+
|
|
9413
9453
|
hit.on('change', function(e) {
|
|
9414
9454
|
if (!inspecting()) return;
|
|
9455
|
+
if (gui.keyboard.ctrlIsPressed()) return;
|
|
9415
9456
|
var ids;
|
|
9416
9457
|
if (e.mode == 'selection') {
|
|
9417
9458
|
ids = e.pinned && e.ids || [];
|
|
@@ -9424,8 +9465,8 @@
|
|
|
9424
9465
|
// id: Id of a feature in the active layer, or -1
|
|
9425
9466
|
function inspect(id, ids, pin) {
|
|
9426
9467
|
var target = hit.getHitTarget();
|
|
9427
|
-
if ((id > -1 || ids && ids.length > 0) && inspecting() && target && target
|
|
9428
|
-
_popup.show(id, ids, target
|
|
9468
|
+
if ((id > -1 || ids && ids.length > 0) && inspecting() && target && target) {
|
|
9469
|
+
_popup.show(id, ids, target, pin);
|
|
9429
9470
|
} else {
|
|
9430
9471
|
_popup.hide();
|
|
9431
9472
|
}
|
|
@@ -9529,15 +9570,20 @@
|
|
|
9529
9570
|
|
|
9530
9571
|
function initLabelDragging(gui, ext, hit) {
|
|
9531
9572
|
var downEvt;
|
|
9532
|
-
var activeId;
|
|
9573
|
+
var activeId = -1;
|
|
9574
|
+
var prevHitEvt;
|
|
9533
9575
|
var activeRecord;
|
|
9534
9576
|
|
|
9535
|
-
function active(
|
|
9536
|
-
return
|
|
9577
|
+
function active() {
|
|
9578
|
+
return gui.interaction.getMode() == 'labels';
|
|
9579
|
+
}
|
|
9580
|
+
|
|
9581
|
+
function labelSelected(e) {
|
|
9582
|
+
return e.id > -1 && active();
|
|
9537
9583
|
}
|
|
9538
9584
|
|
|
9539
9585
|
hit.on('dragstart', function(e) {
|
|
9540
|
-
if (!
|
|
9586
|
+
if (!labelSelected(e)) return;
|
|
9541
9587
|
var symNode = getSymbolTarget(e);
|
|
9542
9588
|
var table = hit.getTargetDataTable();
|
|
9543
9589
|
if (!symNode || !table) {
|
|
@@ -9550,8 +9596,25 @@
|
|
|
9550
9596
|
gui.dispatchEvent('label_dragstart', {FID: activeId});
|
|
9551
9597
|
});
|
|
9552
9598
|
|
|
9599
|
+
hit.on('change', function(e) {
|
|
9600
|
+
if (!active()) return;
|
|
9601
|
+
if (prevHitEvt) clearLabelHighlight(prevHitEvt);
|
|
9602
|
+
showLabelHighlight(e);
|
|
9603
|
+
prevHitEvt = e;
|
|
9604
|
+
});
|
|
9605
|
+
|
|
9606
|
+
function clearLabelHighlight(e) {
|
|
9607
|
+
var txt = getTextNode(getSymbolTarget(e));
|
|
9608
|
+
if (txt) txt.classList.remove('active-label');
|
|
9609
|
+
}
|
|
9610
|
+
|
|
9611
|
+
function showLabelHighlight(e) {
|
|
9612
|
+
var txt = getTextNode(getSymbolTarget(e));
|
|
9613
|
+
if (txt) txt.classList.add('active-label');
|
|
9614
|
+
}
|
|
9615
|
+
|
|
9553
9616
|
hit.on('drag', function(e) {
|
|
9554
|
-
if (!
|
|
9617
|
+
if (!labelSelected(e) || activeId == -1) return;
|
|
9555
9618
|
if (e.id != activeId) {
|
|
9556
9619
|
error$1("Mismatched hit ids:", e.id, activeId);
|
|
9557
9620
|
}
|
|
@@ -9565,7 +9628,7 @@
|
|
|
9565
9628
|
// to anchor point, for better placement when eventual display font is
|
|
9566
9629
|
// different from mapshaper's font.
|
|
9567
9630
|
// if (!isMultilineLabel(textNode)) {
|
|
9568
|
-
autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget()
|
|
9631
|
+
autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget(), ext));
|
|
9569
9632
|
// }
|
|
9570
9633
|
updateNumber(activeRecord, 'dx', internal.roundToDigits(+activeRecord.dx, 3));
|
|
9571
9634
|
updateNumber(activeRecord, 'dy', internal.roundToDigits(+activeRecord.dy, 3));
|
|
@@ -9575,7 +9638,7 @@
|
|
|
9575
9638
|
});
|
|
9576
9639
|
|
|
9577
9640
|
hit.on('dragend', function(e) {
|
|
9578
|
-
if (!
|
|
9641
|
+
if (!labelSelected(e) || activeId == -1) return;
|
|
9579
9642
|
gui.dispatchEvent('label_dragend', {FID: e.id});
|
|
9580
9643
|
activeId = -1;
|
|
9581
9644
|
activeRecord = null;
|
|
@@ -9596,19 +9659,25 @@
|
|
|
9596
9659
|
}
|
|
9597
9660
|
|
|
9598
9661
|
function getSymbolTarget(e) {
|
|
9599
|
-
|
|
9600
|
-
return getSymbolNodeById(e.id, e.container);
|
|
9662
|
+
return e.id > -1 ? getSymbolNodeById(e.id) : null;
|
|
9601
9663
|
}
|
|
9602
9664
|
|
|
9603
9665
|
function getTextNode(symNode) {
|
|
9666
|
+
if (!symNode) return null;
|
|
9604
9667
|
if (symNode.tagName == 'text') return symNode;
|
|
9605
9668
|
return symNode.querySelector('text');
|
|
9606
9669
|
}
|
|
9607
9670
|
|
|
9608
|
-
function
|
|
9671
|
+
// function getSymbolNodeById_OLD(id, parent) {
|
|
9672
|
+
// var sel = '[data-id="' + id + '"]';
|
|
9673
|
+
// return parent.querySelector(sel);
|
|
9674
|
+
// }
|
|
9675
|
+
|
|
9676
|
+
function getSymbolNodeById(id) {
|
|
9609
9677
|
// TODO: optimize selector
|
|
9610
9678
|
var sel = '[data-id="' + id + '"]';
|
|
9611
|
-
|
|
9679
|
+
var activeLayer = hit.getHitTarget();
|
|
9680
|
+
return activeLayer.gui.svg_container.querySelector(sel);
|
|
9612
9681
|
}
|
|
9613
9682
|
|
|
9614
9683
|
// function getTextTarget2(e) {
|
|
@@ -9655,7 +9724,7 @@
|
|
|
9655
9724
|
// fails when symbol includes a dot (<g><circle/><text/></g> structure)
|
|
9656
9725
|
function updateSymbolNode(node, d, id) {
|
|
9657
9726
|
var o = internal.svg.renderStyledLabel(d); // TODO: symbol support
|
|
9658
|
-
var activeLayer = hit.getHitTarget()
|
|
9727
|
+
var activeLayer = hit.getHitTarget();
|
|
9659
9728
|
var xy = activeLayer.shapes[id][0];
|
|
9660
9729
|
var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
9661
9730
|
var node2;
|
|
@@ -9688,7 +9757,7 @@
|
|
|
9688
9757
|
hit.on('drag', function(e) {
|
|
9689
9758
|
if (!active(e)) return;
|
|
9690
9759
|
// TODO: support multi points... get id of closest part to the pointer
|
|
9691
|
-
var p = getPointCoordsById(e.id, symbolInfo.target
|
|
9760
|
+
var p = getPointCoordsById(e.id, symbolInfo.target);
|
|
9692
9761
|
if (!p) return;
|
|
9693
9762
|
var diff = translateDeltaDisplayCoords(e.dx, e.dy, ext);
|
|
9694
9763
|
p[0] += diff[0];
|
|
@@ -9719,8 +9788,8 @@
|
|
|
9719
9788
|
}
|
|
9720
9789
|
}
|
|
9721
9790
|
|
|
9722
|
-
//
|
|
9723
|
-
var HOVER_THRESHOLD
|
|
9791
|
+
// pixel distance threshold for hovering near a vertex or segment midpoint
|
|
9792
|
+
var HOVER_THRESHOLD = 10;
|
|
9724
9793
|
|
|
9725
9794
|
function initLineEditing(gui, ext, hit) {
|
|
9726
9795
|
var hoverVertexInfo;
|
|
@@ -9746,7 +9815,7 @@
|
|
|
9746
9815
|
}
|
|
9747
9816
|
|
|
9748
9817
|
function polygonMode() {
|
|
9749
|
-
return active() && hit.getHitTarget().
|
|
9818
|
+
return active() && hit.getHitTarget().geometry_type == 'polygon';
|
|
9750
9819
|
}
|
|
9751
9820
|
|
|
9752
9821
|
function clearHoverVertex() {
|
|
@@ -9762,7 +9831,7 @@
|
|
|
9762
9831
|
if (e.mode == 'drawing') {
|
|
9763
9832
|
gui.enterMode('drawing_tool');
|
|
9764
9833
|
} else if (active()) {
|
|
9765
|
-
|
|
9834
|
+
turnOff();
|
|
9766
9835
|
}
|
|
9767
9836
|
}, null, 10); // higher priority than hit control, so turnOff() has correct hit target
|
|
9768
9837
|
|
|
@@ -9789,27 +9858,10 @@
|
|
|
9789
9858
|
appendVertex$1(target, e.p);
|
|
9790
9859
|
}
|
|
9791
9860
|
if (e.shapes) {
|
|
9792
|
-
|
|
9861
|
+
replaceDrawnShapes(e.shapes);
|
|
9793
9862
|
}
|
|
9794
9863
|
});
|
|
9795
9864
|
|
|
9796
|
-
function replaceShapes(shapes) {
|
|
9797
|
-
var target = hit.getHitTarget();
|
|
9798
|
-
var records = target.layer.data?.getRecords();
|
|
9799
|
-
var prevLen = target.layer.shapes.length;
|
|
9800
|
-
var newLen = initialShapeCount + shapes.length;
|
|
9801
|
-
var recordCount = records?.length || 0;
|
|
9802
|
-
target.layer.shapes = target.layer.shapes.slice(0, initialShapeCount).concat(shapes);
|
|
9803
|
-
while (records && records.length > newLen) {
|
|
9804
|
-
records.pop();
|
|
9805
|
-
}
|
|
9806
|
-
while (records && records.length < newLen) {
|
|
9807
|
-
appendNewDataRecord(target.layer);
|
|
9808
|
-
}
|
|
9809
|
-
}
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
9865
|
gui.on('undo_path_extend', function(e) {
|
|
9814
9866
|
var target = hit.getHitTarget();
|
|
9815
9867
|
if (drawing() && prevHoverEvent) {
|
|
@@ -9822,14 +9874,14 @@
|
|
|
9822
9874
|
gui.undo.undo(); // remove the path
|
|
9823
9875
|
}
|
|
9824
9876
|
if (e.shapes) {
|
|
9825
|
-
|
|
9877
|
+
replaceDrawnShapes(e.shapes);
|
|
9826
9878
|
}
|
|
9827
9879
|
});
|
|
9828
9880
|
|
|
9829
9881
|
function turnOn() {
|
|
9830
9882
|
var target = hit.getHitTarget();
|
|
9831
|
-
initialArcCount = target.
|
|
9832
|
-
initialShapeCount = target.
|
|
9883
|
+
initialArcCount = target.gui.displayArcs.size();
|
|
9884
|
+
initialShapeCount = target.shapes.length;
|
|
9833
9885
|
if (sessionCount === 0) {
|
|
9834
9886
|
showInstructions();
|
|
9835
9887
|
}
|
|
@@ -9845,6 +9897,12 @@
|
|
|
9845
9897
|
non_blocking: true, max_width: '360px'});
|
|
9846
9898
|
}
|
|
9847
9899
|
|
|
9900
|
+
function hideInstructions() {
|
|
9901
|
+
if (!alert) return;
|
|
9902
|
+
alert.close('fade');
|
|
9903
|
+
alert = null;
|
|
9904
|
+
}
|
|
9905
|
+
|
|
9848
9906
|
function turnOff() {
|
|
9849
9907
|
var removed = 0;
|
|
9850
9908
|
finishCurrentPath();
|
|
@@ -9852,10 +9910,7 @@
|
|
|
9852
9910
|
removed = removeOpenPolygons();
|
|
9853
9911
|
}
|
|
9854
9912
|
clearDrawingInfo();
|
|
9855
|
-
|
|
9856
|
-
alert.close();
|
|
9857
|
-
alert = null;
|
|
9858
|
-
}
|
|
9913
|
+
hideInstructions();
|
|
9859
9914
|
initialArcCount = -1;
|
|
9860
9915
|
initialShapeCount = -1;
|
|
9861
9916
|
if (gui.interaction.getMode() == 'drawing') {
|
|
@@ -9870,20 +9925,21 @@
|
|
|
9870
9925
|
// returns number of removed shapes
|
|
9871
9926
|
function removeOpenPolygons() {
|
|
9872
9927
|
var target = hit.getHitTarget();
|
|
9873
|
-
var arcs = target.source.dataset.arcs;
|
|
9874
|
-
var n = target.
|
|
9875
|
-
// delete open paths
|
|
9928
|
+
var arcs = target.gui.source.dataset.arcs;
|
|
9929
|
+
var n = target.shapes.length;
|
|
9930
|
+
// delete open paths
|
|
9876
9931
|
for (var i=initialShapeCount; i<n; i++) {
|
|
9877
|
-
var shp = target.
|
|
9878
|
-
if (!geom.pathIsClosed(shp[0], arcs)) {
|
|
9879
|
-
target.
|
|
9932
|
+
var shp = target.shapes[i];
|
|
9933
|
+
if (!geom.pathIsClosed(shp[0], arcs)) { // assume open paths have one arc
|
|
9934
|
+
target.shapes[i] = null;
|
|
9880
9935
|
}
|
|
9881
9936
|
}
|
|
9882
|
-
// removes
|
|
9883
|
-
mapshaper.cmd.filterFeatures(target
|
|
9884
|
-
return n - target.
|
|
9937
|
+
// removes features with wrong winding order or null geometry
|
|
9938
|
+
mapshaper.cmd.filterFeatures(target, arcs, {remove_empty: true, quiet: true});
|
|
9939
|
+
return n - target.shapes.length;
|
|
9885
9940
|
}
|
|
9886
9941
|
|
|
9942
|
+
// updates display arcs and redraws all layers
|
|
9887
9943
|
function fullRedraw() {
|
|
9888
9944
|
gui.model.updated({arc_count: true});
|
|
9889
9945
|
}
|
|
@@ -9895,13 +9951,25 @@
|
|
|
9895
9951
|
prevClickEvent = prevHoverEvent = null;
|
|
9896
9952
|
}
|
|
9897
9953
|
|
|
9954
|
+
hit.on('contextmenu', function(e) {
|
|
9955
|
+
if (!active() || drawing() || dragging()) return;
|
|
9956
|
+
var target = hit.getHitTarget();
|
|
9957
|
+
var vInfo = hoverVertexInfo;
|
|
9958
|
+
if (hoverVertexInfo?.type == 'vertex' && !vertexIsEndpoint(vInfo, target)) {
|
|
9959
|
+
e.deleteVertex = function() {
|
|
9960
|
+
deleteActiveVertex(e, vInfo);
|
|
9961
|
+
};
|
|
9962
|
+
}
|
|
9963
|
+
// don't allow copying of open paths as geojson in polygon mode
|
|
9964
|
+
gui.contextMenu.open(e, target);
|
|
9965
|
+
});
|
|
9966
|
+
|
|
9898
9967
|
hit.on('dragstart', function(e) {
|
|
9899
9968
|
if (!active() || drawing() || !hoverVertexInfo) return;
|
|
9900
|
-
|
|
9901
|
-
alert.close('fade');
|
|
9902
|
-
}
|
|
9969
|
+
hideInstructions();
|
|
9903
9970
|
e.originalEvent.stopPropagation();
|
|
9904
9971
|
_dragging = true;
|
|
9972
|
+
updateCursor();
|
|
9905
9973
|
if (hoverVertexInfo.type == 'interpolated') {
|
|
9906
9974
|
insertVertex$1(hit.getHitTarget(), hoverVertexInfo.i, hoverVertexInfo.point);
|
|
9907
9975
|
hoverVertexInfo.ids = [hoverVertexInfo.i];
|
|
@@ -9915,11 +9983,10 @@
|
|
|
9915
9983
|
var target = hit.getHitTarget();
|
|
9916
9984
|
var p = ext.translatePixelCoords(e.x, e.y);
|
|
9917
9985
|
if (gui.keyboard.shiftIsPressed()) {
|
|
9918
|
-
internal.snapPointToArcEndpoint(p, hoverVertexInfo.ids, target.
|
|
9986
|
+
internal.snapPointToArcEndpoint(p, hoverVertexInfo.ids, target.gui.displayArcs);
|
|
9919
9987
|
}
|
|
9920
|
-
internal.snapVerticesToPoint(hoverVertexInfo.ids, p, target.
|
|
9988
|
+
internal.snapVerticesToPoint(hoverVertexInfo.ids, p, target.gui.displayArcs);
|
|
9921
9989
|
hit.setHoverVertex(p, '');
|
|
9922
|
-
|
|
9923
9990
|
// redrawing the whole map updates the data layer as well as the overlay layer
|
|
9924
9991
|
// gui.dispatchEvent('map-needs-refresh');
|
|
9925
9992
|
});
|
|
@@ -9927,9 +9994,9 @@
|
|
|
9927
9994
|
hit.on('dragend', function(e) {
|
|
9928
9995
|
if (!dragging()) return;
|
|
9929
9996
|
_dragging = false;
|
|
9930
|
-
// kludge to get dataset to recalculate internal bounding boxes
|
|
9931
9997
|
var target = hit.getHitTarget();
|
|
9932
|
-
|
|
9998
|
+
// kludge to get dataset to recalculate internal bounding boxes
|
|
9999
|
+
target.gui.displayArcs.transformPoints(function() {});
|
|
9933
10000
|
updateVertexCoords(target, hoverVertexInfo.ids);
|
|
9934
10001
|
gui.dispatchEvent('vertex_dragend', hoverVertexInfo);
|
|
9935
10002
|
gui.dispatchEvent('map-needs-refresh'); // redraw basemap
|
|
@@ -9953,6 +10020,7 @@
|
|
|
9953
10020
|
// ... or the closest point along the segment (for adding a new vertex)
|
|
9954
10021
|
hit.on('hover', function(e) {
|
|
9955
10022
|
if (!active() || dragging()) return;
|
|
10023
|
+
|
|
9956
10024
|
if (drawing()) {
|
|
9957
10025
|
if (!e.overMap) {
|
|
9958
10026
|
finishCurrentPath();
|
|
@@ -9975,6 +10043,7 @@
|
|
|
9975
10043
|
} else {
|
|
9976
10044
|
clearHoverVertex();
|
|
9977
10045
|
}
|
|
10046
|
+
updateCursor();
|
|
9978
10047
|
prevHoverEvent = e;
|
|
9979
10048
|
}, null, 100);
|
|
9980
10049
|
|
|
@@ -9985,23 +10054,22 @@
|
|
|
9985
10054
|
var p = pixToDataCoords(e.x, e.y);
|
|
9986
10055
|
if (drawing()) {
|
|
9987
10056
|
extendCurrentPath(hoverVertexInfo?.point || p);
|
|
9988
|
-
// extendCurrentPath(p); // just extend to current mouse position (not hover vertex)
|
|
9989
10057
|
} else if (gui.keyboard.shiftIsPressed()) {
|
|
9990
10058
|
deleteActiveVertex(e);
|
|
9991
10059
|
} else {
|
|
9992
10060
|
startNewPath(p);
|
|
9993
|
-
|
|
9994
|
-
|
|
9995
|
-
}
|
|
10061
|
+
hideInstructions();
|
|
10062
|
+
updateCursor();
|
|
9996
10063
|
}
|
|
9997
10064
|
prevClickEvent = e;
|
|
9998
10065
|
});
|
|
9999
10066
|
|
|
10000
|
-
// esc key finishes a path
|
|
10067
|
+
// esc or enter key finishes a path
|
|
10001
10068
|
gui.keyboard.on('keydown', function(e) {
|
|
10002
10069
|
if (active() && (e.keyName == 'esc' || e.keyName == 'enter')) {
|
|
10003
10070
|
e.stopPropagation();
|
|
10004
10071
|
finishCurrentPath();
|
|
10072
|
+
e.originalEvent.preventDefault(); // block console "enter"
|
|
10005
10073
|
}
|
|
10006
10074
|
}, null, 10);
|
|
10007
10075
|
|
|
@@ -10015,16 +10083,24 @@
|
|
|
10015
10083
|
return dbl;
|
|
10016
10084
|
}
|
|
10017
10085
|
|
|
10018
|
-
function
|
|
10019
|
-
var
|
|
10020
|
-
|
|
10086
|
+
function updateCursor() {
|
|
10087
|
+
var useArrow = hoverVertexInfo && !hoverVertexInfo.extendable && !drawing();
|
|
10088
|
+
gui.container.findChild('.map-layers').classed('dragging', useArrow);
|
|
10089
|
+
}
|
|
10090
|
+
|
|
10091
|
+
function vertexIsEndpoint(info, target) {
|
|
10092
|
+
var vId = info.ids[0];
|
|
10093
|
+
return internal.vertexIsArcStart(vId, target.gui.displayArcs) ||
|
|
10094
|
+
internal.vertexIsArcEnd(vId, target.gui.displayArcs);
|
|
10095
|
+
}
|
|
10096
|
+
|
|
10097
|
+
// info: optional vertex info object
|
|
10098
|
+
function deleteActiveVertex(e, infoArg) {
|
|
10099
|
+
var info = infoArg || findDraggableVertices(e);
|
|
10100
|
+
if (!info || info.type != 'vertex') return;
|
|
10021
10101
|
var vId = info.ids[0];
|
|
10022
10102
|
var target = hit.getHitTarget();
|
|
10023
|
-
if (
|
|
10024
|
-
internal.vertexIsArcEnd(vId, target.arcs)) {
|
|
10025
|
-
// TODO: support removing arc endpoints
|
|
10026
|
-
return;
|
|
10027
|
-
}
|
|
10103
|
+
if (vertexIsEndpoint(info, target)) return;
|
|
10028
10104
|
gui.dispatchEvent('vertex_delete', {
|
|
10029
10105
|
target: target,
|
|
10030
10106
|
vertex_id: vId
|
|
@@ -10050,25 +10126,27 @@
|
|
|
10050
10126
|
var dist2 = dist / Math.sqrt(2);
|
|
10051
10127
|
var minDist = Infinity;
|
|
10052
10128
|
var cands = [
|
|
10053
|
-
{
|
|
10054
|
-
{
|
|
10055
|
-
{
|
|
10056
|
-
{
|
|
10057
|
-
{
|
|
10058
|
-
{
|
|
10059
|
-
{
|
|
10060
|
-
{
|
|
10129
|
+
{dx: 0, dy: dist},
|
|
10130
|
+
{dx: 0, dy: -dist},
|
|
10131
|
+
{dx: dist, dy: 0},
|
|
10132
|
+
{dx: -dist, dy: 0},
|
|
10133
|
+
{dx: dist2, dy: dist2},
|
|
10134
|
+
{dx: dist2, dy: -dist2},
|
|
10135
|
+
{dx: -dist2, dy: dist2},
|
|
10136
|
+
{dx: -dist2, dy: -dist2}
|
|
10061
10137
|
];
|
|
10062
10138
|
var snapped = cands.reduce(function(memo, cand) {
|
|
10063
|
-
var dist = geom.distance2D(thisEvt.x, thisEvt.y, cand.
|
|
10139
|
+
var dist = geom.distance2D(thisEvt.x, thisEvt.y, x0 + cand.dx, y0 + cand.dy);
|
|
10064
10140
|
if (dist < minDist) {
|
|
10065
10141
|
minDist = dist;
|
|
10066
10142
|
return cand;
|
|
10067
10143
|
}
|
|
10068
10144
|
return memo;
|
|
10069
10145
|
}, null);
|
|
10070
|
-
thisEvt.x = snapped.
|
|
10071
|
-
thisEvt.y = snapped.
|
|
10146
|
+
thisEvt.x = x0 + snapped.dx;
|
|
10147
|
+
thisEvt.y = y0 + snapped.dy;
|
|
10148
|
+
|
|
10149
|
+
return null;
|
|
10072
10150
|
}
|
|
10073
10151
|
|
|
10074
10152
|
function finishCurrentPath() {
|
|
@@ -10089,7 +10167,7 @@
|
|
|
10089
10167
|
var p1 = hoverVertexInfo?.point || p2;
|
|
10090
10168
|
appendNewPath(target, p1, p2);
|
|
10091
10169
|
gui.dispatchEvent('path_add', {target, p1, p2});
|
|
10092
|
-
drawingId = target.
|
|
10170
|
+
drawingId = target.shapes.length - 1;
|
|
10093
10171
|
hit.setDrawingId(drawingId);
|
|
10094
10172
|
}
|
|
10095
10173
|
|
|
@@ -10103,11 +10181,11 @@
|
|
|
10103
10181
|
error$1('Defective path');
|
|
10104
10182
|
}
|
|
10105
10183
|
if (finish && polygonMode()) {
|
|
10106
|
-
shapes1 = target.
|
|
10107
|
-
shapes2 =
|
|
10184
|
+
shapes1 = target.shapes.slice(initialShapeCount);
|
|
10185
|
+
shapes2 = convertClosedPaths(shapes1);
|
|
10108
10186
|
}
|
|
10109
10187
|
if (shapes2) {
|
|
10110
|
-
|
|
10188
|
+
replaceDrawnShapes(shapes2);
|
|
10111
10189
|
gui.dispatchEvent('path_extend', {target, p, shapes1, shapes2});
|
|
10112
10190
|
clearDrawingInfo();
|
|
10113
10191
|
fullRedraw();
|
|
@@ -10117,13 +10195,27 @@
|
|
|
10117
10195
|
gui.dispatchEvent('path_extend', {target, p});
|
|
10118
10196
|
hit.triggerChangeEvent(); // trigger overlay redraw
|
|
10119
10197
|
}
|
|
10198
|
+
}
|
|
10120
10199
|
|
|
10200
|
+
function replaceDrawnShapes(shapes) {
|
|
10201
|
+
var target = hit.getHitTarget();
|
|
10202
|
+
var records = target.data?.getRecords();
|
|
10203
|
+
var prevLen = target.shapes.length;
|
|
10204
|
+
var newLen = initialShapeCount + shapes.length;
|
|
10205
|
+
var recordCount = records?.length || 0;
|
|
10206
|
+
target.shapes = target.shapes.slice(0, initialShapeCount).concat(shapes);
|
|
10207
|
+
while (records && records.length > newLen) {
|
|
10208
|
+
records.pop();
|
|
10209
|
+
}
|
|
10210
|
+
while (records && records.length < newLen) {
|
|
10211
|
+
appendNewDataRecord(target);
|
|
10212
|
+
}
|
|
10121
10213
|
}
|
|
10122
10214
|
|
|
10123
10215
|
// p: [x, y] source data coordinates
|
|
10124
10216
|
function updatePathEndpoint(p) {
|
|
10125
10217
|
var target = hit.getHitTarget();
|
|
10126
|
-
var i = target.
|
|
10218
|
+
var i = target.gui.displayArcs.getPointCount() - 1;
|
|
10127
10219
|
if (hoverVertexInfo) {
|
|
10128
10220
|
p = hoverVertexInfo.point; // snap to selected point
|
|
10129
10221
|
}
|
|
@@ -10133,8 +10225,8 @@
|
|
|
10133
10225
|
|
|
10134
10226
|
function findPathStartInfo(e) {
|
|
10135
10227
|
var target = hit.getHitTarget();
|
|
10136
|
-
var arcId = target.
|
|
10137
|
-
var data = target.
|
|
10228
|
+
var arcId = target.gui.displayArcs.size() - 1;
|
|
10229
|
+
var data = target.gui.displayArcs.getVertexData();
|
|
10138
10230
|
var i = data.ii[arcId];
|
|
10139
10231
|
var x = data.xx[i];
|
|
10140
10232
|
var y = data.yy[i];
|
|
@@ -10142,7 +10234,7 @@
|
|
|
10142
10234
|
var dist = geom.distance2D(p[0], p[1], x, y);
|
|
10143
10235
|
var pathLen = data.nn[arcId];
|
|
10144
10236
|
var pixelDist = dist / ext.getPixelSize();
|
|
10145
|
-
if (pixelDist > HOVER_THRESHOLD
|
|
10237
|
+
if (pixelDist > HOVER_THRESHOLD || pathLen < 4) {
|
|
10146
10238
|
return null;
|
|
10147
10239
|
}
|
|
10148
10240
|
var point = translateDisplayPoint(target, [x, y]);
|
|
@@ -10156,41 +10248,38 @@
|
|
|
10156
10248
|
//
|
|
10157
10249
|
function findDraggableVertices(e) {
|
|
10158
10250
|
var target = hit.getHitTarget();
|
|
10159
|
-
var shp = target.
|
|
10251
|
+
var shp = target.shapes[e.id];
|
|
10160
10252
|
var p = ext.translatePixelCoords(e.x, e.y);
|
|
10161
|
-
var ids = internal.findNearestVertices(p, shp, target.
|
|
10162
|
-
var p2 = target.
|
|
10253
|
+
var ids = internal.findNearestVertices(p, shp, target.gui.displayArcs);
|
|
10254
|
+
var p2 = target.gui.displayArcs.getVertex2(ids[0]);
|
|
10163
10255
|
var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
|
|
10164
10256
|
var pixelDist = dist / ext.getPixelSize();
|
|
10165
|
-
if (pixelDist > HOVER_THRESHOLD
|
|
10257
|
+
if (pixelDist > HOVER_THRESHOLD) {
|
|
10166
10258
|
return null;
|
|
10167
10259
|
}
|
|
10168
10260
|
var point = getVertexCoords(target, ids[0]); // data coordinates
|
|
10169
10261
|
// find out if the vertex is the endpoint of a single path
|
|
10170
10262
|
// (which could be extended by a newly drawn path)
|
|
10171
10263
|
var extendable = ids.length == 1 &&
|
|
10172
|
-
internal.vertexIsArcEndpoint(ids[0], target.
|
|
10173
|
-
var displayPoint = target.
|
|
10264
|
+
internal.vertexIsArcEndpoint(ids[0], target.gui.displayArcs);
|
|
10265
|
+
var displayPoint = target.gui.displayArcs.getVertex2(ids[0]);
|
|
10174
10266
|
return {target, ids, extendable, point, displayPoint, type: 'vertex'};
|
|
10175
10267
|
}
|
|
10176
10268
|
|
|
10269
|
+
|
|
10177
10270
|
function findInterpolatedPoint(e) {
|
|
10178
10271
|
var target = hit.getHitTarget();
|
|
10179
10272
|
//// vertex insertion not supported with simplification
|
|
10180
10273
|
// if (!target.arcs.isFlat()) return null;
|
|
10181
10274
|
var p = ext.translatePixelCoords(e.x, e.y);
|
|
10182
10275
|
var minDist = Infinity;
|
|
10183
|
-
var shp = target.
|
|
10276
|
+
var shp = target.shapes[e.id];
|
|
10184
10277
|
var closest;
|
|
10185
|
-
internal.forEachSegmentInShape(shp, target.
|
|
10278
|
+
internal.forEachSegmentInShape(shp, target.gui.displayArcs, function(i, j, xx, yy) {
|
|
10186
10279
|
var x1 = xx[i],
|
|
10187
10280
|
y1 = yy[i],
|
|
10188
10281
|
x2 = xx[j],
|
|
10189
10282
|
y2 = yy[j],
|
|
10190
|
-
// switching from midpoint to nearest point to the mouse
|
|
10191
|
-
// cx = (x1 + x2) / 2,
|
|
10192
|
-
// cy = (y1 + y2) / 2,
|
|
10193
|
-
// p2 = [cx, cy],
|
|
10194
10283
|
p2 = internal.findClosestPointOnSeg(p[0], p[1], x1, y1, x2, y2, 0),
|
|
10195
10284
|
dist = geom.distance2D(p2[0], p2[1], p[0], p[1]);
|
|
10196
10285
|
if (dist < minDist) {
|
|
@@ -10203,7 +10292,7 @@
|
|
|
10203
10292
|
}
|
|
10204
10293
|
});
|
|
10205
10294
|
|
|
10206
|
-
if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD
|
|
10295
|
+
if (closest.distance / ext.getPixelSize() > HOVER_THRESHOLD) {
|
|
10207
10296
|
return null;
|
|
10208
10297
|
}
|
|
10209
10298
|
closest.point = translateDisplayPoint(target, closest.displayPoint);
|
|
@@ -10212,49 +10301,39 @@
|
|
|
10212
10301
|
return closest;
|
|
10213
10302
|
}
|
|
10214
10303
|
|
|
10215
|
-
//
|
|
10216
|
-
//
|
|
10217
|
-
function
|
|
10304
|
+
// Try to form polygon shapes from an array of path shapes
|
|
10305
|
+
// shapes: array of all shapes that have been drawn in the current session
|
|
10306
|
+
function convertClosedPaths(shapes) {
|
|
10218
10307
|
var target = hit.getHitTarget();
|
|
10308
|
+
// try to convert paths to polygons
|
|
10309
|
+
// NOTE: added "no_cuts" option to prevent polygons function from modifying
|
|
10310
|
+
// arcs, which would break undo/redo and cause other problems
|
|
10219
10311
|
var tmpLyr = {
|
|
10220
10312
|
geometry_type: 'polyline',
|
|
10221
10313
|
shapes: shapes.concat()
|
|
10222
10314
|
};
|
|
10223
|
-
|
|
10224
|
-
|
|
10225
|
-
|
|
10226
|
-
|
|
10227
|
-
|
|
10228
|
-
|
|
10229
|
-
|
|
10230
|
-
|
|
10231
|
-
|
|
10232
|
-
shapes.forEach(function(shp) {
|
|
10233
|
-
if (isOpenPath(shp)) {
|
|
10234
|
-
shapes2.push(shp);
|
|
10235
|
-
}
|
|
10236
|
-
});
|
|
10237
|
-
return shapes2.concat(outputLyr.shapes);
|
|
10315
|
+
var output = mapshaper.cmd.polygons([tmpLyr], target.gui.source.dataset, {no_cuts: true});
|
|
10316
|
+
var closedShapes = output[0].shapes;
|
|
10317
|
+
|
|
10318
|
+
// find paths that were not convertible to polygons
|
|
10319
|
+
var isOpenPath = getOpenPathTest(closedShapes);
|
|
10320
|
+
var openShapes = shapes.filter(function(shp) { return isOpenPath(shp); });
|
|
10321
|
+
|
|
10322
|
+
// retain both converted polygons and unconverted polylines
|
|
10323
|
+
return openShapes.concat(closedShapes);
|
|
10238
10324
|
}
|
|
10239
10325
|
|
|
10240
10326
|
// Returns a function for testing if a shape is an unclosed path, and doesn't
|
|
10241
10327
|
// overlap with an array of polygon shapes
|
|
10242
|
-
|
|
10243
|
-
|
|
10244
|
-
|
|
10245
|
-
|
|
10246
|
-
if (arcId < 0) arcId = ~arcId;
|
|
10247
|
-
arcs.push(arcId);
|
|
10328
|
+
function getOpenPathTest(polygonShapes) {
|
|
10329
|
+
var polygonArcs = [];
|
|
10330
|
+
internal.forEachArcId(polygonShapes, function(arcId) {
|
|
10331
|
+
polygonArcs.push(internal.absArcId(arcId));
|
|
10248
10332
|
});
|
|
10333
|
+
|
|
10249
10334
|
return function(shp) {
|
|
10250
|
-
// assume that compound
|
|
10251
|
-
|
|
10252
|
-
if (shapeHasOneFwdArc(shp)) {
|
|
10253
|
-
var arcId = shp[0][0];
|
|
10254
|
-
if (arcId < 0) arcId = ~arcId;
|
|
10255
|
-
isOpen = !arcs.includes(arcId);
|
|
10256
|
-
}
|
|
10257
|
-
return isOpen;
|
|
10335
|
+
// assume that any compound shape is a polygon
|
|
10336
|
+
return shapeHasOneFwdArc(shp) && !polygonArcs.includes(shp[0][0]);
|
|
10258
10337
|
};
|
|
10259
10338
|
}
|
|
10260
10339
|
|
|
@@ -10283,8 +10362,7 @@
|
|
|
10283
10362
|
// x, y: pixel coordinates
|
|
10284
10363
|
function addPoint(x, y) {
|
|
10285
10364
|
var p = ext.translatePixelCoords(x, y);
|
|
10286
|
-
var
|
|
10287
|
-
var lyr = target.layer;
|
|
10365
|
+
var lyr = hit.getHitTarget();
|
|
10288
10366
|
var fid = lyr.shapes.length;
|
|
10289
10367
|
var d = appendNewDataRecord(lyr);
|
|
10290
10368
|
if (d) {
|
|
@@ -10293,186 +10371,10 @@
|
|
|
10293
10371
|
lyr.data.getRecords()[fid] = d;
|
|
10294
10372
|
}
|
|
10295
10373
|
lyr.shapes[fid] = [p];
|
|
10296
|
-
updatePointCoords(
|
|
10297
|
-
}
|
|
10298
|
-
|
|
10299
|
-
|
|
10300
|
-
}
|
|
10301
|
-
|
|
10302
|
-
// pointer thresholds for hovering near a vertex or segment midpoint
|
|
10303
|
-
var HOVER_THRESHOLD = 8;
|
|
10304
|
-
var MIDPOINT_THRESHOLD = 11;
|
|
10305
|
-
|
|
10306
|
-
function initVertexDragging(gui, ext, hit) {
|
|
10307
|
-
var insertionPoint;
|
|
10308
|
-
var dragInfo;
|
|
10309
|
-
|
|
10310
|
-
function active() {
|
|
10311
|
-
return gui.interaction.getMode() == 'vertices';
|
|
10312
|
-
}
|
|
10313
|
-
|
|
10314
|
-
function dragging() {
|
|
10315
|
-
return active() && !!dragInfo;
|
|
10316
|
-
}
|
|
10317
|
-
|
|
10318
|
-
function setHoverVertex(id) {
|
|
10319
|
-
var target = hit.getHitTarget();
|
|
10320
|
-
hit.setHoverVertex(target.arcs.getVertex2(id));
|
|
10321
|
-
}
|
|
10322
|
-
|
|
10323
|
-
function clearHoverVertex() {
|
|
10324
|
-
hit.clearHoverVertex();
|
|
10325
|
-
}
|
|
10326
|
-
|
|
10327
|
-
// return data on the nearest vertex (or identical vertices) to the pointer
|
|
10328
|
-
// (if within a distance threshold)
|
|
10329
|
-
//
|
|
10330
|
-
function findDraggableVertices(e) {
|
|
10331
|
-
var target = hit.getHitTarget();
|
|
10332
|
-
var shp = target.layer.shapes[e.id];
|
|
10333
|
-
var p = ext.translatePixelCoords(e.x, e.y);
|
|
10334
|
-
var nearestIds = internal.findNearestVertices(p, shp, target.arcs);
|
|
10335
|
-
var p2 = target.arcs.getVertex2(nearestIds[0]);
|
|
10336
|
-
var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
|
|
10337
|
-
var pixelDist = dist / ext.getPixelSize();
|
|
10338
|
-
if (pixelDist > HOVER_THRESHOLD) {
|
|
10339
|
-
return null;
|
|
10340
|
-
}
|
|
10341
|
-
var points = nearestIds.map(function(i) {
|
|
10342
|
-
return getVertexCoords(target, i); // data coordinates
|
|
10343
|
-
});
|
|
10344
|
-
return {
|
|
10345
|
-
target: target,
|
|
10346
|
-
ids: nearestIds,
|
|
10347
|
-
points: points
|
|
10348
|
-
};
|
|
10374
|
+
updatePointCoords(lyr, fid);
|
|
10349
10375
|
}
|
|
10350
10376
|
|
|
10351
|
-
function findVertexInsertionPoint(e) {
|
|
10352
|
-
var target = hit.getHitTarget();
|
|
10353
|
-
//// vertex insertion not supported with simplification
|
|
10354
|
-
// if (!target.arcs.isFlat()) return null;
|
|
10355
|
-
var p = ext.translatePixelCoords(e.x, e.y);
|
|
10356
|
-
var midpoint = findNearestMidpoint(p, e.id, target);
|
|
10357
|
-
if (!midpoint ||
|
|
10358
|
-
midpoint.distance / ext.getPixelSize() > MIDPOINT_THRESHOLD) return null;
|
|
10359
|
-
return midpoint;
|
|
10360
|
-
}
|
|
10361
|
-
|
|
10362
|
-
hit.on('dragstart', function(e) {
|
|
10363
|
-
if (!active()) return;
|
|
10364
|
-
if (insertionPoint) {
|
|
10365
|
-
var target = hit.getHitTarget();
|
|
10366
|
-
insertVertex$1(target, insertionPoint.i, insertionPoint.point);
|
|
10367
|
-
dragInfo = {
|
|
10368
|
-
target: target,
|
|
10369
|
-
insertion: true,
|
|
10370
|
-
ids: [insertionPoint.i],
|
|
10371
|
-
points: [insertionPoint.point]
|
|
10372
|
-
};
|
|
10373
|
-
insertionPoint = null;
|
|
10374
|
-
} else {
|
|
10375
|
-
dragInfo = findDraggableVertices(e);
|
|
10376
|
-
}
|
|
10377
|
-
if (dragInfo) {
|
|
10378
|
-
setHoverVertex(dragInfo.ids[0]);
|
|
10379
|
-
}
|
|
10380
|
-
});
|
|
10381
|
-
|
|
10382
|
-
hit.on('drag', function(e) {
|
|
10383
|
-
if (!dragging()) return;
|
|
10384
|
-
var target = hit.getHitTarget();
|
|
10385
|
-
var p = ext.translatePixelCoords(e.x, e.y);
|
|
10386
|
-
if (gui.keyboard.shiftIsPressed()) {
|
|
10387
|
-
internal.snapPointToArcEndpoint(p, dragInfo.ids, target.arcs);
|
|
10388
|
-
}
|
|
10389
|
-
internal.snapVerticesToPoint(dragInfo.ids, p, target.arcs);
|
|
10390
|
-
setHoverVertex(dragInfo.ids[0]);
|
|
10391
|
-
// redrawing the whole map updates the data layer as well as the overlay layer
|
|
10392
|
-
// gui.dispatchEvent('map-needs-refresh');
|
|
10393
|
-
});
|
|
10394
|
-
|
|
10395
|
-
hit.on('dragend', function(e) {
|
|
10396
|
-
if (!dragging()) return;
|
|
10397
|
-
// kludge to get dataset to recalculate internal bounding boxes
|
|
10398
|
-
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
10399
|
-
clearHoverVertex();
|
|
10400
|
-
updateVertexCoords(dragInfo.target, dragInfo.ids);
|
|
10401
|
-
gui.dispatchEvent('vertex_dragend', dragInfo);
|
|
10402
|
-
gui.dispatchEvent('map-needs-refresh');
|
|
10403
|
-
dragInfo = null;
|
|
10404
|
-
});
|
|
10405
|
-
|
|
10406
|
-
hit.on('dblclick', function(e) {
|
|
10407
|
-
if (!active()) return;
|
|
10408
|
-
var info = findDraggableVertices(e); // same selection criteria as for dragging
|
|
10409
|
-
if (!info) return;
|
|
10410
|
-
var target = hit.getHitTarget();
|
|
10411
|
-
var vId = info.ids[0];
|
|
10412
|
-
if (internal.vertexIsArcStart(vId, target.arcs) ||
|
|
10413
|
-
internal.vertexIsArcEnd(vId, target.arcs)) {
|
|
10414
|
-
// TODO: support removing arc endpoints
|
|
10415
|
-
return;
|
|
10416
|
-
}
|
|
10417
|
-
gui.dispatchEvent('vertex_delete', {
|
|
10418
|
-
target: target,
|
|
10419
|
-
vertex_id: vId
|
|
10420
|
-
});
|
|
10421
|
-
deleteVertex$1(target, vId);
|
|
10422
|
-
clearHoverVertex();
|
|
10423
|
-
gui.dispatchEvent('map-needs-refresh');
|
|
10424
|
-
});
|
|
10425
|
-
|
|
10426
|
-
// highlight hit vertex in path edit mode
|
|
10427
|
-
hit.on('hover', function(e) {
|
|
10428
|
-
insertionPoint = null;
|
|
10429
|
-
if (!active() || dragging()) return; // no hover effect while dragging
|
|
10430
|
-
var info = findDraggableVertices(e);
|
|
10431
|
-
if (info) {
|
|
10432
|
-
// hovering near a vertex: highlight the vertex
|
|
10433
|
-
setHoverVertex(info.ids[0]);
|
|
10434
|
-
return;
|
|
10435
|
-
}
|
|
10436
|
-
// if hovering near a segment midpoint: show the midpoint and save midpoint info
|
|
10437
|
-
insertionPoint = findVertexInsertionPoint(e);
|
|
10438
|
-
if (insertionPoint) {
|
|
10439
|
-
hit.setHoverVertex(insertionPoint.displayPoint);
|
|
10440
|
-
} else {
|
|
10441
|
-
// pointer is not over a vertex: clear any hover effect
|
|
10442
|
-
clearHoverVertex();
|
|
10443
|
-
}
|
|
10444
|
-
}, null, 100);
|
|
10445
|
-
}
|
|
10446
|
-
|
|
10447
10377
|
|
|
10448
|
-
// Given a location @p (e.g. corresponding to the mouse pointer location),
|
|
10449
|
-
// find the midpoint of two vertices on @shp suitable for inserting a new vertex
|
|
10450
|
-
function findNearestMidpoint(p, fid, target) {
|
|
10451
|
-
var arcs = target.arcs;
|
|
10452
|
-
var shp = target.layer.shapes[fid];
|
|
10453
|
-
var minDist = Infinity, v;
|
|
10454
|
-
internal.forEachSegmentInShape(shp, arcs, function(i, j, xx, yy) {
|
|
10455
|
-
var x1 = xx[i],
|
|
10456
|
-
y1 = yy[i],
|
|
10457
|
-
x2 = xx[j],
|
|
10458
|
-
y2 = yy[j],
|
|
10459
|
-
cx = (x1 + x2) / 2,
|
|
10460
|
-
cy = (y1 + y2) / 2,
|
|
10461
|
-
midpoint = [cx, cy],
|
|
10462
|
-
dist = geom.distance2D(cx, cy, p[0], p[1]);
|
|
10463
|
-
if (dist < minDist) {
|
|
10464
|
-
minDist = dist;
|
|
10465
|
-
v = {
|
|
10466
|
-
i: (i < j ? i : j) + 1, // insertion point
|
|
10467
|
-
segment: [i, j],
|
|
10468
|
-
segmentLen: geom.distance2D(x1, y1, x2, y2),
|
|
10469
|
-
displayPoint: midpoint,
|
|
10470
|
-
point: translateDisplayPoint(target, midpoint),
|
|
10471
|
-
distance: dist
|
|
10472
|
-
};
|
|
10473
|
-
}
|
|
10474
|
-
});
|
|
10475
|
-
return v || null;
|
|
10476
10378
|
}
|
|
10477
10379
|
|
|
10478
10380
|
function initInteractiveEditing(gui, ext, hit) {
|
|
@@ -10480,7 +10382,6 @@
|
|
|
10480
10382
|
initPointDragging(gui, ext, hit);
|
|
10481
10383
|
initPointDrawing(gui, ext, hit);
|
|
10482
10384
|
initLineEditing(gui, ext, hit);
|
|
10483
|
-
initVertexDragging(gui, ext, hit);
|
|
10484
10385
|
}
|
|
10485
10386
|
|
|
10486
10387
|
function MapExtent(_position) {
|
|
@@ -10854,47 +10755,46 @@
|
|
|
10854
10755
|
}
|
|
10855
10756
|
|
|
10856
10757
|
// TODO: consider moving this upstream
|
|
10857
|
-
function getArcsForRendering(
|
|
10858
|
-
var dataset =
|
|
10758
|
+
function getArcsForRendering(lyr, ext) {
|
|
10759
|
+
var dataset = lyr.gui.source.dataset;
|
|
10859
10760
|
var sourceArcs = dataset.arcs;
|
|
10860
|
-
if (
|
|
10761
|
+
if (lyr.gui.geographic && dataset.gui?.displayArcs) {
|
|
10861
10762
|
return dataset.gui.displayArcs.getScaledArcs(ext);
|
|
10862
10763
|
}
|
|
10863
|
-
return
|
|
10764
|
+
return lyr.gui.displayArcs;
|
|
10864
10765
|
}
|
|
10865
10766
|
|
|
10866
|
-
function drawOutlineLayerToCanvas(
|
|
10767
|
+
function drawOutlineLayerToCanvas(lyr, canv, ext) {
|
|
10867
10768
|
var arcs;
|
|
10868
|
-
var style =
|
|
10769
|
+
var style = lyr.gui.style;
|
|
10770
|
+
var arcCounts = lyr.gui.arcCounts;
|
|
10869
10771
|
var darkStyle = {strokeWidth: style.strokeWidth, strokeColor: style.strokeColors[1]},
|
|
10870
10772
|
lightStyle = {strokeWidth: style.strokeWidth, strokeColor: style.strokeColors[0]};
|
|
10871
10773
|
var filter;
|
|
10872
|
-
if (internal.layerHasPaths(
|
|
10873
|
-
if (!
|
|
10874
|
-
|
|
10875
|
-
internal.countArcsInShapes(
|
|
10774
|
+
if (internal.layerHasPaths(lyr.gui.displayLayer)) {
|
|
10775
|
+
if (!arcCounts) {
|
|
10776
|
+
arcCounts = lyr.gui.arcCounts = new Uint8Array(lyr.gui.displayArcs.size());
|
|
10777
|
+
internal.countArcsInShapes(lyr.gui.displayLayer.shapes, arcCounts);
|
|
10876
10778
|
}
|
|
10877
|
-
|
|
10878
|
-
|
|
10879
|
-
|
|
10880
|
-
|
|
10881
|
-
|
|
10882
|
-
|
|
10883
|
-
|
|
10884
|
-
|
|
10885
|
-
canv.drawArcs(arcs, darkStyle, filter);
|
|
10886
|
-
}
|
|
10779
|
+
arcs = getArcsForRendering(lyr, ext);
|
|
10780
|
+
if (lightStyle.strokeColor) {
|
|
10781
|
+
filter = getArcFilter(arcs, ext, false, arcCounts);
|
|
10782
|
+
canv.drawArcs(arcs, lightStyle, filter);
|
|
10783
|
+
}
|
|
10784
|
+
if (darkStyle.strokeColor && lyr.gui.displayLayer.geometry_type != 'point') {
|
|
10785
|
+
filter = getArcFilter(arcs, ext, true, arcCounts);
|
|
10786
|
+
canv.drawArcs(arcs, darkStyle, filter);
|
|
10887
10787
|
}
|
|
10888
10788
|
}
|
|
10889
|
-
if (
|
|
10890
|
-
canv.drawSquareDots(
|
|
10789
|
+
if (lyr.gui.displayLayer.geometry_type == 'point') {
|
|
10790
|
+
canv.drawSquareDots(lyr.gui.displayLayer.shapes, style);
|
|
10891
10791
|
}
|
|
10892
10792
|
}
|
|
10893
10793
|
|
|
10894
|
-
function drawStyledLayerToCanvas(
|
|
10794
|
+
function drawStyledLayerToCanvas(lyr, canv, ext) {
|
|
10895
10795
|
// TODO: add filter for out-of-view shapes
|
|
10896
|
-
var style =
|
|
10897
|
-
var layer =
|
|
10796
|
+
var style = lyr.gui.style;
|
|
10797
|
+
var layer = lyr.gui.displayLayer;
|
|
10898
10798
|
var arcs, filter;
|
|
10899
10799
|
if (layer.geometry_type == 'point') {
|
|
10900
10800
|
if (style.type == 'styled') {
|
|
@@ -10903,7 +10803,7 @@
|
|
|
10903
10803
|
canv.drawSquareDots(layer.shapes, style);
|
|
10904
10804
|
}
|
|
10905
10805
|
} else {
|
|
10906
|
-
arcs = getArcsForRendering(
|
|
10806
|
+
arcs = getArcsForRendering(lyr, ext);
|
|
10907
10807
|
filter = getShapeFilter(arcs, ext);
|
|
10908
10808
|
canv.drawStyledPaths(layer.shapes, arcs, style, filter);
|
|
10909
10809
|
if (style.vertices) {
|
|
@@ -11497,12 +11397,12 @@
|
|
|
11497
11397
|
}
|
|
11498
11398
|
};
|
|
11499
11399
|
|
|
11500
|
-
el.reposition = function(
|
|
11400
|
+
el.reposition = function(lyr, type) {
|
|
11501
11401
|
resize(ext);
|
|
11502
|
-
reposition(
|
|
11402
|
+
reposition(lyr, type, ext);
|
|
11503
11403
|
};
|
|
11504
11404
|
|
|
11505
|
-
el.drawLayer = function(
|
|
11405
|
+
el.drawLayer = function(lyr, type) {
|
|
11506
11406
|
var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
11507
11407
|
var html = '';
|
|
11508
11408
|
// generate a unique id so layer can be identified when symbols are repositioned
|
|
@@ -11510,24 +11410,25 @@
|
|
|
11510
11410
|
var id = utils$1.getUniqueName();
|
|
11511
11411
|
var classNames = [id, 'mapshaper-svg-layer', 'mapshaper-' + type + '-layer'];
|
|
11512
11412
|
g.setAttribute('class', classNames.join(' '));
|
|
11513
|
-
|
|
11413
|
+
lyr.gui.svg_id = id;
|
|
11414
|
+
lyr.gui.svg_container = g;
|
|
11514
11415
|
resize(ext);
|
|
11515
11416
|
if (type == 'label' || type == 'symbol') {
|
|
11516
|
-
html = renderSymbols(
|
|
11417
|
+
html = renderSymbols(lyr.gui.displayLayer, ext);
|
|
11517
11418
|
} else if (type == 'furniture') {
|
|
11518
|
-
html = renderFurniture(
|
|
11419
|
+
html = renderFurniture(lyr.gui.displayLayer, ext);
|
|
11519
11420
|
}
|
|
11520
11421
|
g.innerHTML = html;
|
|
11521
11422
|
svg.append(g);
|
|
11522
11423
|
|
|
11523
11424
|
// prevent svg hit detection on inactive layers
|
|
11524
|
-
if (!
|
|
11425
|
+
if (!lyr.active) {
|
|
11525
11426
|
g.style.pointerEvents = 'none';
|
|
11526
11427
|
}
|
|
11527
11428
|
};
|
|
11528
11429
|
|
|
11529
|
-
function reposition(
|
|
11530
|
-
var container = el.findChild('.' +
|
|
11430
|
+
function reposition(lyr, type, ext) {
|
|
11431
|
+
var container = el.findChild('.' + lyr.gui.svg_id);
|
|
11531
11432
|
if (!container || !container.node()) {
|
|
11532
11433
|
console.error('[reposition] missing SVG container');
|
|
11533
11434
|
return;
|
|
@@ -11535,9 +11436,9 @@
|
|
|
11535
11436
|
var elements;
|
|
11536
11437
|
if (type == 'symbol') {
|
|
11537
11438
|
elements = El.findAll('.mapshaper-svg-symbol', container.node());
|
|
11538
|
-
repositionSymbols(elements,
|
|
11439
|
+
repositionSymbols(elements, lyr.gui.displayLayer, ext);
|
|
11539
11440
|
} else if (type == 'furniture') {
|
|
11540
|
-
repositionFurniture(container.node(),
|
|
11441
|
+
repositionFurniture(container.node(), lyr.gui.displayLayer, ext);
|
|
11541
11442
|
} else {
|
|
11542
11443
|
// container.getElementsByTagName('text')
|
|
11543
11444
|
error('Unsupported symbol type:', type);
|
|
@@ -11571,7 +11472,7 @@
|
|
|
11571
11472
|
_svg.clear();
|
|
11572
11473
|
}
|
|
11573
11474
|
layers.forEach(function(lyr) {
|
|
11574
|
-
var isSvgLayer = internal.layerHasSvgSymbols(lyr
|
|
11475
|
+
var isSvgLayer = internal.layerHasSvgSymbols(lyr) || internal.layerHasLabels(lyr);
|
|
11575
11476
|
if (isSvgLayer && !needSvgRedraw) {
|
|
11576
11477
|
_svg.reposition(lyr, 'symbol');
|
|
11577
11478
|
} else if (isSvgLayer) {
|
|
@@ -11620,7 +11521,7 @@
|
|
|
11620
11521
|
|
|
11621
11522
|
function drawCanvasLayer(lyr, canv) {
|
|
11622
11523
|
if (!lyr) return;
|
|
11623
|
-
if (lyr.style.type == 'outline') {
|
|
11524
|
+
if (lyr.gui.style.type == 'outline') {
|
|
11624
11525
|
drawOutlineLayerToCanvas(lyr, canv, ext);
|
|
11625
11526
|
} else {
|
|
11626
11527
|
drawStyledLayerToCanvas(lyr, canv, ext);
|
|
@@ -11688,8 +11589,8 @@
|
|
|
11688
11589
|
gui.on('interaction_mode_change', function(e) {
|
|
11689
11590
|
if (e.mode === 'box') {
|
|
11690
11591
|
gui.enterMode('box_tool');
|
|
11691
|
-
} else if (
|
|
11692
|
-
|
|
11592
|
+
} else if (_on) {
|
|
11593
|
+
turnOff();
|
|
11693
11594
|
}
|
|
11694
11595
|
});
|
|
11695
11596
|
|
|
@@ -11792,8 +11693,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11792
11693
|
gui.on('interaction_mode_change', function(e) {
|
|
11793
11694
|
if (e.mode === 'rectangles') {
|
|
11794
11695
|
gui.enterMode('rectangle_tool');
|
|
11795
|
-
} else if (
|
|
11796
|
-
|
|
11696
|
+
} else if (_on) {
|
|
11697
|
+
turnOff();
|
|
11797
11698
|
}
|
|
11798
11699
|
});
|
|
11799
11700
|
|
|
@@ -11803,8 +11704,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11803
11704
|
var id = e.id;
|
|
11804
11705
|
if (e.id > -1 && e.pinned) {
|
|
11805
11706
|
var target = hit.getHitTarget();
|
|
11806
|
-
var path = target.
|
|
11807
|
-
var bbox = target.
|
|
11707
|
+
var path = target.shapes[e.id][0];
|
|
11708
|
+
var bbox = target.gui.displayArcs.getSimpleShapeBounds(path).toArray();
|
|
11808
11709
|
box.setDataCoords(bbox);
|
|
11809
11710
|
dragInfo = {
|
|
11810
11711
|
id: e.id,
|
|
@@ -11812,7 +11713,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11812
11713
|
ids: [],
|
|
11813
11714
|
points: []
|
|
11814
11715
|
};
|
|
11815
|
-
var iter = target.
|
|
11716
|
+
var iter = target.gui.displayArcs.getShapeIter(path);
|
|
11816
11717
|
while (iter.hasNext()) {
|
|
11817
11718
|
dragInfo.points.push([iter.x, iter.y]);
|
|
11818
11719
|
dragInfo.ids.push(iter._arc.i);
|
|
@@ -11911,8 +11812,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11911
11812
|
};
|
|
11912
11813
|
}
|
|
11913
11814
|
|
|
11914
|
-
function getDisplayLayerForTable(
|
|
11915
|
-
var
|
|
11815
|
+
function getDisplayLayerForTable(tableArg) {
|
|
11816
|
+
var table = tableArg || new internal.DataTable(0),
|
|
11817
|
+
n = table.size(),
|
|
11916
11818
|
cellWidth = 12,
|
|
11917
11819
|
cellHeight = 5,
|
|
11918
11820
|
gutter = 6,
|
|
@@ -11970,54 +11872,45 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
11970
11872
|
};
|
|
11971
11873
|
}
|
|
11972
11874
|
|
|
11875
|
+
// lyr: a map layer with gui property
|
|
11973
11876
|
// displayCRS: CRS to use for display, or null (which clears any current display CRS)
|
|
11974
|
-
function
|
|
11975
|
-
var crsInfo = getDatasetCrsInfo(lyr.source.dataset);
|
|
11976
|
-
var sourceCRS = crsInfo.crs;
|
|
11977
|
-
|
|
11978
|
-
//if (!lyr.geographic || !sourceCRS) {
|
|
11979
|
-
// let getDisplayLayer() handle case of unprojectable source
|
|
11980
|
-
if (!lyr.geographic) {
|
|
11877
|
+
function projectLayerForDisplay(lyr, displayCRS) {
|
|
11878
|
+
var crsInfo = getDatasetCrsInfo(lyr.gui.source.dataset);
|
|
11879
|
+
var sourceCRS = crsInfo.crs || null; // let enhanceLayerForDisplay() handle null case
|
|
11880
|
+
if (!lyr.gui.geographic) {
|
|
11981
11881
|
return;
|
|
11982
11882
|
}
|
|
11983
|
-
if (lyr.dynamic_crs && internal.crsAreEqual(sourceCRS, lyr.dynamic_crs)) {
|
|
11883
|
+
if (lyr.gui.dynamic_crs && internal.crsAreEqual(sourceCRS, lyr.gui.dynamic_crs)) {
|
|
11984
11884
|
return;
|
|
11985
11885
|
}
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
lyr.dynamic_crs = lyr2.dynamic_crs;
|
|
11989
|
-
lyr.layer = lyr2.layer;
|
|
11990
|
-
|
|
11991
|
-
if (lyr.style && lyr.style.ids) {
|
|
11886
|
+
enhanceLayerForDisplay(lyr, lyr.gui.source.dataset, {crs: displayCRS});
|
|
11887
|
+
if (lyr.gui.style?.ids) {
|
|
11992
11888
|
// re-apply layer filter
|
|
11993
|
-
lyr.
|
|
11889
|
+
lyr.gui.displayLayer = filterLayerByIds(lyr.gui.displayLayer, lyr.gui.style.ids);
|
|
11994
11890
|
}
|
|
11995
|
-
lyr.invertPoint = lyr2.invertPoint;
|
|
11996
|
-
lyr.projectPoint = lyr2.projectPoint;
|
|
11997
|
-
lyr.bounds = lyr2.bounds;
|
|
11998
|
-
lyr.arcs = lyr2.arcs;
|
|
11999
11891
|
}
|
|
12000
11892
|
|
|
12001
11893
|
|
|
12002
|
-
//
|
|
12003
|
-
function
|
|
12004
|
-
var
|
|
12005
|
-
|
|
12006
|
-
|
|
12007
|
-
|
|
11894
|
+
// Supplement a layer with information needed for rendering
|
|
11895
|
+
function enhanceLayerForDisplay(layer, dataset, opts) {
|
|
11896
|
+
var gui = {
|
|
11897
|
+
empty: internal.getFeatureCount(layer) === 0,
|
|
11898
|
+
geographic: false,
|
|
11899
|
+
displayArcs: null,
|
|
11900
|
+
displayLayer: null,
|
|
11901
|
+
source: {dataset},
|
|
11902
|
+
bounds: null,
|
|
12008
11903
|
style: null,
|
|
11904
|
+
dynamic_crs: null,
|
|
12009
11905
|
invertPoint: null,
|
|
12010
|
-
projectPoint: null
|
|
12011
|
-
source: {
|
|
12012
|
-
layer: layer,
|
|
12013
|
-
dataset: dataset
|
|
12014
|
-
},
|
|
12015
|
-
empty: internal.getFeatureCount(layer) === 0
|
|
11906
|
+
projectPoint: null
|
|
12016
11907
|
};
|
|
12017
11908
|
|
|
12018
11909
|
var displayCRS = opts.crs || null;
|
|
12019
|
-
// display arcs may have been generated when another layer in the dataset
|
|
12020
|
-
|
|
11910
|
+
// display arcs may have been generated when another layer in the dataset
|
|
11911
|
+
// was converted for display... re-use if available
|
|
11912
|
+
var displayArcs = dataset.gui?.displayArcs;
|
|
11913
|
+
var unprojectable = false;
|
|
12021
11914
|
var sourceCRS;
|
|
12022
11915
|
var emptyArcs;
|
|
12023
11916
|
|
|
@@ -12025,8 +11918,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12025
11918
|
var crsInfo = getDatasetCrsInfo(dataset);
|
|
12026
11919
|
if (crsInfo.error) {
|
|
12027
11920
|
// unprojectable dataset -- return empty layer
|
|
12028
|
-
|
|
12029
|
-
obj.geographic = true;
|
|
11921
|
+
gui.unprojectable = true;
|
|
12030
11922
|
} else {
|
|
12031
11923
|
sourceCRS = crsInfo.crs;
|
|
12032
11924
|
}
|
|
@@ -12035,7 +11927,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12035
11927
|
// Assume that dataset.displayArcs is in the display CRS
|
|
12036
11928
|
// (it must be deleted upstream if reprojection is needed)
|
|
12037
11929
|
// if (!obj.empty && dataset.arcs && !displayArcs) {
|
|
12038
|
-
if (dataset.arcs && !displayArcs) {
|
|
11930
|
+
if (dataset.arcs && !displayArcs && !gui.unprojectable) {
|
|
12039
11931
|
// project arcs, if needed
|
|
12040
11932
|
if (needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
12041
11933
|
displayArcs = projectArcsForDisplay(dataset.arcs, sourceCRS, displayCRS);
|
|
@@ -12049,46 +11941,42 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12049
11941
|
}
|
|
12050
11942
|
|
|
12051
11943
|
if (internal.layerHasFurniture(layer)) {
|
|
12052
|
-
obj.layer = layer;
|
|
12053
|
-
obj.tabular = true;
|
|
12054
11944
|
// TODO: consider how to render furniture in GUI
|
|
12055
|
-
// obj.furniture = true;
|
|
12056
|
-
// obj.furniture_type = internal.getFurnitureLayerType(layer);
|
|
12057
11945
|
// treating furniture layers (other than frame) as tabular for now,
|
|
12058
11946
|
// so there is something to show if they are selected
|
|
12059
|
-
// obj.tabular = obj.furniture_type != 'frame';
|
|
12060
|
-
} else if (layer.geometry_type) {
|
|
12061
|
-
obj.geographic = true;
|
|
12062
|
-
obj.layer = layer;
|
|
12063
|
-
obj.arcs = displayArcs;
|
|
12064
|
-
} else if (!obj.empty) {
|
|
12065
|
-
obj.tabular = true;
|
|
12066
|
-
} else {
|
|
12067
|
-
obj.layer = {shapes: []}; // ideally we should avoid empty layers
|
|
12068
11947
|
}
|
|
12069
11948
|
|
|
12070
|
-
if (
|
|
12071
|
-
|
|
11949
|
+
if (gui.unprojectable) {
|
|
11950
|
+
gui.displayLayer = {shapes: []}; // TODO: improve
|
|
11951
|
+
} else if (layer.geometry_type) {
|
|
11952
|
+
gui.geographic = true;
|
|
11953
|
+
gui.displayLayer = layer;
|
|
11954
|
+
gui.displayArcs = displayArcs;
|
|
11955
|
+
} else {
|
|
11956
|
+
var table = getDisplayLayerForTable(layer.data);
|
|
11957
|
+
gui.tabular = true;
|
|
11958
|
+
gui.displayLayer = table.layer;
|
|
11959
|
+
gui.displayArcs = table.arcs;
|
|
12072
11960
|
}
|
|
12073
11961
|
|
|
12074
11962
|
// dynamic reprojection (arcs were already reprojected above)
|
|
12075
|
-
if (
|
|
12076
|
-
|
|
12077
|
-
|
|
12078
|
-
|
|
11963
|
+
if (gui.geographic && needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
11964
|
+
gui.dynamic_crs = displayCRS;
|
|
11965
|
+
gui.invertPoint = internal.getProjTransform2(displayCRS, sourceCRS);
|
|
11966
|
+
gui.projectPoint = internal.getProjTransform2(sourceCRS, displayCRS);
|
|
12079
11967
|
if (internal.layerHasPoints(layer)) {
|
|
12080
|
-
|
|
11968
|
+
gui.displayLayer = projectPointsForDisplay(layer, sourceCRS, displayCRS);
|
|
12081
11969
|
} else if (internal.layerHasPaths(layer)) {
|
|
12082
11970
|
emptyArcs = findEmptyArcs(displayArcs);
|
|
12083
11971
|
if (emptyArcs.length > 0) {
|
|
12084
11972
|
// Don't try to draw paths containing coordinates that failed to project
|
|
12085
|
-
|
|
11973
|
+
gui.displayLayer = internal.filterPathLayerByArcIds(gui.displayLayer, emptyArcs);
|
|
12086
11974
|
}
|
|
12087
11975
|
}
|
|
12088
11976
|
}
|
|
12089
11977
|
|
|
12090
|
-
|
|
12091
|
-
|
|
11978
|
+
gui.bounds = getDisplayBounds(gui.displayLayer, gui.displayArcs);
|
|
11979
|
+
layer.gui = gui;
|
|
12092
11980
|
}
|
|
12093
11981
|
|
|
12094
11982
|
|
|
@@ -12402,13 +12290,19 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12402
12290
|
|
|
12403
12291
|
model.on('update', onUpdate);
|
|
12404
12292
|
|
|
12293
|
+
document.addEventListener('visibilitychange', function(e) {
|
|
12294
|
+
// refresh map when browser tab is re-activated (Chrome on mac has been
|
|
12295
|
+
// blanking the canvas after several other tabs are visited)
|
|
12296
|
+
if (document.visibilityState == 'visible') drawLayers();
|
|
12297
|
+
});
|
|
12405
12298
|
|
|
12406
12299
|
// Update display of segment intersections
|
|
12407
12300
|
this.setIntersectionLayer = function(lyr, dataset) {
|
|
12408
12301
|
if (lyr == _intersectionLyr) return; // no change
|
|
12409
12302
|
if (lyr) {
|
|
12410
|
-
|
|
12411
|
-
_intersectionLyr
|
|
12303
|
+
enhanceLayerForDisplay(lyr, dataset, getDisplayOptions());
|
|
12304
|
+
_intersectionLyr = lyr;
|
|
12305
|
+
_intersectionLyr.gui.style = getIntersectionStyle(_intersectionLyr.gui.displayLayer, getGlobalStyleOptions());
|
|
12412
12306
|
} else {
|
|
12413
12307
|
_intersectionLyr = null;
|
|
12414
12308
|
}
|
|
@@ -12437,9 +12331,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12437
12331
|
};
|
|
12438
12332
|
|
|
12439
12333
|
this.getDisplayCRS = function() {
|
|
12440
|
-
if (!_activeLyr || !_activeLyr.geographic) return null;
|
|
12441
|
-
if (_activeLyr.dynamic_crs) return _activeLyr.dynamic_crs;
|
|
12442
|
-
var info = getDatasetCrsInfo(_activeLyr.source.dataset);
|
|
12334
|
+
if (!_activeLyr || !_activeLyr.gui.geographic) return null;
|
|
12335
|
+
if (_activeLyr.gui.dynamic_crs) return _activeLyr.gui.dynamic_crs;
|
|
12336
|
+
var info = getDatasetCrsInfo(_activeLyr.gui.source.dataset);
|
|
12443
12337
|
return info.crs || null;
|
|
12444
12338
|
};
|
|
12445
12339
|
|
|
@@ -12478,7 +12372,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12478
12372
|
|
|
12479
12373
|
// Reproject all visible map layers
|
|
12480
12374
|
getContentLayers().forEach(function(lyr) {
|
|
12481
|
-
|
|
12375
|
+
projectLayerForDisplay(lyr, newCRS);
|
|
12482
12376
|
});
|
|
12483
12377
|
|
|
12484
12378
|
// kludge to make sure all layers have styles
|
|
@@ -12503,7 +12397,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12503
12397
|
var prevLyr = _activeLyr || null;
|
|
12504
12398
|
var fullBounds;
|
|
12505
12399
|
var needReset;
|
|
12506
|
-
|
|
12507
12400
|
if (!prevLyr) {
|
|
12508
12401
|
initMap(); // first call
|
|
12509
12402
|
}
|
|
@@ -12529,8 +12422,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12529
12422
|
return;
|
|
12530
12423
|
}
|
|
12531
12424
|
|
|
12532
|
-
|
|
12533
|
-
_activeLyr
|
|
12425
|
+
enhanceLayerForDisplay(e.layer, e.dataset, getDisplayOptions());
|
|
12426
|
+
_activeLyr = e.layer;
|
|
12427
|
+
_activeLyr.gui.style = getActiveLayerStyle(_activeLyr.gui.displayLayer, getGlobalStyleOptions());
|
|
12534
12428
|
_activeLyr.active = true;
|
|
12535
12429
|
|
|
12536
12430
|
if (popupCanStayOpen(e.flags)) {
|
|
@@ -12544,7 +12438,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12544
12438
|
updateVisibleMapLayers();
|
|
12545
12439
|
fullBounds = calcFullBounds();
|
|
12546
12440
|
|
|
12547
|
-
if (!prevLyr || prevLyr.tabular || _activeLyr.tabular) {
|
|
12441
|
+
if (!prevLyr || prevLyr.gui.tabular || _activeLyr.gui.tabular) {
|
|
12548
12442
|
needReset = true;
|
|
12549
12443
|
} else {
|
|
12550
12444
|
needReset = mapNeedsReset(fullBounds, _ext.getFullBounds(), _ext.getBounds(), e.flags);
|
|
@@ -12587,12 +12481,11 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12587
12481
|
}
|
|
12588
12482
|
|
|
12589
12483
|
function updateOverlayLayer(e) {
|
|
12590
|
-
var style = getOverlayStyle(_activeLyr.
|
|
12484
|
+
var style = getOverlayStyle(_activeLyr.gui.displayLayer, e, getGlobalStyleOptions());
|
|
12591
12485
|
if (style) {
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
}, _activeLyr);
|
|
12486
|
+
var displayLayer = filterLayerByIds(_activeLyr.gui.displayLayer, style.ids);
|
|
12487
|
+
var gui = Object.assign({}, _activeLyr.gui, {style, displayLayer});
|
|
12488
|
+
_overlayLyr = utils$1.defaults({gui}, _activeLyr);
|
|
12596
12489
|
} else {
|
|
12597
12490
|
_overlayLyr = null;
|
|
12598
12491
|
}
|
|
@@ -12623,7 +12516,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12623
12516
|
var b = new Bounds();
|
|
12624
12517
|
var layers = getContentLayers();
|
|
12625
12518
|
layers.forEach(function(lyr) {
|
|
12626
|
-
b.mergeBounds(lyr.bounds);
|
|
12519
|
+
b.mergeBounds(lyr.gui.bounds);
|
|
12627
12520
|
});
|
|
12628
12521
|
|
|
12629
12522
|
if (!b.hasBounds()) {
|
|
@@ -12646,7 +12539,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12646
12539
|
var widthPx = _ext.width();
|
|
12647
12540
|
var marginPct = widthPx < 700 && 3.5 || widthPx < 800 && 3 || 2.5;
|
|
12648
12541
|
if (isTableView()) {
|
|
12649
|
-
var n = internal.getFeatureCount(_activeLyr
|
|
12542
|
+
var n = internal.getFeatureCount(_activeLyr);
|
|
12650
12543
|
marginPct = n < 5 && 20 || n < 100 && 10 || 4;
|
|
12651
12544
|
}
|
|
12652
12545
|
b.scale(1 + marginPct / 100 * 2);
|
|
@@ -12658,7 +12551,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12658
12551
|
}
|
|
12659
12552
|
|
|
12660
12553
|
function isActiveLayer(lyr) {
|
|
12661
|
-
return _activeLyr && lyr == _activeLyr
|
|
12554
|
+
return _activeLyr && lyr == _activeLyr || false;
|
|
12662
12555
|
}
|
|
12663
12556
|
|
|
12664
12557
|
function isVisibleLayer(lyr) {
|
|
@@ -12666,12 +12559,12 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12666
12559
|
}
|
|
12667
12560
|
|
|
12668
12561
|
function isTableView() {
|
|
12669
|
-
return !!_activeLyr.tabular;
|
|
12562
|
+
return !!_activeLyr.gui.tabular;
|
|
12670
12563
|
}
|
|
12671
12564
|
|
|
12672
12565
|
function findFrameLayer() {
|
|
12673
12566
|
return getVisibleMapLayers().find(function(lyr) {
|
|
12674
|
-
return internal.isFrameLayer(lyr.
|
|
12567
|
+
return internal.isFrameLayer(lyr.gui.displayLayer, lyr.gui.displayArcs);
|
|
12675
12568
|
});
|
|
12676
12569
|
}
|
|
12677
12570
|
|
|
@@ -12682,10 +12575,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12682
12575
|
|
|
12683
12576
|
function getFrameData() {
|
|
12684
12577
|
var lyr = findFrameLayer();
|
|
12685
|
-
return lyr && internal.getFrameLayerData(lyr
|
|
12578
|
+
return lyr && internal.getFrameLayerData(lyr, lyr.gui.displayArcs) || null;
|
|
12686
12579
|
}
|
|
12687
12580
|
|
|
12688
12581
|
function clearAllDisplayArcs() {
|
|
12582
|
+
model.forEachLayer(function(lyr) {
|
|
12583
|
+
if (lyr.gui) delete lyr.gui.arcCounts;
|
|
12584
|
+
});
|
|
12689
12585
|
model.getDatasets().forEach(function(o) {
|
|
12690
12586
|
delete o.gui;
|
|
12691
12587
|
});
|
|
@@ -12698,7 +12594,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12698
12594
|
if (isActiveLayer(o.layer)) {
|
|
12699
12595
|
layers.push(_activeLyr);
|
|
12700
12596
|
} else if (!isTableView()) {
|
|
12701
|
-
|
|
12597
|
+
enhanceLayerForDisplay(o.layer, o.dataset, getDisplayOptions());
|
|
12598
|
+
layers.push(o.layer);
|
|
12702
12599
|
}
|
|
12703
12600
|
});
|
|
12704
12601
|
_visibleLayers = layers;
|
|
@@ -12720,13 +12617,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12720
12617
|
return findActiveLayer(layers);
|
|
12721
12618
|
}
|
|
12722
12619
|
return layers.filter(function(o) {
|
|
12723
|
-
return !!o.geographic;
|
|
12620
|
+
return !!o.gui.geographic;
|
|
12724
12621
|
});
|
|
12725
12622
|
}
|
|
12726
12623
|
|
|
12727
12624
|
function getDrawableContentLayers() {
|
|
12728
12625
|
return getContentLayers().filter(function(lyr) {
|
|
12729
|
-
if (isActiveLayer(lyr
|
|
12626
|
+
if (isActiveLayer(lyr) && lyr.hidden) return false;
|
|
12730
12627
|
return true;
|
|
12731
12628
|
});
|
|
12732
12629
|
}
|
|
@@ -12740,31 +12637,33 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12740
12637
|
|
|
12741
12638
|
function updateLayerStyles(layers) {
|
|
12742
12639
|
layers.forEach(function(mapLayer, i) {
|
|
12640
|
+
var style;
|
|
12743
12641
|
if (mapLayer.active) {
|
|
12744
12642
|
// regenerating active style everytime, to support style change when
|
|
12745
12643
|
// switching between outline and preview modes.
|
|
12746
|
-
|
|
12747
|
-
if (
|
|
12644
|
+
style = getActiveLayerStyle(mapLayer.gui.displayLayer, getGlobalStyleOptions());
|
|
12645
|
+
if (style.type != 'styled' && layers.length > 1 && style.strokeColors) {
|
|
12748
12646
|
// kludge to hide ghosted layers when reference layers are present
|
|
12749
12647
|
// TODO: consider never showing ghosted layers (which appear after
|
|
12750
12648
|
// commands like dissolve and filter).
|
|
12751
|
-
|
|
12752
|
-
strokeColors: [null,
|
|
12753
|
-
},
|
|
12649
|
+
style = utils$1.defaults({
|
|
12650
|
+
strokeColors: [null, style.strokeColors[1]]
|
|
12651
|
+
}, style);
|
|
12754
12652
|
}
|
|
12755
12653
|
} else {
|
|
12756
|
-
if (mapLayer
|
|
12654
|
+
if (mapLayer == _activeLyr) {
|
|
12757
12655
|
console.error("Error: shared map layer");
|
|
12758
12656
|
}
|
|
12759
|
-
|
|
12657
|
+
style = getReferenceLayerStyle(mapLayer.gui.displayLayer, getGlobalStyleOptions());
|
|
12760
12658
|
}
|
|
12659
|
+
mapLayer.gui.style = style;
|
|
12761
12660
|
});
|
|
12762
12661
|
}
|
|
12763
12662
|
|
|
12764
12663
|
function sortMapLayers(layers) {
|
|
12765
12664
|
layers.sort(function(a, b) {
|
|
12766
12665
|
// assume that each layer has a menu_order (assigned by updateLayerStackOrder())
|
|
12767
|
-
return a.
|
|
12666
|
+
return a.menu_order - b.menu_order;
|
|
12768
12667
|
});
|
|
12769
12668
|
}
|
|
12770
12669
|
|
|
@@ -12844,6 +12743,99 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12844
12743
|
});
|
|
12845
12744
|
}
|
|
12846
12745
|
|
|
12746
|
+
function ContextMenu() {
|
|
12747
|
+
var body = document.querySelector('body');
|
|
12748
|
+
var menu = El('div').addClass('contextmenu rollover').appendTo(body);
|
|
12749
|
+
var _open = false;
|
|
12750
|
+
var _openCount = 0;
|
|
12751
|
+
document.addEventListener('mousedown', close);
|
|
12752
|
+
|
|
12753
|
+
this.isOpen = function() {
|
|
12754
|
+
return _open;
|
|
12755
|
+
};
|
|
12756
|
+
|
|
12757
|
+
function close() {
|
|
12758
|
+
var count = _openCount;
|
|
12759
|
+
if (!_open) return;
|
|
12760
|
+
setTimeout(function() {
|
|
12761
|
+
if (count == _openCount) {
|
|
12762
|
+
menu.hide();
|
|
12763
|
+
_open = false;
|
|
12764
|
+
}
|
|
12765
|
+
}, 300);
|
|
12766
|
+
}
|
|
12767
|
+
|
|
12768
|
+
function addMenuItem(label, func) {
|
|
12769
|
+
El('div')
|
|
12770
|
+
.appendTo(menu)
|
|
12771
|
+
.addClass('contextmenu-item')
|
|
12772
|
+
.text(label)
|
|
12773
|
+
.on('click', func)
|
|
12774
|
+
.show();
|
|
12775
|
+
}
|
|
12776
|
+
|
|
12777
|
+
this.open = function(e, lyr) {
|
|
12778
|
+
_open = true;
|
|
12779
|
+
_openCount++;
|
|
12780
|
+
var rspace = body.clientWidth - e.pageX;
|
|
12781
|
+
var xoffs = 10;
|
|
12782
|
+
menu.empty().show();
|
|
12783
|
+
if (rspace > 150) {
|
|
12784
|
+
menu.css('left', e.pageX + xoffs + 'px');
|
|
12785
|
+
} else {
|
|
12786
|
+
menu.css('right', (body.clientWidth - e.pageX + xoffs) + 'px');
|
|
12787
|
+
}
|
|
12788
|
+
menu.css('top', (e.pageY - 15) + 'px');
|
|
12789
|
+
|
|
12790
|
+
// menu contents
|
|
12791
|
+
if (e.deleteVertex) {
|
|
12792
|
+
addMenuItem('Delete vertex', e.deleteVertex);
|
|
12793
|
+
}
|
|
12794
|
+
if (e.coordinates) {
|
|
12795
|
+
addCopyCoords();
|
|
12796
|
+
}
|
|
12797
|
+
if (e.ids?.length) {
|
|
12798
|
+
addMenuItem('Copy as GeoJSON', copyGeoJSON);
|
|
12799
|
+
}
|
|
12800
|
+
|
|
12801
|
+
function addCopyCoords() {
|
|
12802
|
+
var bbox = internal.getLayerBounds(lyr, lyr.gui.source.dataset.arcs).toArray();
|
|
12803
|
+
var p = internal.getRoundedCoords(e.coordinates, internal.getBoundsPrecisionForDisplay(bbox));
|
|
12804
|
+
var coordStr = p.join(',');
|
|
12805
|
+
addMenuItem(coordStr, function() {
|
|
12806
|
+
saveFileContentToClipboard(coordStr);
|
|
12807
|
+
});
|
|
12808
|
+
}
|
|
12809
|
+
|
|
12810
|
+
function copyGeoJSON() {
|
|
12811
|
+
var opts = {
|
|
12812
|
+
no_replace: true,
|
|
12813
|
+
ids: e.ids,
|
|
12814
|
+
quiet: true
|
|
12815
|
+
};
|
|
12816
|
+
var dataset = lyr.gui.source.dataset;
|
|
12817
|
+
var layer = mapshaper.cmd.filterFeatures(lyr, dataset.arcs, opts);
|
|
12818
|
+
// the drawing tool can send open paths with 'polygon' geometry type,
|
|
12819
|
+
// should be changed to 'polyline'
|
|
12820
|
+
if (layerHasOpenPaths(layer, dataset.arcs)) {
|
|
12821
|
+
layer.geometry_type = 'polyline';
|
|
12822
|
+
}
|
|
12823
|
+
var features = internal.exportLayerAsGeoJSON(layer, dataset, {rfc7946: true, prettify: true}, true, 'string');
|
|
12824
|
+
var str = internal.geojson.formatCollection({"type": "FeatureCollection"}, features);
|
|
12825
|
+
saveFileContentToClipboard(str);
|
|
12826
|
+
}
|
|
12827
|
+
};
|
|
12828
|
+
}
|
|
12829
|
+
|
|
12830
|
+
|
|
12831
|
+
function layerHasOpenPaths(layer, arcs) {
|
|
12832
|
+
var retn = false;
|
|
12833
|
+
internal.editShapes(layer.shapes, function(part) {
|
|
12834
|
+
if (!geom.pathIsClosed(part, arcs)) retn = true;
|
|
12835
|
+
});
|
|
12836
|
+
return retn;
|
|
12837
|
+
}
|
|
12838
|
+
|
|
12847
12839
|
function GuiInstance(container, opts) {
|
|
12848
12840
|
var gui = new ModeSwitcher();
|
|
12849
12841
|
opts = utils$1.extend({
|
|
@@ -12862,15 +12854,15 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12862
12854
|
gui.model = new Model(gui);
|
|
12863
12855
|
gui.keyboard = new KeyboardEvents(gui);
|
|
12864
12856
|
gui.buttons = new SidebarButtons(gui);
|
|
12865
|
-
gui.map = new MshpMap(gui);
|
|
12866
|
-
gui.interaction = new InteractionMode(gui);
|
|
12867
12857
|
gui.session = new SessionHistory(gui);
|
|
12858
|
+
gui.contextMenu = new ContextMenu();
|
|
12868
12859
|
gui.undo = new Undo(gui);
|
|
12869
|
-
gui.
|
|
12870
|
-
|
|
12860
|
+
gui.map = new MshpMap(gui);
|
|
12871
12861
|
if (opts.saveControl) {
|
|
12872
12862
|
new SessionSnapshots(gui);
|
|
12873
12863
|
}
|
|
12864
|
+
gui.interaction = new InteractionMode(gui);
|
|
12865
|
+
gui.state = {};
|
|
12874
12866
|
|
|
12875
12867
|
var msgCount = 0;
|
|
12876
12868
|
var clearMsg;
|