mapshaper 0.6.81 → 0.6.83
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 +11 -10
- package/package.json +2 -2
- package/www/index.html +3 -3
- package/www/mapshaper-gui.js +508 -421
- package/www/mapshaper.js +11 -10
- package/www/modules.js +1856 -140
- package/www/page.css +56 -11
package/www/mapshaper-gui.js
CHANGED
|
@@ -2564,18 +2564,6 @@
|
|
|
2564
2564
|
return isProjectedLayer(lyr) ? lyr.gui.invertPoint(p[0], p[1]) : p;
|
|
2565
2565
|
}
|
|
2566
2566
|
|
|
2567
|
-
// bbox: display coords
|
|
2568
|
-
// intended to work with rectangular projections like Mercator
|
|
2569
|
-
function getBBoxCoords(lyr, bbox) {
|
|
2570
|
-
if (!isProjectedLayer(lyr)) return bbox.concat();
|
|
2571
|
-
var a = translateDisplayPoint(lyr, [bbox[0], bbox[1]]);
|
|
2572
|
-
var b = translateDisplayPoint(lyr, [bbox[2], bbox[3]]);
|
|
2573
|
-
var bounds = new internal.Bounds();
|
|
2574
|
-
bounds.mergePoint(a[0], a[1]);
|
|
2575
|
-
bounds.mergePoint(b[0], b[1]);
|
|
2576
|
-
return bounds.toArray();
|
|
2577
|
-
}
|
|
2578
|
-
|
|
2579
2567
|
function isProjectedLayer(lyr) {
|
|
2580
2568
|
return !!lyr?.gui.invertPoint;
|
|
2581
2569
|
}
|
|
@@ -3425,7 +3413,7 @@
|
|
|
3425
3413
|
//
|
|
3426
3414
|
function pointExceedsTolerance(p, points, tolerance) {
|
|
3427
3415
|
if (points.length < 2) return false;
|
|
3428
|
-
var p1 = points[0], p2, dist;
|
|
3416
|
+
var p1 = points[0], p2, dist, angle;
|
|
3429
3417
|
for (var i=1; i<points.length; i++) {
|
|
3430
3418
|
p2 = points[i];
|
|
3431
3419
|
dist = Math.sqrt(geom.pointSegDistSq(p2[0], p2[1], p1[0], p1[1], p[0], p[1]));
|
|
@@ -3434,6 +3422,15 @@
|
|
|
3434
3422
|
return false;
|
|
3435
3423
|
}
|
|
3436
3424
|
|
|
3425
|
+
function getAvgPoint(points) {
|
|
3426
|
+
var x=0, y=0;
|
|
3427
|
+
for (var i=0; i<points.length; i++) {
|
|
3428
|
+
x += points[i][0];
|
|
3429
|
+
y += points[i][1];
|
|
3430
|
+
}
|
|
3431
|
+
return [x/points.length, y/points.length];
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3437
3434
|
function setZ(lyr, z) {
|
|
3438
3435
|
lyr.gui.source.dataset.arcs.setRetainedInterval(z);
|
|
3439
3436
|
if (isProjectedLayer(lyr)) {
|
|
@@ -5812,6 +5809,7 @@
|
|
|
5812
5809
|
var ctrlDown = false;
|
|
5813
5810
|
var metaDown = false;
|
|
5814
5811
|
var altDown = false;
|
|
5812
|
+
var spaceDown = false;
|
|
5815
5813
|
|
|
5816
5814
|
function updateControlKeys(e) {
|
|
5817
5815
|
shiftDown = e.shiftKey;
|
|
@@ -5819,15 +5817,22 @@
|
|
|
5819
5817
|
metaDown = e.metaKey;
|
|
5820
5818
|
altDown = e.altKey;
|
|
5821
5819
|
}
|
|
5820
|
+
|
|
5821
|
+
function mouseIsPressed() {
|
|
5822
|
+
return gui.map.getMouse().isDown();
|
|
5823
|
+
}
|
|
5824
|
+
|
|
5822
5825
|
document.addEventListener('keyup', function(e) {
|
|
5823
|
-
if (!GUI.isActiveInstance(gui)) return;
|
|
5826
|
+
if (!GUI.isActiveInstance(gui) || e.repeat) return;
|
|
5824
5827
|
// this can fail to fire if keyup occurs over a context menu
|
|
5828
|
+
if (e.keyCode == 32) spaceDown = false;
|
|
5825
5829
|
updateControlKeys(e);
|
|
5826
5830
|
self.dispatchEvent('keyup', getEventData(e));
|
|
5827
5831
|
});
|
|
5828
5832
|
|
|
5829
5833
|
document.addEventListener('keydown', function(e) {
|
|
5830
|
-
if (!GUI.isActiveInstance(gui)) return;
|
|
5834
|
+
if (!GUI.isActiveInstance(gui) || e.repeat) return;
|
|
5835
|
+
if (e.keyCode == 32) spaceDown = true;
|
|
5831
5836
|
updateControlKeys(e);
|
|
5832
5837
|
self.dispatchEvent('keydown', getEventData(e));
|
|
5833
5838
|
});
|
|
@@ -5837,10 +5842,11 @@
|
|
|
5837
5842
|
updateControlKeys(e);
|
|
5838
5843
|
});
|
|
5839
5844
|
|
|
5840
|
-
this.shiftIsPressed =
|
|
5841
|
-
this.ctrlIsPressed =
|
|
5842
|
-
this.altIsPressed =
|
|
5843
|
-
this.metaIsPressed =
|
|
5845
|
+
this.shiftIsPressed = () => shiftDown;
|
|
5846
|
+
this.ctrlIsPressed = () => ctrlDown;
|
|
5847
|
+
this.altIsPressed = () => altDown;
|
|
5848
|
+
this.metaIsPressed = () => metaDown;
|
|
5849
|
+
this.spaceIsPressed = () => spaceDown;
|
|
5844
5850
|
|
|
5845
5851
|
this.onMenuSubmit = function(menuEl, cb) {
|
|
5846
5852
|
gui.on('enter_key', function(e) {
|
|
@@ -5878,7 +5884,7 @@
|
|
|
5878
5884
|
|
|
5879
5885
|
var menus = {
|
|
5880
5886
|
standard: ['info', 'selection', 'box'],
|
|
5881
|
-
empty: ['edit_points', 'edit_lines', 'edit_polygons'],
|
|
5887
|
+
empty: ['edit_points', 'edit_lines', 'edit_polygons', 'box'],
|
|
5882
5888
|
polygons: ['info', 'selection', 'box', 'edit_polygons'],
|
|
5883
5889
|
rectangles: ['info', 'selection', 'box', 'rectangles'],
|
|
5884
5890
|
lines: ['info', 'selection', 'box' , 'edit_lines'],
|
|
@@ -8056,7 +8062,6 @@
|
|
|
8056
8062
|
var transientIds = []; // e.g. hit ids while dragging a box
|
|
8057
8063
|
var drawingId = -1; // kludge to allow hit detection and drawing (different feature ids)
|
|
8058
8064
|
var active = false;
|
|
8059
|
-
var interactionMode;
|
|
8060
8065
|
var targetLayer;
|
|
8061
8066
|
var hitTest;
|
|
8062
8067
|
var pinnedOn; // used in multi-edit mode (selection) for toggling pinning behavior
|
|
@@ -8066,16 +8071,11 @@
|
|
|
8066
8071
|
var priority = 2;
|
|
8067
8072
|
|
|
8068
8073
|
mouse.on('contextmenu', function(e) {
|
|
8069
|
-
// shift key enables default menu (for development)
|
|
8070
|
-
if (gui.keyboard.shiftIsPressed()) {
|
|
8071
|
-
return;
|
|
8072
|
-
}
|
|
8073
8074
|
e.originalEvent.preventDefault();
|
|
8074
|
-
if (
|
|
8075
|
-
|
|
8075
|
+
if (El('body').hasClass('map-view')) {
|
|
8076
|
+
triggerHitEvent('contextmenu', e);
|
|
8076
8077
|
}
|
|
8077
|
-
|
|
8078
|
-
}, false);
|
|
8078
|
+
});
|
|
8079
8079
|
|
|
8080
8080
|
// init keyboard controls for pinned features
|
|
8081
8081
|
gui.keyboard.on('keydown', function(evt) {
|
|
@@ -8117,11 +8117,14 @@
|
|
|
8117
8117
|
};
|
|
8118
8118
|
|
|
8119
8119
|
function updateHitTest(featureFilter) {
|
|
8120
|
-
hitTest = getPointerHitTest(targetLayer, ext, interactionMode, featureFilter);
|
|
8120
|
+
hitTest = getPointerHitTest(targetLayer, ext, interactionMode(), featureFilter);
|
|
8121
|
+
}
|
|
8122
|
+
|
|
8123
|
+
function interactionMode() {
|
|
8124
|
+
return gui.interaction.getMode();
|
|
8121
8125
|
}
|
|
8122
8126
|
|
|
8123
8127
|
function turnOn(mode) {
|
|
8124
|
-
interactionMode = mode;
|
|
8125
8128
|
active = true;
|
|
8126
8129
|
updateHitTest();
|
|
8127
8130
|
}
|
|
@@ -8136,12 +8139,8 @@
|
|
|
8136
8139
|
}
|
|
8137
8140
|
}
|
|
8138
8141
|
|
|
8139
|
-
function hoverable() {
|
|
8140
|
-
return !!interactionMode;
|
|
8141
|
-
}
|
|
8142
|
-
|
|
8143
8142
|
function selectable() {
|
|
8144
|
-
return interactionMode == 'selection';
|
|
8143
|
+
return interactionMode() == 'selection';
|
|
8145
8144
|
}
|
|
8146
8145
|
|
|
8147
8146
|
function pinnable() {
|
|
@@ -8150,16 +8149,16 @@
|
|
|
8150
8149
|
}
|
|
8151
8150
|
|
|
8152
8151
|
function draggable() {
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8152
|
+
var mode = interactionMode();
|
|
8153
|
+
return mode == 'vertices' || mode == 'edit_points' ||
|
|
8154
|
+
mode == 'labels' || mode == 'edit_lines' || mode == 'edit_polygons';
|
|
8156
8155
|
}
|
|
8157
8156
|
|
|
8158
8157
|
function clickable() {
|
|
8158
|
+
var mode = interactionMode();
|
|
8159
8159
|
// click used to pin popup and select features
|
|
8160
|
-
return
|
|
8161
|
-
|
|
8162
|
-
interactionMode == 'edit_points';
|
|
8160
|
+
return mode == 'data' || mode == 'info' || mode == 'selection' ||
|
|
8161
|
+
mode == 'rectangles' || mode == 'edit_points';
|
|
8163
8162
|
}
|
|
8164
8163
|
|
|
8165
8164
|
self.getHitId = function() {
|
|
@@ -8284,7 +8283,6 @@
|
|
|
8284
8283
|
// (some modes do not support pinning)
|
|
8285
8284
|
gui.on('interaction_mode_change', function(e) {
|
|
8286
8285
|
self.clearSelection();
|
|
8287
|
-
// if (e.mode == 'off' || e.mode == 'box') {
|
|
8288
8286
|
if (gui.interaction.modeUsesHitDetection(e.mode)) {
|
|
8289
8287
|
turnOn(e.mode);
|
|
8290
8288
|
} else {
|
|
@@ -8317,7 +8315,7 @@
|
|
|
8317
8315
|
updateSelectionState(convertClickDataToSelectionData(hitTest(e)));
|
|
8318
8316
|
}
|
|
8319
8317
|
|
|
8320
|
-
if (pinned && interactionMode == 'edit_points') {
|
|
8318
|
+
if (pinned && interactionMode() == 'edit_points') {
|
|
8321
8319
|
// kludge: intercept the click event if popup is turning off, so
|
|
8322
8320
|
// a new point doesn't get made
|
|
8323
8321
|
return;
|
|
@@ -8442,6 +8440,7 @@
|
|
|
8442
8440
|
|
|
8443
8441
|
// check if an event is used in the current interaction mode
|
|
8444
8442
|
function eventIsEnabled(type) {
|
|
8443
|
+
var mode = interactionMode();
|
|
8445
8444
|
if (!active) return false;
|
|
8446
8445
|
if (type == 'click' && gui.keyboard.ctrlIsPressed()) {
|
|
8447
8446
|
return false; // don't fire if context menu might open
|
|
@@ -8450,13 +8449,13 @@
|
|
|
8450
8449
|
return false;
|
|
8451
8450
|
}
|
|
8452
8451
|
if (type == 'click' &&
|
|
8453
|
-
(
|
|
8452
|
+
(mode == 'edit_lines' || mode == 'edit_polygons')) {
|
|
8454
8453
|
return true; // click events are triggered even if no shape is hit
|
|
8455
8454
|
}
|
|
8456
|
-
if (type == 'click' &&
|
|
8455
|
+
if (type == 'click' && mode == 'edit_points') {
|
|
8457
8456
|
return true;
|
|
8458
8457
|
}
|
|
8459
|
-
if ((
|
|
8458
|
+
if ((mode == 'edit_lines' || mode == 'edit_polygons') &&
|
|
8460
8459
|
(type == 'hover' || type == 'dblclick')) {
|
|
8461
8460
|
return true; // special case -- using hover for line drawing animation
|
|
8462
8461
|
}
|
|
@@ -8477,7 +8476,7 @@
|
|
|
8477
8476
|
}
|
|
8478
8477
|
|
|
8479
8478
|
function possiblyStopPropagation(e) {
|
|
8480
|
-
if (interactionMode == 'edit_lines' || interactionMode == 'edit_polygons') {
|
|
8479
|
+
if (interactionMode() == 'edit_lines' || interactionMode() == 'edit_polygons') {
|
|
8481
8480
|
// handled conditionally in the control
|
|
8482
8481
|
return;
|
|
8483
8482
|
}
|
|
@@ -8494,7 +8493,7 @@
|
|
|
8494
8493
|
// evt: event data (may be a pointer event object, an ordinary object or null)
|
|
8495
8494
|
function triggerHitEvent(type, evt) {
|
|
8496
8495
|
var eventData = {
|
|
8497
|
-
mode: interactionMode
|
|
8496
|
+
mode: interactionMode()
|
|
8498
8497
|
};
|
|
8499
8498
|
if (evt) {
|
|
8500
8499
|
// data coordinates
|
|
@@ -8813,6 +8812,11 @@
|
|
|
8813
8812
|
element.addEventListener('mousedown', onAreaDown);
|
|
8814
8813
|
element.addEventListener('dblclick', onAreaDblClick);
|
|
8815
8814
|
document.addEventListener('contextmenu', function(e) {
|
|
8815
|
+
if (!e.ctrlKey) {
|
|
8816
|
+
e.preventDefault();
|
|
8817
|
+
}
|
|
8818
|
+
});
|
|
8819
|
+
element.addEventListener('contextmenu', function(e) {
|
|
8816
8820
|
_self.dispatchEvent('contextmenu', procMouseEvent(e));
|
|
8817
8821
|
});
|
|
8818
8822
|
|
|
@@ -9090,9 +9094,9 @@
|
|
|
9090
9094
|
|
|
9091
9095
|
box.getDataCoords = function() {
|
|
9092
9096
|
if (!boxCoords) return null;
|
|
9093
|
-
var
|
|
9097
|
+
var lyr = gui.map.getActiveLayer();
|
|
9098
|
+
var dataBox = lyr ? translateCoordsToLayerCRS(boxCoords, lyr) : translateCoordsToLatLon(boxCoords);
|
|
9094
9099
|
fixBounds(dataBox);
|
|
9095
|
-
// return internal.getRoundedCoords(dataBox, internal.getBoundsPrecisionForDisplay(dataBox));
|
|
9096
9100
|
return dataBox;
|
|
9097
9101
|
};
|
|
9098
9102
|
|
|
@@ -9127,6 +9131,26 @@
|
|
|
9127
9131
|
}
|
|
9128
9132
|
};
|
|
9129
9133
|
|
|
9134
|
+
function translateCoordsToLatLon(bbox) {
|
|
9135
|
+
var crs = gui.map.getDisplayCRS();
|
|
9136
|
+
var a = internal.toLngLat([bbox[0], bbox[1]], crs);
|
|
9137
|
+
var b = internal.toLngLat([bbox[2], bbox[3]], crs);
|
|
9138
|
+
return a.concat(b);
|
|
9139
|
+
}
|
|
9140
|
+
|
|
9141
|
+
// bbox: display coords
|
|
9142
|
+
// intended to work with rectangular projections like Mercator
|
|
9143
|
+
function translateCoordsToLayerCRS(bbox, lyr) {
|
|
9144
|
+
if (!isProjectedLayer(lyr)) return bbox.concat();
|
|
9145
|
+
var a = translateDisplayPoint(lyr, [bbox[0], bbox[1]]);
|
|
9146
|
+
var b = translateDisplayPoint(lyr, [bbox[2], bbox[3]]);
|
|
9147
|
+
var bounds = new internal.Bounds();
|
|
9148
|
+
bounds.mergePoint(a[0], a[1]);
|
|
9149
|
+
bounds.mergePoint(b[0], b[1]);
|
|
9150
|
+
return bounds.toArray();
|
|
9151
|
+
}
|
|
9152
|
+
|
|
9153
|
+
// get bbox coords in the display CRS
|
|
9130
9154
|
function getBoxCoords(e) {
|
|
9131
9155
|
var bbox = pixToCoords(e.a.concat(e.b), gui.map.getExtent());
|
|
9132
9156
|
fixBounds(bbox);
|
|
@@ -9227,6 +9251,7 @@
|
|
|
9227
9251
|
zoomBox = new HighlightBox(gui, {draggable: true, name: 'zoom-box'}), // .addClass('zooming'),
|
|
9228
9252
|
shiftDrag = false,
|
|
9229
9253
|
zoomScaleMultiplier = 1,
|
|
9254
|
+
panCount = 0,
|
|
9230
9255
|
inBtn, outBtn,
|
|
9231
9256
|
dragStartEvt,
|
|
9232
9257
|
_fx, _fy; // zoom foci, [0,1]
|
|
@@ -9278,6 +9303,7 @@
|
|
|
9278
9303
|
// var lyr = gui.model.getActiveLayer()?.layer;
|
|
9279
9304
|
// if (lyr && !internal.layerHasGeometry(lyr)) return;
|
|
9280
9305
|
shiftDrag = !!e.shiftKey;
|
|
9306
|
+
panCount = 0;
|
|
9281
9307
|
if (shiftDrag) {
|
|
9282
9308
|
if (useBoxZoom()) zoomBox.turnOn();
|
|
9283
9309
|
dragStartEvt = e;
|
|
@@ -9289,9 +9315,18 @@
|
|
|
9289
9315
|
if (disabled()) return;
|
|
9290
9316
|
if (shiftDrag) {
|
|
9291
9317
|
gui.dispatchEvent('shift_drag', getBoxData(e));
|
|
9292
|
-
|
|
9293
|
-
ext.pan(e.dx, e.dy);
|
|
9318
|
+
return;
|
|
9294
9319
|
}
|
|
9320
|
+
if (++panCount == 1) {
|
|
9321
|
+
El('body').addClass('pan');
|
|
9322
|
+
setTimeout(function() {
|
|
9323
|
+
var body = El('body');
|
|
9324
|
+
if (body.hasClass('pan')) {
|
|
9325
|
+
body.addClass('panning');
|
|
9326
|
+
}
|
|
9327
|
+
}, 100);
|
|
9328
|
+
}
|
|
9329
|
+
ext.pan(e.dx, e.dy);
|
|
9295
9330
|
});
|
|
9296
9331
|
|
|
9297
9332
|
mouse.on('dragend', function(e) {
|
|
@@ -9301,6 +9336,8 @@
|
|
|
9301
9336
|
shiftDrag = false;
|
|
9302
9337
|
gui.dispatchEvent('shift_drag_end', getBoxData(e));
|
|
9303
9338
|
zoomBox.turnOff();
|
|
9339
|
+
} else {
|
|
9340
|
+
El('body').removeClass('panning').removeClass('pan');
|
|
9304
9341
|
}
|
|
9305
9342
|
});
|
|
9306
9343
|
|
|
@@ -10304,7 +10341,7 @@
|
|
|
10304
10341
|
}
|
|
10305
10342
|
|
|
10306
10343
|
function pencilIsActive() {
|
|
10307
|
-
return
|
|
10344
|
+
return active() && (cmdKeyDown() || pathDrawing()) && !vertexDragging() && !!pencilPoints;
|
|
10308
10345
|
}
|
|
10309
10346
|
|
|
10310
10347
|
function polygonMode() {
|
|
@@ -10389,8 +10426,7 @@
|
|
|
10389
10426
|
function showInstructions() {
|
|
10390
10427
|
var isMac = navigator.userAgent.includes('Mac');
|
|
10391
10428
|
var undoKey = isMac ? '⌘' : '^';
|
|
10392
|
-
var
|
|
10393
|
-
var msg = `Instructions: Click to start a path or add a point. ${drawKey}-drag draws a path. Drag points to reshape. Type ${undoKey}Z/${undoKey}Y to undo/redo.`;
|
|
10429
|
+
var msg = `Instructions: click to start a path, click or drag to keep drawing. Drag vertices to reshape a path. Type ${undoKey}Z/${undoKey}Y to undo/redo.`;
|
|
10394
10430
|
alert = showPopupAlert(msg, null, {
|
|
10395
10431
|
non_blocking: true, max_width: '388px'});
|
|
10396
10432
|
}
|
|
@@ -10449,8 +10485,15 @@
|
|
|
10449
10485
|
drawingId = -1;
|
|
10450
10486
|
hoverVertexInfo = null;
|
|
10451
10487
|
prevClickEvent = prevHoverEvent = null;
|
|
10488
|
+
updateCursor();
|
|
10452
10489
|
}
|
|
10453
10490
|
|
|
10491
|
+
gui.keyboard.on('keydown', function(e) {
|
|
10492
|
+
if (active() && e.keyName == 'space') {
|
|
10493
|
+
e.stopPropagation(); // prevent console from opening if shift-panning
|
|
10494
|
+
}
|
|
10495
|
+
}, null, 1);
|
|
10496
|
+
|
|
10454
10497
|
hit.on('contextmenu', function(e) {
|
|
10455
10498
|
if (!active() || pathDrawing() || vertexDragging()) return;
|
|
10456
10499
|
var target = hit.getHitTarget();
|
|
@@ -10482,11 +10525,21 @@
|
|
|
10482
10525
|
});
|
|
10483
10526
|
|
|
10484
10527
|
gui.map.getMouse().on('drag', function(e) {
|
|
10485
|
-
if (!
|
|
10528
|
+
if (!pencilIsActive()) {
|
|
10529
|
+
if (!pencilPoints) {
|
|
10530
|
+
// null points signals that a path was just completed -- block panning
|
|
10531
|
+
e.stopPropagation();
|
|
10532
|
+
}
|
|
10533
|
+
return;
|
|
10534
|
+
}
|
|
10535
|
+
if (gui.keyboard.spaceIsPressed()) {
|
|
10536
|
+
// pan if dragging with spacebar down
|
|
10537
|
+
pencilPoints = []; // don't continue previous line after panning
|
|
10538
|
+
return;
|
|
10539
|
+
}
|
|
10486
10540
|
e.stopPropagation(); // prevent panning
|
|
10487
|
-
if (!pencilIsActive()) return;
|
|
10488
10541
|
hoverVertexInfo = findPathStartInfo(e);
|
|
10489
|
-
var xy = [e.x, e.y];
|
|
10542
|
+
var xy = [e.x, e.y], xy2;
|
|
10490
10543
|
var p = pixToDataCoords(e.x, e.y);
|
|
10491
10544
|
if (!pathDrawing()) {
|
|
10492
10545
|
pencilPoints = [xy];
|
|
@@ -10495,17 +10548,20 @@
|
|
|
10495
10548
|
// start pencil-drawing when a path is started
|
|
10496
10549
|
pencilPoints = [xy];
|
|
10497
10550
|
extendCurrentPath(p);
|
|
10498
|
-
} else if (hoverVertexInfo && pencilPoints.length > 2) {
|
|
10551
|
+
} else if (polygonMode() && hoverVertexInfo && pencilPoints.length > 2) {
|
|
10499
10552
|
// close path
|
|
10500
10553
|
p = hoverVertexInfo.point;
|
|
10501
10554
|
appendVertex$1(hit.getHitTarget(), p);
|
|
10502
10555
|
extendCurrentPath(p);
|
|
10503
10556
|
pencilPoints = null; // stop drawing
|
|
10504
|
-
} else if (pointExceedsTolerance(xy, pencilPoints, 1.
|
|
10505
|
-
|
|
10506
|
-
p = pixToDataCoords(
|
|
10507
|
-
pencilPoints = [xy];
|
|
10557
|
+
} else if (pencilPoints.length >= 2 && pointExceedsTolerance(xy, pencilPoints, 1.4)) {
|
|
10558
|
+
xy2 = pencilPoints.pop();
|
|
10559
|
+
p = pixToDataCoords(xy2[0], xy2[1]);
|
|
10508
10560
|
extendCurrentPath(p);
|
|
10561
|
+
// kludgy way to get a smoother line (could be better)
|
|
10562
|
+
// not this pencilPoints = [getAvgPoint(pencilPoints), xy2, xy];
|
|
10563
|
+
// not this pencilPoints = pencilPoints.slice(-2).concat([xy2, xy]);
|
|
10564
|
+
pencilPoints = [getAvgPoint(pencilPoints.slice(-3).concat([xy2])), xy2, xy];
|
|
10509
10565
|
} else {
|
|
10510
10566
|
// skip this point, update the hover line
|
|
10511
10567
|
pencilPoints.push(xy);
|
|
@@ -10624,9 +10680,11 @@
|
|
|
10624
10680
|
}
|
|
10625
10681
|
|
|
10626
10682
|
function updateCursor() {
|
|
10627
|
-
gui.container.findChild('.map-layers')
|
|
10683
|
+
var el = gui.container.findChild('.map-layers');
|
|
10684
|
+
el.classed('draw-tool', active());
|
|
10628
10685
|
var useArrow = hoverVertexInfo && !hoverVertexInfo.extendable && !pathDrawing();
|
|
10629
|
-
|
|
10686
|
+
el.classed('dragging', useArrow);
|
|
10687
|
+
el.classed('drawing', pathDrawing());
|
|
10630
10688
|
}
|
|
10631
10689
|
|
|
10632
10690
|
function vertexIsEndpoint(info, target) {
|
|
@@ -12063,7 +12121,7 @@
|
|
|
12063
12121
|
|
|
12064
12122
|
new SimpleButton(popup.findChild('.select-btn')).on('click', function() {
|
|
12065
12123
|
var coords = box.getDataCoords();
|
|
12066
|
-
if (!coords) return;
|
|
12124
|
+
if (!coords || noData()) return;
|
|
12067
12125
|
gui.enterMode('selection_tool');
|
|
12068
12126
|
gui.interaction.setMode('selection');
|
|
12069
12127
|
// kludge to pass bbox to the selection tool
|
|
@@ -12072,6 +12130,10 @@
|
|
|
12072
12130
|
});
|
|
12073
12131
|
});
|
|
12074
12132
|
|
|
12133
|
+
function noData() {
|
|
12134
|
+
return !gui.model.getActiveLayer();
|
|
12135
|
+
}
|
|
12136
|
+
|
|
12075
12137
|
new SimpleButton(popup.findChild('.clip-btn')).on('click', function() {
|
|
12076
12138
|
runCommand('-clip bbox=' + box.getDataCoords().join(','));
|
|
12077
12139
|
});
|
|
@@ -12129,7 +12191,9 @@
|
|
|
12129
12191
|
|
|
12130
12192
|
function showCoords() {
|
|
12131
12193
|
El(infoBtn.node()).addClass('selected-btn');
|
|
12132
|
-
|
|
12194
|
+
var bbox = box.getDataCoords();
|
|
12195
|
+
var rounded = internal.getRoundedCoords(bbox, internal.getBoundsPrecisionForDisplay(bbox));
|
|
12196
|
+
coords.text(rounded.join(','));
|
|
12133
12197
|
coords.show();
|
|
12134
12198
|
GUI.selectElement(coords.node());
|
|
12135
12199
|
}
|
|
@@ -12262,373 +12326,107 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12262
12326
|
}
|
|
12263
12327
|
}
|
|
12264
12328
|
|
|
12265
|
-
|
|
12266
|
-
var script = document.createElement('script');
|
|
12267
|
-
script.onload = cb;
|
|
12268
|
-
script.src = url;
|
|
12269
|
-
document.head.appendChild(script);
|
|
12270
|
-
}
|
|
12329
|
+
utils$1.inherit(MshpMap, EventDispatcher);
|
|
12271
12330
|
|
|
12272
|
-
function
|
|
12273
|
-
var
|
|
12274
|
-
|
|
12275
|
-
|
|
12276
|
-
|
|
12277
|
-
|
|
12278
|
-
|
|
12279
|
-
|
|
12331
|
+
function MshpMap(gui) {
|
|
12332
|
+
var opts = gui.options,
|
|
12333
|
+
el = gui.container.findChild('.map-layers').node(),
|
|
12334
|
+
position = new ElementPosition(el),
|
|
12335
|
+
model = gui.model,
|
|
12336
|
+
map = this,
|
|
12337
|
+
_mouse = new MouseArea(el, position),
|
|
12338
|
+
_ext = new MapExtent(position),
|
|
12339
|
+
_nav = new MapNav(gui, _ext, _mouse),
|
|
12340
|
+
_visibleLayers = [], // cached visible map layers
|
|
12341
|
+
_hit,
|
|
12342
|
+
_intersectionLyr, _activeLyr, _overlayLyr,
|
|
12343
|
+
_renderer, _dynamicCRS;
|
|
12280
12344
|
|
|
12281
|
-
|
|
12282
|
-
var menu = gui.container.findChild('.basemap-options');
|
|
12283
|
-
// var hideBtn = new SimpleButton(menu.findChild('.hide-btn'));
|
|
12284
|
-
var fadeBtn = new SimpleButton(menu.findChild('.fade-btn'));
|
|
12285
|
-
var closeBtn = new SimpleButton(menu.findChild('.close2-btn'));
|
|
12286
|
-
var clearBtn = new SimpleButton(menu.findChild('.clear-btn'));
|
|
12287
|
-
var list = menu.findChild('.basemap-styles');
|
|
12288
|
-
var container = gui.container.findChild('.basemap-container');
|
|
12289
|
-
var basemapBtn = gui.container.findChild('.basemap-btn');
|
|
12290
|
-
var basemapNote = gui.container.findChild('.basemap-note');
|
|
12291
|
-
var basemapWarning = gui.container.findChild('.basemap-warning');
|
|
12292
|
-
var mapEl = gui.container.findChild('.basemap');
|
|
12293
|
-
var extentNote = El('div').addClass('basemap-prompt').appendTo(container).hide();
|
|
12294
|
-
var params = window.mapboxParams;
|
|
12295
|
-
var map;
|
|
12296
|
-
var activeStyle;
|
|
12297
|
-
var loading = false;
|
|
12298
|
-
var faded = false;
|
|
12345
|
+
_mouse.disable(); // wait for gui.focus() to activate mouse events
|
|
12299
12346
|
|
|
12300
|
-
|
|
12301
|
-
|
|
12302
|
-
|
|
12303
|
-
}
|
|
12304
|
-
basemapBtn.hide();
|
|
12305
|
-
}
|
|
12347
|
+
model.on('select', function(e) {
|
|
12348
|
+
_intersectionLyr = null;
|
|
12349
|
+
_overlayLyr = null;
|
|
12350
|
+
});
|
|
12306
12351
|
|
|
12307
|
-
function
|
|
12308
|
-
|
|
12352
|
+
gui.on('active', function() {
|
|
12353
|
+
_mouse.enable();
|
|
12354
|
+
});
|
|
12309
12355
|
|
|
12310
|
-
|
|
12311
|
-
|
|
12312
|
-
|
|
12313
|
-
});
|
|
12356
|
+
gui.on('inactive', function() {
|
|
12357
|
+
_mouse.disable();
|
|
12358
|
+
});
|
|
12314
12359
|
|
|
12315
|
-
|
|
12316
|
-
|
|
12317
|
-
|
|
12318
|
-
updateButtons();
|
|
12319
|
-
closeMenu();
|
|
12320
|
-
}
|
|
12321
|
-
});
|
|
12360
|
+
gui.on('map-needs-refresh', function() {
|
|
12361
|
+
drawLayers();
|
|
12362
|
+
});
|
|
12322
12363
|
|
|
12323
|
-
|
|
12324
|
-
if (faded) {
|
|
12325
|
-
mapEl.css('opacity', 1);
|
|
12326
|
-
faded = false;
|
|
12327
|
-
fadeBtn.text('Fade');
|
|
12328
|
-
} else if (activeStyle) {
|
|
12329
|
-
mapEl.css('opacity', 0.35);
|
|
12330
|
-
faded = true;
|
|
12331
|
-
fadeBtn.text('Unfade');
|
|
12332
|
-
}
|
|
12333
|
-
});
|
|
12364
|
+
model.on('update', onUpdate);
|
|
12334
12365
|
|
|
12335
|
-
|
|
12336
|
-
|
|
12337
|
-
|
|
12338
|
-
|
|
12366
|
+
document.addEventListener('visibilitychange', function(e) {
|
|
12367
|
+
// refresh map when browser tab is re-activated (Chrome on mac has been
|
|
12368
|
+
// blanking the canvas after several other tabs are visited)
|
|
12369
|
+
if (document.visibilityState == 'visible') drawLayers();
|
|
12370
|
+
});
|
|
12339
12371
|
|
|
12340
|
-
|
|
12341
|
-
|
|
12342
|
-
|
|
12343
|
-
|
|
12344
|
-
|
|
12345
|
-
|
|
12346
|
-
|
|
12347
|
-
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12351
|
-
|
|
12352
|
-
|
|
12353
|
-
}
|
|
12372
|
+
// Update display of segment intersections
|
|
12373
|
+
this.setIntersectionLayer = function(lyr, dataset) {
|
|
12374
|
+
if (lyr == _intersectionLyr) return; // no change
|
|
12375
|
+
if (lyr) {
|
|
12376
|
+
enhanceLayerForDisplay(lyr, dataset, getDisplayOptions());
|
|
12377
|
+
_intersectionLyr = lyr;
|
|
12378
|
+
_intersectionLyr.gui.style = getIntersectionStyle(_intersectionLyr.gui.displayLayer, getGlobalStyleOptions());
|
|
12379
|
+
} else {
|
|
12380
|
+
_intersectionLyr = null;
|
|
12381
|
+
}
|
|
12382
|
+
// TODO: try to avoid redrawing layers twice (in some situations)
|
|
12383
|
+
drawLayers();
|
|
12384
|
+
};
|
|
12354
12385
|
|
|
12355
|
-
|
|
12356
|
-
|
|
12357
|
-
|
|
12358
|
-
gui.clearMode();
|
|
12359
|
-
}, 200);
|
|
12360
|
-
}
|
|
12386
|
+
this.setLayerPinning = function(target, pinned) {
|
|
12387
|
+
target.layer.pinned = !!pinned;
|
|
12388
|
+
};
|
|
12361
12389
|
|
|
12362
|
-
function
|
|
12363
|
-
|
|
12364
|
-
|
|
12365
|
-
|
|
12366
|
-
}
|
|
12390
|
+
this.translatePixelCoords = function(x, y) {
|
|
12391
|
+
var p = _ext.translatePixelCoords(x, y);
|
|
12392
|
+
if (!_dynamicCRS) return p;
|
|
12393
|
+
return internal.toLngLat(p, _dynamicCRS);
|
|
12394
|
+
};
|
|
12367
12395
|
|
|
12368
|
-
function
|
|
12369
|
-
|
|
12370
|
-
|
|
12371
|
-
|
|
12372
|
-
|
|
12373
|
-
|
|
12374
|
-
|
|
12375
|
-
refresh();
|
|
12376
|
-
} else if (prepareMapView()) {
|
|
12377
|
-
initMap();
|
|
12396
|
+
this.pixelCoordsToDisplayCoords = function(x, y) {
|
|
12397
|
+
var p1 = _ext.translatePixelCoords(x, y);
|
|
12398
|
+
var p2 = _ext.translatePixelCoords(x+1, y+1);
|
|
12399
|
+
var crs = this.getDisplayCRS();
|
|
12400
|
+
if (crs) {
|
|
12401
|
+
p1 = internal.toLngLat(p1, crs) || p1;
|
|
12402
|
+
p2 = internal.toLngLat(p2, crs) || p2;
|
|
12378
12403
|
}
|
|
12379
|
-
|
|
12380
|
-
|
|
12381
|
-
function updateButtons() {
|
|
12382
|
-
list.findChildren('.basemap-style-btn').forEach(function(el, i) {
|
|
12383
|
-
el.classed('active', params.styles[i] == activeStyle);
|
|
12384
|
-
});
|
|
12385
|
-
}
|
|
12386
|
-
|
|
12387
|
-
function turnOn() {
|
|
12388
|
-
// TODO: show basemap even if there is no data
|
|
12389
|
-
var activeLyr = gui.model.getActiveLayer(); // may be null
|
|
12390
|
-
var info = getDatasetCrsInfo(activeLyr?.dataset); // defaults to wgs84
|
|
12391
|
-
var dataCRS = info.crs || null;
|
|
12392
|
-
var displayCRS = gui.map.getDisplayCRS();
|
|
12393
|
-
var warning;
|
|
12404
|
+
return formatCoordsForDisplay(p1, p2);
|
|
12405
|
+
};
|
|
12394
12406
|
|
|
12395
|
-
|
|
12396
|
-
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12407
|
+
// this.getCenterLngLat = function() {
|
|
12408
|
+
// var bounds = _ext.getBounds();
|
|
12409
|
+
// var crs = this.getDisplayCRS();
|
|
12410
|
+
// // TODO: handle case where active layer is a frame layer
|
|
12411
|
+
// if (!bounds.hasBounds() || !crs) {
|
|
12412
|
+
// return null;
|
|
12413
|
+
// }
|
|
12414
|
+
// return internal.toLngLat([bounds.centerX(), bounds.centerY()], crs);
|
|
12415
|
+
// };
|
|
12402
12416
|
|
|
12403
|
-
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
basemapNote.show();
|
|
12417
|
+
this.getDisplayCRS = function() {
|
|
12418
|
+
if (!_activeLyr) {
|
|
12419
|
+
return _dynamicCRS || internal.parseCrsString('wgs84');
|
|
12407
12420
|
}
|
|
12408
|
-
|
|
12409
|
-
|
|
12410
|
-
|
|
12411
|
-
|
|
12412
|
-
|
|
12413
|
-
|
|
12414
|
-
|
|
12415
|
-
|
|
12416
|
-
|
|
12417
|
-
function enabled() {
|
|
12418
|
-
return !!(mapEl && params);
|
|
12419
|
-
}
|
|
12420
|
-
|
|
12421
|
-
function show() {
|
|
12422
|
-
gui.container.addClass('basemap-on');
|
|
12423
|
-
mapEl.node().style.display = 'block';
|
|
12424
|
-
}
|
|
12425
|
-
|
|
12426
|
-
function hide() {
|
|
12427
|
-
gui.container.removeClass('basemap-on');
|
|
12428
|
-
mapEl.node().style.display = 'none';
|
|
12429
|
-
}
|
|
12430
|
-
|
|
12431
|
-
function getLonLatBounds() {
|
|
12432
|
-
var bbox = ext.getBounds().toArray();
|
|
12433
|
-
var bbox2 = fromWebMercator(bbox[0], bbox[1])
|
|
12434
|
-
.concat(fromWebMercator(bbox[2], bbox[3]));
|
|
12435
|
-
return bbox2;
|
|
12436
|
-
}
|
|
12437
|
-
|
|
12438
|
-
function initMap() {
|
|
12439
|
-
if (!enabled() || map || loading) return;
|
|
12440
|
-
loading = true;
|
|
12441
|
-
loadStylesheet(params.css);
|
|
12442
|
-
loadScript(params.js, function() {
|
|
12443
|
-
map = new window.mapboxgl.Map({
|
|
12444
|
-
accessToken: params.key,
|
|
12445
|
-
logoPosition: 'bottom-left',
|
|
12446
|
-
container: mapEl.node(),
|
|
12447
|
-
style: activeStyle.url,
|
|
12448
|
-
bounds: getLonLatBounds(),
|
|
12449
|
-
doubleClickZoom: false,
|
|
12450
|
-
dragPan: false,
|
|
12451
|
-
dragRotate: false,
|
|
12452
|
-
scrollZoom: false,
|
|
12453
|
-
interactive: false,
|
|
12454
|
-
keyboard: false,
|
|
12455
|
-
maxPitch: 0,
|
|
12456
|
-
renderWorldCopies: true // false // false prevents panning off the map
|
|
12457
|
-
});
|
|
12458
|
-
map.on('load', function() {
|
|
12459
|
-
loading = false;
|
|
12460
|
-
refresh();
|
|
12461
|
-
});
|
|
12462
|
-
});
|
|
12463
|
-
}
|
|
12464
|
-
|
|
12465
|
-
// @bbox: latlon bounding box of current map extent
|
|
12466
|
-
function checkBounds(bbox) {
|
|
12467
|
-
var mpp = ext.getBounds().width() / ext.width();
|
|
12468
|
-
var z = scaleToZoom(mpp);
|
|
12469
|
-
var msg;
|
|
12470
|
-
if (bbox[1] >= -85 && bbox[3] <= 85 && z <= 20) {
|
|
12471
|
-
extentNote.hide();
|
|
12472
|
-
return true;
|
|
12473
|
-
}
|
|
12474
|
-
if (z > 20) {
|
|
12475
|
-
msg = 'zoom out';
|
|
12476
|
-
} else if (bbox[1] > 0) {
|
|
12477
|
-
msg = 'pan south';
|
|
12478
|
-
} else if (bbox[3] < 0) {
|
|
12479
|
-
msg = 'pan north';
|
|
12480
|
-
} else {
|
|
12481
|
-
msg = msg = 'zoom in';
|
|
12482
|
-
}
|
|
12483
|
-
extentNote.html(msg + ' to see the basemap').show();
|
|
12484
|
-
return false;
|
|
12485
|
-
}
|
|
12486
|
-
|
|
12487
|
-
function crsIsUsable(crs) {
|
|
12488
|
-
if (!crs) return false;
|
|
12489
|
-
if (!internal.isInvertibleCRS(crs)) return false;
|
|
12490
|
-
return true;
|
|
12491
|
-
}
|
|
12492
|
-
|
|
12493
|
-
function prepareMapView() {
|
|
12494
|
-
var crs = gui.map.getDisplayCRS();
|
|
12495
|
-
if (!crs) return false;
|
|
12496
|
-
if (!internal.isWebMercator(crs)) {
|
|
12497
|
-
gui.map.setDisplayCRS(internal.parseCrsString('webmercator'));
|
|
12498
|
-
}
|
|
12499
|
-
return true;
|
|
12500
|
-
}
|
|
12501
|
-
|
|
12502
|
-
function refresh() {
|
|
12503
|
-
var crs = gui.map.getDisplayCRS();
|
|
12504
|
-
var off = !crs || !enabled() || !map || loading || !activeStyle;
|
|
12505
|
-
fadeBtn.active(!off);
|
|
12506
|
-
clearBtn.active(!off);
|
|
12507
|
-
if (off) {
|
|
12508
|
-
hide();
|
|
12509
|
-
extentNote.hide();
|
|
12510
|
-
return;
|
|
12511
|
-
}
|
|
12512
|
-
|
|
12513
|
-
prepareMapView();
|
|
12514
|
-
var bbox = getLonLatBounds();
|
|
12515
|
-
if (!checkBounds(bbox)) {
|
|
12516
|
-
// map does not display outside these bounds
|
|
12517
|
-
hide();
|
|
12518
|
-
} else {
|
|
12519
|
-
show();
|
|
12520
|
-
map.resize();
|
|
12521
|
-
map.fitBounds(bbox, {animate: false});
|
|
12522
|
-
}
|
|
12523
|
-
}
|
|
12524
|
-
|
|
12525
|
-
return {refresh: refresh}; // called by map when extent changes
|
|
12526
|
-
}
|
|
12527
|
-
|
|
12528
|
-
utils$1.inherit(MshpMap, EventDispatcher);
|
|
12529
|
-
|
|
12530
|
-
function MshpMap(gui) {
|
|
12531
|
-
var opts = gui.options,
|
|
12532
|
-
el = gui.container.findChild('.map-layers').node(),
|
|
12533
|
-
position = new ElementPosition(el),
|
|
12534
|
-
model = gui.model,
|
|
12535
|
-
map = this,
|
|
12536
|
-
_mouse = new MouseArea(el, position),
|
|
12537
|
-
_ext = new MapExtent(position),
|
|
12538
|
-
_nav = new MapNav(gui, _ext, _mouse),
|
|
12539
|
-
_visibleLayers = [], // cached visible map layers
|
|
12540
|
-
_hit,
|
|
12541
|
-
_basemap,
|
|
12542
|
-
_intersectionLyr, _activeLyr, _overlayLyr,
|
|
12543
|
-
_renderer, _dynamicCRS;
|
|
12544
|
-
|
|
12545
|
-
_basemap = new Basemap(gui, _ext);
|
|
12546
|
-
|
|
12547
|
-
_mouse.disable(); // wait for gui.focus() to activate mouse events
|
|
12548
|
-
|
|
12549
|
-
model.on('select', function(e) {
|
|
12550
|
-
_intersectionLyr = null;
|
|
12551
|
-
_overlayLyr = null;
|
|
12552
|
-
});
|
|
12553
|
-
|
|
12554
|
-
gui.on('active', function() {
|
|
12555
|
-
_mouse.enable();
|
|
12556
|
-
});
|
|
12557
|
-
|
|
12558
|
-
gui.on('inactive', function() {
|
|
12559
|
-
_mouse.disable();
|
|
12560
|
-
});
|
|
12561
|
-
|
|
12562
|
-
gui.on('map-needs-refresh', function() {
|
|
12563
|
-
drawLayers();
|
|
12564
|
-
});
|
|
12565
|
-
|
|
12566
|
-
model.on('update', onUpdate);
|
|
12567
|
-
|
|
12568
|
-
document.addEventListener('visibilitychange', function(e) {
|
|
12569
|
-
// refresh map when browser tab is re-activated (Chrome on mac has been
|
|
12570
|
-
// blanking the canvas after several other tabs are visited)
|
|
12571
|
-
if (document.visibilityState == 'visible') drawLayers();
|
|
12572
|
-
});
|
|
12573
|
-
|
|
12574
|
-
// Update display of segment intersections
|
|
12575
|
-
this.setIntersectionLayer = function(lyr, dataset) {
|
|
12576
|
-
if (lyr == _intersectionLyr) return; // no change
|
|
12577
|
-
if (lyr) {
|
|
12578
|
-
enhanceLayerForDisplay(lyr, dataset, getDisplayOptions());
|
|
12579
|
-
_intersectionLyr = lyr;
|
|
12580
|
-
_intersectionLyr.gui.style = getIntersectionStyle(_intersectionLyr.gui.displayLayer, getGlobalStyleOptions());
|
|
12581
|
-
} else {
|
|
12582
|
-
_intersectionLyr = null;
|
|
12583
|
-
}
|
|
12584
|
-
// TODO: try to avoid redrawing layers twice (in some situations)
|
|
12585
|
-
drawLayers();
|
|
12586
|
-
};
|
|
12587
|
-
|
|
12588
|
-
this.setLayerPinning = function(target, pinned) {
|
|
12589
|
-
target.layer.pinned = !!pinned;
|
|
12590
|
-
};
|
|
12591
|
-
|
|
12592
|
-
this.translatePixelCoords = function(x, y) {
|
|
12593
|
-
var p = _ext.translatePixelCoords(x, y);
|
|
12594
|
-
if (!_dynamicCRS) return p;
|
|
12595
|
-
return internal.toLngLat(p, _dynamicCRS);
|
|
12596
|
-
};
|
|
12597
|
-
|
|
12598
|
-
this.pixelCoordsToDisplayCoords = function(x, y) {
|
|
12599
|
-
var p1 = _ext.translatePixelCoords(x, y);
|
|
12600
|
-
var p2 = _ext.translatePixelCoords(x+1, y+1);
|
|
12601
|
-
var crs = this.getDisplayCRS();
|
|
12602
|
-
if (crs) {
|
|
12603
|
-
p1 = internal.toLngLat(p1, crs) || p1;
|
|
12604
|
-
p2 = internal.toLngLat(p2, crs) || p2;
|
|
12605
|
-
}
|
|
12606
|
-
return formatCoordsForDisplay(p1, p2);
|
|
12607
|
-
};
|
|
12608
|
-
|
|
12609
|
-
// this.getCenterLngLat = function() {
|
|
12610
|
-
// var bounds = _ext.getBounds();
|
|
12611
|
-
// var crs = this.getDisplayCRS();
|
|
12612
|
-
// // TODO: handle case where active layer is a frame layer
|
|
12613
|
-
// if (!bounds.hasBounds() || !crs) {
|
|
12614
|
-
// return null;
|
|
12615
|
-
// }
|
|
12616
|
-
// return internal.toLngLat([bounds.centerX(), bounds.centerY()], crs);
|
|
12617
|
-
// };
|
|
12618
|
-
|
|
12619
|
-
this.getDisplayCRS = function() {
|
|
12620
|
-
if (!_activeLyr) {
|
|
12621
|
-
return _dynamicCRS || internal.parseCrsString('wgs84');
|
|
12622
|
-
}
|
|
12623
|
-
if (!_activeLyr.gui.geographic) {
|
|
12624
|
-
return null;
|
|
12625
|
-
}
|
|
12626
|
-
if (_activeLyr.gui.dynamic_crs) {
|
|
12627
|
-
return _activeLyr.gui.dynamic_crs;
|
|
12628
|
-
}
|
|
12629
|
-
var info = getDatasetCrsInfo(_activeLyr.gui.source.dataset);
|
|
12630
|
-
return info.crs || null;
|
|
12631
|
-
};
|
|
12421
|
+
if (!_activeLyr.gui.geographic) {
|
|
12422
|
+
return null;
|
|
12423
|
+
}
|
|
12424
|
+
if (_activeLyr.gui.dynamic_crs) {
|
|
12425
|
+
return _activeLyr.gui.dynamic_crs;
|
|
12426
|
+
}
|
|
12427
|
+
var info = getDatasetCrsInfo(_activeLyr.gui.source.dataset);
|
|
12428
|
+
return info.crs || null;
|
|
12429
|
+
};
|
|
12632
12430
|
|
|
12633
12431
|
this.getExtent = function() {return _ext;};
|
|
12634
12432
|
this.getMouse = function() {return _mouse;};
|
|
@@ -12694,7 +12492,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12694
12492
|
}
|
|
12695
12493
|
|
|
12696
12494
|
_ext.on('change', function(e) {
|
|
12697
|
-
|
|
12495
|
+
gui?.basemap.refresh(); // keep basemap synced up (if enabled)
|
|
12698
12496
|
drawLayers(e.redraw ? '' : 'nav');
|
|
12699
12497
|
});
|
|
12700
12498
|
|
|
@@ -12773,7 +12571,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12773
12571
|
|
|
12774
12572
|
if (needReset) {
|
|
12775
12573
|
_ext.reset();
|
|
12776
|
-
|
|
12574
|
+
gui?.basemap.refresh();
|
|
12777
12575
|
}
|
|
12778
12576
|
drawLayers();
|
|
12779
12577
|
map.dispatchEvent('updated');
|
|
@@ -13163,6 +12961,293 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
13163
12961
|
return retn;
|
|
13164
12962
|
}
|
|
13165
12963
|
|
|
12964
|
+
function loadScript(url, cb) {
|
|
12965
|
+
var script = document.createElement('script');
|
|
12966
|
+
script.onload = cb;
|
|
12967
|
+
script.src = url;
|
|
12968
|
+
document.head.appendChild(script);
|
|
12969
|
+
}
|
|
12970
|
+
|
|
12971
|
+
function loadStylesheet(url) {
|
|
12972
|
+
var el = document.createElement('link');
|
|
12973
|
+
el.rel = 'stylesheet';
|
|
12974
|
+
el.type = 'text/css';
|
|
12975
|
+
el.media = 'screen';
|
|
12976
|
+
el.href = url;
|
|
12977
|
+
document.head.appendChild(el);
|
|
12978
|
+
}
|
|
12979
|
+
|
|
12980
|
+
function Basemap(gui) {
|
|
12981
|
+
var menu = gui.container.findChild('.basemap-options');
|
|
12982
|
+
var fadeBtn = new SimpleButton(menu.findChild('.fade-btn'));
|
|
12983
|
+
var closeBtn = new SimpleButton(menu.findChild('.close2-btn'));
|
|
12984
|
+
var clearBtn = new SimpleButton(menu.findChild('.clear-btn'));
|
|
12985
|
+
var menuButtons = menu.findChild('.basemap-styles');
|
|
12986
|
+
var overlayButtons = gui.container.findChild('.basemap-overlay-buttons');
|
|
12987
|
+
var container = gui.container.findChild('.basemap-container');
|
|
12988
|
+
var basemapBtn = gui.container.findChild('.basemap-btn');
|
|
12989
|
+
var basemapNote = gui.container.findChild('.basemap-note');
|
|
12990
|
+
var basemapWarning = gui.container.findChild('.basemap-warning');
|
|
12991
|
+
var mapEl = gui.container.findChild('.basemap');
|
|
12992
|
+
var extentNote = El('div').addClass('basemap-prompt').appendTo(container).hide();
|
|
12993
|
+
var params = window.mapboxParams;
|
|
12994
|
+
var map;
|
|
12995
|
+
var activeStyle;
|
|
12996
|
+
var loading = false;
|
|
12997
|
+
var faded = false;
|
|
12998
|
+
|
|
12999
|
+
if (params) {
|
|
13000
|
+
// TODO: check page URL for compatibility with mapbox key
|
|
13001
|
+
init();
|
|
13002
|
+
} else {
|
|
13003
|
+
basemapBtn.hide();
|
|
13004
|
+
}
|
|
13005
|
+
|
|
13006
|
+
function init() {
|
|
13007
|
+
gui.addMode('basemap', turnOn, turnOff, basemapBtn);
|
|
13008
|
+
|
|
13009
|
+
closeBtn.on('click', function() {
|
|
13010
|
+
gui.clearMode();
|
|
13011
|
+
turnOff();
|
|
13012
|
+
});
|
|
13013
|
+
|
|
13014
|
+
clearBtn.on('click', function() {
|
|
13015
|
+
if (activeStyle) {
|
|
13016
|
+
turnOffBasemap();
|
|
13017
|
+
updateButtons();
|
|
13018
|
+
closeMenu();
|
|
13019
|
+
}
|
|
13020
|
+
});
|
|
13021
|
+
|
|
13022
|
+
fadeBtn.on('click', function() {
|
|
13023
|
+
if (faded) {
|
|
13024
|
+
mapEl.css('opacity', 1);
|
|
13025
|
+
faded = false;
|
|
13026
|
+
fadeBtn.text('Fade');
|
|
13027
|
+
} else if (activeStyle) {
|
|
13028
|
+
mapEl.css('opacity', 0.35);
|
|
13029
|
+
faded = true;
|
|
13030
|
+
fadeBtn.text('Unfade');
|
|
13031
|
+
}
|
|
13032
|
+
});
|
|
13033
|
+
|
|
13034
|
+
gui.model.on('update', onUpdate);
|
|
13035
|
+
|
|
13036
|
+
gui.on('map_click', function() {
|
|
13037
|
+
// close menu if user click on the map
|
|
13038
|
+
if (gui.getMode() == 'basemap') gui.clearMode();
|
|
13039
|
+
});
|
|
13040
|
+
|
|
13041
|
+
params.styles.forEach(function(style) {
|
|
13042
|
+
El('div')
|
|
13043
|
+
.html(`<div class="basemap-style-btn"><img src="${style.icon}"></img></div><div class="basemap-style-label">${style.name}</div>`)
|
|
13044
|
+
.appendTo(menuButtons)
|
|
13045
|
+
.findChild('.basemap-style-btn').on('click', onClick);
|
|
13046
|
+
|
|
13047
|
+
El('div').addClass('basemap-overlay-btn basemap-style-btn')
|
|
13048
|
+
.html(`<img src="${style.icon}"></img>`).on('click', onClick)
|
|
13049
|
+
.appendTo(overlayButtons);
|
|
13050
|
+
|
|
13051
|
+
function onClick() {
|
|
13052
|
+
if (overlayButtons.hasClass('disabled')) return;
|
|
13053
|
+
if (style == activeStyle) {
|
|
13054
|
+
turnOffBasemap();
|
|
13055
|
+
} else {
|
|
13056
|
+
showBasemap(style);
|
|
13057
|
+
}
|
|
13058
|
+
updateButtons();
|
|
13059
|
+
closeMenu();
|
|
13060
|
+
}
|
|
13061
|
+
});
|
|
13062
|
+
}
|
|
13063
|
+
|
|
13064
|
+
// close and turn off mode
|
|
13065
|
+
function closeMenu() {
|
|
13066
|
+
setTimeout(function() {
|
|
13067
|
+
gui.clearMode();
|
|
13068
|
+
}, 200);
|
|
13069
|
+
}
|
|
13070
|
+
|
|
13071
|
+
function turnOffBasemap() {
|
|
13072
|
+
activeStyle = null;
|
|
13073
|
+
gui.map.setDisplayCRS(null);
|
|
13074
|
+
refresh();
|
|
13075
|
+
}
|
|
13076
|
+
|
|
13077
|
+
function showBasemap(style) {
|
|
13078
|
+
activeStyle = style;
|
|
13079
|
+
// TODO: consider enabling dark basemap mode
|
|
13080
|
+
// Make sure that the selected layer style gets updated in gui-map.js
|
|
13081
|
+
// gui.state.dark_basemap = style && style.dark || false;
|
|
13082
|
+
if (map) {
|
|
13083
|
+
map.setStyle(style.url);
|
|
13084
|
+
refresh();
|
|
13085
|
+
} else if (prepareMapView()) {
|
|
13086
|
+
initMap();
|
|
13087
|
+
}
|
|
13088
|
+
}
|
|
13089
|
+
|
|
13090
|
+
function updateButtons() {
|
|
13091
|
+
menuButtons.findChildren('.basemap-style-btn').forEach(function(el, i) {
|
|
13092
|
+
el.classed('active', params.styles[i] == activeStyle);
|
|
13093
|
+
});
|
|
13094
|
+
overlayButtons.findChildren('.basemap-style-btn').forEach(function(el, i) {
|
|
13095
|
+
el.classed('active', params.styles[i] == activeStyle);
|
|
13096
|
+
});
|
|
13097
|
+
}
|
|
13098
|
+
|
|
13099
|
+
function turnOn() {
|
|
13100
|
+
onUpdate();
|
|
13101
|
+
menu.show();
|
|
13102
|
+
}
|
|
13103
|
+
|
|
13104
|
+
function onUpdate() {
|
|
13105
|
+
var activeLyr = gui.model.getActiveLayer(); // may be null
|
|
13106
|
+
var info = getDatasetCrsInfo(activeLyr?.dataset); // defaults to wgs84
|
|
13107
|
+
var dataCRS = info.crs || null;
|
|
13108
|
+
var displayCRS = gui.map.getDisplayCRS();
|
|
13109
|
+
var warning, note;
|
|
13110
|
+
|
|
13111
|
+
|
|
13112
|
+
if (!dataCRS || !displayCRS || !crsIsUsable(displayCRS) || !crsIsUsable(dataCRS)) {
|
|
13113
|
+
warning = 'This data is incompatible with the basemaps.';
|
|
13114
|
+
if (!internal.layerHasGeometry(activeLyr.layer)) {
|
|
13115
|
+
warning += ' Reason: layer is missing geographic data';
|
|
13116
|
+
} else if (!dataCRS) {
|
|
13117
|
+
warning += ' Reason: unknown projection.';
|
|
13118
|
+
}
|
|
13119
|
+
basemapWarning.html(warning).show();
|
|
13120
|
+
basemapNote.hide();
|
|
13121
|
+
overlayButtons.addClass('disabled');
|
|
13122
|
+
activeStyle = null;
|
|
13123
|
+
updateButtons();
|
|
13124
|
+
} else {
|
|
13125
|
+
note = `Your data ${activeStyle ? 'is' : 'will be'} displayed using the Mercator projection.`;
|
|
13126
|
+
basemapNote.text(note).show();
|
|
13127
|
+
overlayButtons.show();
|
|
13128
|
+
overlayButtons.removeClass('disabled');
|
|
13129
|
+
}
|
|
13130
|
+
}
|
|
13131
|
+
|
|
13132
|
+
function turnOff() {
|
|
13133
|
+
basemapWarning.hide();
|
|
13134
|
+
basemapNote.hide();
|
|
13135
|
+
menu.hide();
|
|
13136
|
+
}
|
|
13137
|
+
|
|
13138
|
+
function enabled() {
|
|
13139
|
+
return !!(mapEl && params);
|
|
13140
|
+
}
|
|
13141
|
+
|
|
13142
|
+
function show() {
|
|
13143
|
+
gui.container.addClass('basemap-on');
|
|
13144
|
+
mapEl.node().style.display = 'block';
|
|
13145
|
+
}
|
|
13146
|
+
|
|
13147
|
+
function hide() {
|
|
13148
|
+
gui.container.removeClass('basemap-on');
|
|
13149
|
+
mapEl.node().style.display = 'none';
|
|
13150
|
+
}
|
|
13151
|
+
|
|
13152
|
+
function getLonLatBounds() {
|
|
13153
|
+
var ext = gui.map.getExtent();
|
|
13154
|
+
var bbox = ext.getBounds().toArray();
|
|
13155
|
+
var bbox2 = fromWebMercator(bbox[0], bbox[1])
|
|
13156
|
+
.concat(fromWebMercator(bbox[2], bbox[3]));
|
|
13157
|
+
return bbox2;
|
|
13158
|
+
}
|
|
13159
|
+
|
|
13160
|
+
function initMap() {
|
|
13161
|
+
if (!enabled() || map || loading) return;
|
|
13162
|
+
loading = true;
|
|
13163
|
+
loadStylesheet(params.css);
|
|
13164
|
+
loadScript(params.js, function() {
|
|
13165
|
+
map = new window.mapboxgl.Map({
|
|
13166
|
+
accessToken: params.key,
|
|
13167
|
+
logoPosition: 'bottom-left',
|
|
13168
|
+
container: mapEl.node(),
|
|
13169
|
+
style: activeStyle.url,
|
|
13170
|
+
bounds: getLonLatBounds(),
|
|
13171
|
+
doubleClickZoom: false,
|
|
13172
|
+
dragPan: false,
|
|
13173
|
+
dragRotate: false,
|
|
13174
|
+
scrollZoom: false,
|
|
13175
|
+
interactive: false,
|
|
13176
|
+
keyboard: false,
|
|
13177
|
+
maxPitch: 0,
|
|
13178
|
+
renderWorldCopies: true // false // false prevents panning off the map
|
|
13179
|
+
});
|
|
13180
|
+
map.on('load', function() {
|
|
13181
|
+
loading = false;
|
|
13182
|
+
refresh();
|
|
13183
|
+
});
|
|
13184
|
+
});
|
|
13185
|
+
}
|
|
13186
|
+
|
|
13187
|
+
// @bbox: latlon bounding box of current map extent
|
|
13188
|
+
function checkBounds(bbox) {
|
|
13189
|
+
var ext = gui.map.getExtent();
|
|
13190
|
+
var mpp = ext.getBounds().width() / ext.width();
|
|
13191
|
+
var z = scaleToZoom(mpp);
|
|
13192
|
+
var msg;
|
|
13193
|
+
if (bbox[1] >= -85 && bbox[3] <= 85 && z <= 20) {
|
|
13194
|
+
extentNote.hide();
|
|
13195
|
+
return true;
|
|
13196
|
+
}
|
|
13197
|
+
if (z > 20) {
|
|
13198
|
+
msg = 'zoom out';
|
|
13199
|
+
} else if (bbox[1] > 0) {
|
|
13200
|
+
msg = 'pan south';
|
|
13201
|
+
} else if (bbox[3] < 0) {
|
|
13202
|
+
msg = 'pan north';
|
|
13203
|
+
} else {
|
|
13204
|
+
msg = msg = 'zoom in';
|
|
13205
|
+
}
|
|
13206
|
+
extentNote.html(msg + ' to see the basemap').show();
|
|
13207
|
+
return false;
|
|
13208
|
+
}
|
|
13209
|
+
|
|
13210
|
+
function crsIsUsable(crs) {
|
|
13211
|
+
if (!crs) return false;
|
|
13212
|
+
if (!internal.isInvertibleCRS(crs)) return false;
|
|
13213
|
+
return true;
|
|
13214
|
+
}
|
|
13215
|
+
|
|
13216
|
+
function prepareMapView() {
|
|
13217
|
+
var crs = gui.map.getDisplayCRS();
|
|
13218
|
+
if (!crs) return false;
|
|
13219
|
+
if (!internal.isWebMercator(crs)) {
|
|
13220
|
+
gui.map.setDisplayCRS(internal.parseCrsString('webmercator'));
|
|
13221
|
+
}
|
|
13222
|
+
return true;
|
|
13223
|
+
}
|
|
13224
|
+
|
|
13225
|
+
function refresh() {
|
|
13226
|
+
var crs = gui.map.getDisplayCRS();
|
|
13227
|
+
var off = !crs || !enabled() || !map || loading || !activeStyle;
|
|
13228
|
+
fadeBtn.active(!off);
|
|
13229
|
+
clearBtn.active(!off);
|
|
13230
|
+
if (off) {
|
|
13231
|
+
hide();
|
|
13232
|
+
extentNote.hide();
|
|
13233
|
+
return;
|
|
13234
|
+
}
|
|
13235
|
+
|
|
13236
|
+
prepareMapView();
|
|
13237
|
+
var bbox = getLonLatBounds();
|
|
13238
|
+
if (!checkBounds(bbox)) {
|
|
13239
|
+
// map does not display outside these bounds
|
|
13240
|
+
hide();
|
|
13241
|
+
} else {
|
|
13242
|
+
show();
|
|
13243
|
+
map.resize();
|
|
13244
|
+
map.fitBounds(bbox, {animate: false});
|
|
13245
|
+
}
|
|
13246
|
+
}
|
|
13247
|
+
|
|
13248
|
+
return {refresh, show: onUpdate};
|
|
13249
|
+
}
|
|
13250
|
+
|
|
13166
13251
|
function GuiInstance(container, opts) {
|
|
13167
13252
|
var gui = new ModeSwitcher();
|
|
13168
13253
|
opts = utils$1.extend({
|
|
@@ -13180,6 +13265,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
13180
13265
|
gui.model = new Model(gui);
|
|
13181
13266
|
gui.keyboard = new KeyboardEvents(gui);
|
|
13182
13267
|
gui.buttons = new SidebarButtons(gui);
|
|
13268
|
+
gui.basemap = new Basemap(gui);
|
|
13183
13269
|
gui.session = new SessionHistory(gui);
|
|
13184
13270
|
gui.contextMenu = new ContextMenu();
|
|
13185
13271
|
gui.undo = new Undo(gui);
|
|
@@ -13345,6 +13431,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
13345
13431
|
if (dataLoaded) return;
|
|
13346
13432
|
dataLoaded = true;
|
|
13347
13433
|
gui.buttons.show();
|
|
13434
|
+
gui.basemap.show();
|
|
13348
13435
|
El('#mode-buttons').show();
|
|
13349
13436
|
El('#splash-buttons').hide();
|
|
13350
13437
|
El('body').addClass('map-view');
|