mapshaper 0.6.65 → 0.6.67
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 +259 -128
- package/package.json +1 -1
- package/www/index.html +4 -3
- package/www/mapshaper-gui.js +554 -324
- package/www/mapshaper.js +259 -128
- package/www/page.css +11 -4
package/www/mapshaper-gui.js
CHANGED
|
@@ -1714,6 +1714,47 @@
|
|
|
1714
1714
|
}
|
|
1715
1715
|
}
|
|
1716
1716
|
|
|
1717
|
+
function openAddLayerPopup(gui) {
|
|
1718
|
+
var popup = showPopupAlert('', 'Add empty layer');
|
|
1719
|
+
var el = popup.container();
|
|
1720
|
+
el.addClass('option-menu');
|
|
1721
|
+
var html = `<div><input type="text" class="layer-name text-input" placeholder="layer name"></div>
|
|
1722
|
+
<div style="margin: 2px 0 4px;">
|
|
1723
|
+
Type:
|
|
1724
|
+
<label><input type="radio" name="geomtype" checked value="point" class="radio">point</label>
|
|
1725
|
+
<label><input type="radio" name="geomtype" value="polygon" class="radio">polygon</label>
|
|
1726
|
+
<label><input type="radio" name="geomtype" value="polyline" class="radio">line</label>
|
|
1727
|
+
</div>
|
|
1728
|
+
<div tabindex="0" class="btn dialog-btn">Create</div></span>`;
|
|
1729
|
+
el.html(html);
|
|
1730
|
+
var name = el.findChild('.layer-name');
|
|
1731
|
+
name.node().focus();
|
|
1732
|
+
var btn = el.findChild('.btn').on('click', function() {
|
|
1733
|
+
var nameStr = name.node().value.trim();
|
|
1734
|
+
var type = el.findChild('input:checked').node().value;
|
|
1735
|
+
addLayer(gui, nameStr, type);
|
|
1736
|
+
popup.close();
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
function addLayer(gui, name, type) {
|
|
1741
|
+
var targ = gui.model.getActiveLayer();
|
|
1742
|
+
var crsInfo = targ && internal.getDatasetCrsInfo(targ.dataset);
|
|
1743
|
+
var dataset = {
|
|
1744
|
+
layers: [{
|
|
1745
|
+
name: name || undefined,
|
|
1746
|
+
geometry_type: type,
|
|
1747
|
+
shapes: []
|
|
1748
|
+
}],
|
|
1749
|
+
info: {}
|
|
1750
|
+
};
|
|
1751
|
+
if (crsInfo) {
|
|
1752
|
+
internal.setDatasetCrsInfo(dataset, crsInfo);
|
|
1753
|
+
}
|
|
1754
|
+
gui.model.addDataset(dataset);
|
|
1755
|
+
gui.model.updated({select: true});
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1717
1758
|
// @cb function(<FileList>)
|
|
1718
1759
|
function DropControl(gui, el, cb) {
|
|
1719
1760
|
var area = El(el);
|
|
@@ -1832,7 +1873,10 @@
|
|
|
1832
1873
|
new FileChooser('#file-selection-btn', receiveFiles);
|
|
1833
1874
|
new FileChooser('#import-buttons .add-btn', receiveFiles);
|
|
1834
1875
|
new FileChooser('#add-file-btn', receiveFiles);
|
|
1835
|
-
|
|
1876
|
+
new SimpleButton('#add-empty-btn').on('click', function() {
|
|
1877
|
+
gui.clearMode(); // close import dialog
|
|
1878
|
+
openAddLayerPopup(gui);
|
|
1879
|
+
});
|
|
1836
1880
|
initDropArea('#import-quick-drop', true);
|
|
1837
1881
|
initDropArea('#import-drop');
|
|
1838
1882
|
gui.keyboard.onMenuSubmit(El('#import-options'), importQueuedFiles);
|
|
@@ -2040,18 +2084,7 @@
|
|
|
2040
2084
|
return true;
|
|
2041
2085
|
}
|
|
2042
2086
|
|
|
2043
|
-
|
|
2044
|
-
var dataset = {
|
|
2045
|
-
layers: [{
|
|
2046
|
-
name: 'New layer',
|
|
2047
|
-
geometry_type: 'point',
|
|
2048
|
-
shapes: []
|
|
2049
|
-
}],
|
|
2050
|
-
info: {}
|
|
2051
|
-
};
|
|
2052
|
-
model.addDataset(dataset);
|
|
2053
|
-
gui.clearMode();
|
|
2054
|
-
}
|
|
2087
|
+
|
|
2055
2088
|
|
|
2056
2089
|
function filesMayContainPaths(files) {
|
|
2057
2090
|
return utils$1.some(files, function(f) {
|
|
@@ -2565,6 +2598,7 @@
|
|
|
2565
2598
|
}
|
|
2566
2599
|
}
|
|
2567
2600
|
|
|
2601
|
+
// coords: [x, y] point in data CRS (not display CRS)
|
|
2568
2602
|
function setPointCoords(lyr, fid, coords) {
|
|
2569
2603
|
lyr.source.layer.shapes[fid] = coords;
|
|
2570
2604
|
if (isProjectedLayer(lyr)) {
|
|
@@ -2602,7 +2636,7 @@
|
|
|
2602
2636
|
return !!(lyr.source && lyr.invertPoint);
|
|
2603
2637
|
}
|
|
2604
2638
|
|
|
2605
|
-
// Update data coordinates by projecting display coordinates
|
|
2639
|
+
// Update source data coordinates by projecting display coordinates
|
|
2606
2640
|
function updatePointCoords(lyr, fid) {
|
|
2607
2641
|
if (!isProjectedLayer(lyr)) return;
|
|
2608
2642
|
var displayShp = lyr.layer.shapes[fid];
|
|
@@ -3875,7 +3909,7 @@
|
|
|
3875
3909
|
async function exportMenuSelection(targets) {
|
|
3876
3910
|
var opts = getExportOpts();
|
|
3877
3911
|
// note: command line "target" option gets ignored
|
|
3878
|
-
var files = await internal.exportTargetLayers(targets, opts);
|
|
3912
|
+
var files = await internal.exportTargetLayers(model, targets, opts);
|
|
3879
3913
|
gui.session.layersExported(getTargetLayerIds(), getExportOptsAsString());
|
|
3880
3914
|
if (files.length == 1 && checkboxOn(clipboardCheckbox)) {
|
|
3881
3915
|
await saveFileContentToClipboard(files[0].content);
|
|
@@ -4272,6 +4306,7 @@
|
|
|
4272
4306
|
|
|
4273
4307
|
if (opts.pinnable) classes += ' pinnable';
|
|
4274
4308
|
if (map.isActiveLayer(lyr)) classes += ' active';
|
|
4309
|
+
if (lyr.hidden) classes += ' invisible';
|
|
4275
4310
|
if (lyr.pinned) classes += ' pinned';
|
|
4276
4311
|
|
|
4277
4312
|
html = '<!-- ' + lyr.menu_id + '--><div class="' + classes + '">';
|
|
@@ -4350,10 +4385,24 @@
|
|
|
4350
4385
|
// init pin button
|
|
4351
4386
|
GUI.onClick(entry.findChild('img.black-eye'), function(e) {
|
|
4352
4387
|
var target = findLayerById(id);
|
|
4353
|
-
var
|
|
4388
|
+
var lyr = target.layer;
|
|
4389
|
+
var active = map.isActiveLayer(lyr);
|
|
4390
|
+
var hidden = false; // active && lyr.hidden || false;
|
|
4391
|
+
var pinned = false;
|
|
4392
|
+
var unpinned = false;
|
|
4354
4393
|
e.stopPropagation();
|
|
4355
|
-
|
|
4356
|
-
|
|
4394
|
+
if (active) {
|
|
4395
|
+
hidden = !lyr.hidden;
|
|
4396
|
+
pinned = !hidden && lyr.unpinned;
|
|
4397
|
+
unpinned = lyr.pinned && hidden;
|
|
4398
|
+
} else {
|
|
4399
|
+
pinned = !lyr.pinned;
|
|
4400
|
+
}
|
|
4401
|
+
lyr.hidden = hidden;
|
|
4402
|
+
lyr.unpinned = unpinned;
|
|
4403
|
+
map.setLayerPinning(target, pinned);
|
|
4404
|
+
entry.classed('pinned', pinned);
|
|
4405
|
+
entry.classed('invisible', hidden);
|
|
4357
4406
|
updatePinAllButton();
|
|
4358
4407
|
map.redraw();
|
|
4359
4408
|
});
|
|
@@ -4379,12 +4428,16 @@
|
|
|
4379
4428
|
GUI.onClick(entry, function() {
|
|
4380
4429
|
var target = findLayerById(id);
|
|
4381
4430
|
// don't select if user is typing or dragging
|
|
4382
|
-
if (
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4431
|
+
if (GUI.textIsSelected() || dragging) return;
|
|
4432
|
+
// undo any temporary hiding when layer is selected
|
|
4433
|
+
target.layer.hidden = false;
|
|
4434
|
+
if (!map.isActiveLayer(target.layer)) {
|
|
4435
|
+
model.selectLayer(target.layer, target.dataset);
|
|
4387
4436
|
}
|
|
4437
|
+
// close menu after a delay
|
|
4438
|
+
setTimeout(function() {
|
|
4439
|
+
gui.clearMode();
|
|
4440
|
+
}, 230);
|
|
4388
4441
|
});
|
|
4389
4442
|
}
|
|
4390
4443
|
|
|
@@ -4656,6 +4709,19 @@
|
|
|
4656
4709
|
addHistoryState(stashedUndo, redo);
|
|
4657
4710
|
});
|
|
4658
4711
|
|
|
4712
|
+
gui.on('rectangle_dragend', function(e) {
|
|
4713
|
+
var target = e.data.target;
|
|
4714
|
+
var points1 = e.points;
|
|
4715
|
+
var points2 = e.ids.map(id => getVertexCoords(target, id));
|
|
4716
|
+
var undo = function() {
|
|
4717
|
+
setRectangleCoords(target, e.ids, points1);
|
|
4718
|
+
};
|
|
4719
|
+
var redo = function() {
|
|
4720
|
+
setRectangleCoords(target, e.ids, points2);
|
|
4721
|
+
};
|
|
4722
|
+
addHistoryState(undo, redo);
|
|
4723
|
+
});
|
|
4724
|
+
|
|
4659
4725
|
gui.on('vertex_dragend', function(e) {
|
|
4660
4726
|
var target = e.data.target;
|
|
4661
4727
|
var startPoint = e.points[0]; // in data coords
|
|
@@ -4701,6 +4767,9 @@
|
|
|
4701
4767
|
}
|
|
4702
4768
|
|
|
4703
4769
|
this.undo = function() {
|
|
4770
|
+
// firing even if history is empty
|
|
4771
|
+
// (because this event may trigger a new history state)
|
|
4772
|
+
gui.dispatchEvent('undo_redo_pre');
|
|
4704
4773
|
var item = getHistoryItem();
|
|
4705
4774
|
if (item) {
|
|
4706
4775
|
offset++;
|
|
@@ -4710,6 +4779,7 @@
|
|
|
4710
4779
|
};
|
|
4711
4780
|
|
|
4712
4781
|
this.redo = function() {
|
|
4782
|
+
gui.dispatchEvent('undo_redo_pre');
|
|
4713
4783
|
if (offset <= 0) return;
|
|
4714
4784
|
offset--;
|
|
4715
4785
|
var item = getHistoryItem();
|
|
@@ -4783,6 +4853,30 @@
|
|
|
4783
4853
|
});
|
|
4784
4854
|
}
|
|
4785
4855
|
|
|
4856
|
+
function ToggleButton(el) {
|
|
4857
|
+
var btn = El(el),
|
|
4858
|
+
self = new EventDispatcher(),
|
|
4859
|
+
on = false;
|
|
4860
|
+
|
|
4861
|
+
btn.on('click', function(e) {
|
|
4862
|
+
on = !on;
|
|
4863
|
+
btn.classed('active', on);
|
|
4864
|
+
self.dispatchEvent('click', {on: on, active: on});
|
|
4865
|
+
});
|
|
4866
|
+
|
|
4867
|
+
self.turnOff = function() {
|
|
4868
|
+
on = false;
|
|
4869
|
+
btn.removeClass('active');
|
|
4870
|
+
};
|
|
4871
|
+
|
|
4872
|
+
self.turnOn = function() {
|
|
4873
|
+
on = true;
|
|
4874
|
+
btn.addClass('active');
|
|
4875
|
+
};
|
|
4876
|
+
|
|
4877
|
+
return self;
|
|
4878
|
+
}
|
|
4879
|
+
|
|
4786
4880
|
function ModeSwitcher() {
|
|
4787
4881
|
var self = this;
|
|
4788
4882
|
var mode = null;
|
|
@@ -4872,11 +4966,10 @@
|
|
|
4872
4966
|
standard: ['info', 'selection', 'data', 'box'],
|
|
4873
4967
|
polygons: ['info', 'selection', 'data', 'box', 'vertices'],
|
|
4874
4968
|
rectangles: ['info', 'selection', 'data', 'box', 'rectangles', 'vertices'],
|
|
4875
|
-
lines: ['info', 'selection', 'data', 'box', 'vertices'],
|
|
4969
|
+
lines: ['info', 'selection', 'data', 'box', 'vertices' /*, 'draw-lines'*/],
|
|
4876
4970
|
table: ['info', 'selection', 'data'],
|
|
4877
|
-
labels: ['info', 'selection', 'data', 'box', 'labels', 'location'],
|
|
4878
|
-
|
|
4879
|
-
points: ['info', 'selection', 'data', 'box', 'location']
|
|
4971
|
+
labels: ['info', 'selection', 'data', 'box', 'labels', 'location', 'add-points'],
|
|
4972
|
+
points: ['info', 'selection', 'data', 'box', 'location', 'add-points']
|
|
4880
4973
|
};
|
|
4881
4974
|
|
|
4882
4975
|
var prompts = {
|
|
@@ -4895,6 +4988,7 @@
|
|
|
4895
4988
|
vertices: 'edit vertices',
|
|
4896
4989
|
selection: 'select features',
|
|
4897
4990
|
'add-points': 'add points',
|
|
4991
|
+
'draw-lines': 'draw lines',
|
|
4898
4992
|
rectangles: 'drag-to-resize',
|
|
4899
4993
|
off: 'turn off'
|
|
4900
4994
|
};
|
|
@@ -5138,7 +5232,9 @@
|
|
|
5138
5232
|
};
|
|
5139
5233
|
|
|
5140
5234
|
self.selectLayer = function(lyr, dataset) {
|
|
5141
|
-
if (self.getActiveLayer().layer == lyr)
|
|
5235
|
+
if (self.getActiveLayer().layer == lyr) {
|
|
5236
|
+
return;
|
|
5237
|
+
}
|
|
5142
5238
|
self.setDefaultTarget([lyr], dataset);
|
|
5143
5239
|
self.updated({select: true});
|
|
5144
5240
|
gui.session.setTargetLayer(lyr);
|
|
@@ -6844,7 +6940,6 @@
|
|
|
6844
6940
|
return internal.svg.getTransform(p, scale);
|
|
6845
6941
|
}
|
|
6846
6942
|
|
|
6847
|
-
|
|
6848
6943
|
function repositionSymbols(elements, layer, ext) {
|
|
6849
6944
|
var el, idx, shp, p, displayOn, inView, displayBounds;
|
|
6850
6945
|
for (var i=0, n=elements.length; i<n; i++) {
|
|
@@ -6868,7 +6963,7 @@
|
|
|
6868
6963
|
}
|
|
6869
6964
|
}
|
|
6870
6965
|
|
|
6871
|
-
function renderSymbols(lyr, ext
|
|
6966
|
+
function renderSymbols(lyr, ext) {
|
|
6872
6967
|
var records = lyr.data.getRecords();
|
|
6873
6968
|
var symbols = lyr.shapes.map(function(shp, i) {
|
|
6874
6969
|
var d = records[i];
|
|
@@ -6976,6 +7071,8 @@
|
|
|
6976
7071
|
var interactionMode;
|
|
6977
7072
|
var targetLayer;
|
|
6978
7073
|
var hitTest;
|
|
7074
|
+
var pinnedOn; // used in multi-edit mode (selection) for toggling pinning behavior
|
|
7075
|
+
|
|
6979
7076
|
// event priority is higher than navigation, so stopping propagation disables
|
|
6980
7077
|
// pan navigation
|
|
6981
7078
|
var priority = 2;
|
|
@@ -7034,6 +7131,7 @@
|
|
|
7034
7131
|
updateSelectionState(null); // no hit data, no event
|
|
7035
7132
|
active = false;
|
|
7036
7133
|
hitTest = null;
|
|
7134
|
+
pinnedOn = false;
|
|
7037
7135
|
}
|
|
7038
7136
|
}
|
|
7039
7137
|
|
|
@@ -7070,6 +7168,13 @@
|
|
|
7070
7168
|
updateSelectionState({ids: ids});
|
|
7071
7169
|
};
|
|
7072
7170
|
|
|
7171
|
+
self.setPinning = function(val) {
|
|
7172
|
+
if (pinnedOn != val) {
|
|
7173
|
+
pinnedOn = val;
|
|
7174
|
+
triggerHitEvent('change');
|
|
7175
|
+
}
|
|
7176
|
+
};
|
|
7177
|
+
|
|
7073
7178
|
self.setTransientIds = function(ids) {
|
|
7074
7179
|
// turnOn('selection');
|
|
7075
7180
|
transientIds = ids || [];
|
|
@@ -7139,7 +7244,7 @@
|
|
|
7139
7244
|
// make sure popup is unpinned and turned off when switching editing modes
|
|
7140
7245
|
// (some modes do not support pinning)
|
|
7141
7246
|
gui.on('interaction_mode_change', function(e) {
|
|
7142
|
-
|
|
7247
|
+
self.clearSelection();
|
|
7143
7248
|
// if (e.mode == 'off' || e.mode == 'box') {
|
|
7144
7249
|
if (gui.interaction.modeUsesSelection(e.mode)) {
|
|
7145
7250
|
turnOn(e.mode);
|
|
@@ -7148,7 +7253,11 @@
|
|
|
7148
7253
|
}
|
|
7149
7254
|
});
|
|
7150
7255
|
|
|
7151
|
-
gui.on('
|
|
7256
|
+
gui.on('undo_redo_pre', function() {
|
|
7257
|
+
self.clearSelection();
|
|
7258
|
+
});
|
|
7259
|
+
|
|
7260
|
+
gui.on('shift_drag_start', function() {
|
|
7152
7261
|
self.clearHover();
|
|
7153
7262
|
});
|
|
7154
7263
|
|
|
@@ -7300,6 +7409,9 @@
|
|
|
7300
7409
|
if (transientIds.length) {
|
|
7301
7410
|
eventData.ids = utils$1.uniq(transientIds.concat(eventData.ids || []));
|
|
7302
7411
|
}
|
|
7412
|
+
if (pinnedOn) {
|
|
7413
|
+
eventData.pinned = true;
|
|
7414
|
+
}
|
|
7303
7415
|
self.dispatchEvent(type, eventData);
|
|
7304
7416
|
}
|
|
7305
7417
|
|
|
@@ -7801,13 +7913,19 @@
|
|
|
7801
7913
|
|
|
7802
7914
|
function HighlightBox(gui, optsArg) {
|
|
7803
7915
|
var el = El('div').addClass('zoom-box').appendTo('body'),
|
|
7804
|
-
opts = Object.assign({
|
|
7916
|
+
opts = Object.assign({
|
|
7917
|
+
name: 'box',
|
|
7918
|
+
handles: false,
|
|
7919
|
+
persistent: false,
|
|
7920
|
+
draggable: false // does dragging the map draw a box
|
|
7921
|
+
}, optsArg),
|
|
7805
7922
|
box = new EventDispatcher(),
|
|
7806
7923
|
stroke = 2,
|
|
7807
7924
|
activeHandle = null,
|
|
7808
7925
|
prevXY = null,
|
|
7809
7926
|
boxCoords = null,
|
|
7810
7927
|
_on = false,
|
|
7928
|
+
_visible = false,
|
|
7811
7929
|
handles;
|
|
7812
7930
|
|
|
7813
7931
|
if (opts.classname) {
|
|
@@ -7817,19 +7935,20 @@
|
|
|
7817
7935
|
el.hide();
|
|
7818
7936
|
|
|
7819
7937
|
gui.on('map_rendered', function() {
|
|
7820
|
-
if (!_on) return;
|
|
7938
|
+
if (!_on || !_visible) return;
|
|
7821
7939
|
redraw();
|
|
7822
7940
|
});
|
|
7823
7941
|
|
|
7824
|
-
gui.on('
|
|
7942
|
+
gui.on('shift_drag', function(e) {
|
|
7825
7943
|
if (!_on) return;
|
|
7944
|
+
if (!opts.draggable) return;
|
|
7826
7945
|
boxCoords = getBoxCoords(e.data);
|
|
7827
7946
|
redraw();
|
|
7828
7947
|
box.dispatchEvent('drag');
|
|
7829
7948
|
});
|
|
7830
7949
|
|
|
7831
|
-
gui.on('
|
|
7832
|
-
if (!_on) return;
|
|
7950
|
+
gui.on('shift_drag_end', function(e) {
|
|
7951
|
+
if (!_on || !_visible || !opts.draggable) return;
|
|
7833
7952
|
boxCoords = getBoxCoords(e.data);
|
|
7834
7953
|
var pix = coordsToPix(boxCoords, gui.map.getExtent());
|
|
7835
7954
|
box.dispatchEvent('dragend', {map_bbox: pix});
|
|
@@ -7851,21 +7970,30 @@
|
|
|
7851
7970
|
});
|
|
7852
7971
|
|
|
7853
7972
|
document.addEventListener('mousemove', function(e) {
|
|
7854
|
-
if (!_on || !activeHandle || !prevXY || !boxCoords) return;
|
|
7973
|
+
if (!_on || !activeHandle || !prevXY || !boxCoords || !_visible) return;
|
|
7855
7974
|
var xy = {x: e.pageX, y: e.pageY};
|
|
7856
7975
|
var scale = gui.map.getExtent().getPixelSize();
|
|
7857
7976
|
var dx = (xy.x - prevXY.x) * scale;
|
|
7858
7977
|
var dy = -(xy.y - prevXY.y) * scale;
|
|
7859
|
-
|
|
7978
|
+
var shifting = activeHandle.col == 'center' && activeHandle.row == 'center';
|
|
7979
|
+
var centered = gui.keyboard.shiftIsPressed() && !shifting;
|
|
7980
|
+
if (activeHandle.col == 'left' || shifting) {
|
|
7860
7981
|
boxCoords[0] += dx;
|
|
7861
|
-
|
|
7982
|
+
if (centered) boxCoords[2] -= dx;
|
|
7983
|
+
}
|
|
7984
|
+
if (activeHandle.col == 'right' || shifting) {
|
|
7862
7985
|
boxCoords[2] += dx;
|
|
7986
|
+
if (centered) boxCoords[0] -= dx;
|
|
7863
7987
|
}
|
|
7864
|
-
if (activeHandle.row == 'top') {
|
|
7988
|
+
if (activeHandle.row == 'top' || shifting) {
|
|
7865
7989
|
boxCoords[3] += dy;
|
|
7866
|
-
|
|
7990
|
+
if (centered) boxCoords[1] -= dy;
|
|
7991
|
+
}
|
|
7992
|
+
if (activeHandle.row == 'bottom' || shifting) {
|
|
7867
7993
|
boxCoords[1] += dy;
|
|
7994
|
+
if (centered) boxCoords[3] -= dy;
|
|
7868
7995
|
}
|
|
7996
|
+
|
|
7869
7997
|
prevXY = xy;
|
|
7870
7998
|
redraw();
|
|
7871
7999
|
box.dispatchEvent('handle_drag');
|
|
@@ -7907,9 +8035,11 @@
|
|
|
7907
8035
|
box.hide = function() {
|
|
7908
8036
|
el.hide();
|
|
7909
8037
|
boxCoords = null;
|
|
8038
|
+
_visible = false;
|
|
7910
8039
|
};
|
|
7911
8040
|
|
|
7912
8041
|
box.show = function(x1, y1, x2, y2) {
|
|
8042
|
+
_visible = true;
|
|
7913
8043
|
var w = Math.abs(x1 - x2),
|
|
7914
8044
|
h = Math.abs(y1 - y2),
|
|
7915
8045
|
props = {
|
|
@@ -7974,7 +8104,7 @@
|
|
|
7974
8104
|
function initHandles(el) {
|
|
7975
8105
|
var handles = [];
|
|
7976
8106
|
for (var i=0; i<9; i++) {
|
|
7977
|
-
if (i == 4) continue;
|
|
8107
|
+
// if (i == 4) continue; // skip middle handle
|
|
7978
8108
|
var c = Math.floor(i / 3);
|
|
7979
8109
|
var r = i % 3;
|
|
7980
8110
|
handles.push({
|
|
@@ -8020,13 +8150,14 @@
|
|
|
8020
8150
|
function MapNav(gui, ext, mouse) {
|
|
8021
8151
|
var wheel = new MouseWheel(mouse),
|
|
8022
8152
|
zoomTween = new Tween(Tween.sineInOut),
|
|
8023
|
-
zoomBox = new HighlightBox(gui), // .addClass('zooming'),
|
|
8024
|
-
|
|
8153
|
+
zoomBox = new HighlightBox(gui, {draggable: true, name: 'zoom-box'}), // .addClass('zooming'),
|
|
8154
|
+
shiftDrag = false,
|
|
8025
8155
|
zoomScaleMultiplier = 1,
|
|
8026
8156
|
inBtn, outBtn,
|
|
8027
8157
|
dragStartEvt,
|
|
8028
8158
|
_fx, _fy; // zoom foci, [0,1]
|
|
8029
8159
|
|
|
8160
|
+
// Was used in old frame view... remove?
|
|
8030
8161
|
this.setZoomFactor = function(k) {
|
|
8031
8162
|
zoomScaleMultiplier = k || 1;
|
|
8032
8163
|
};
|
|
@@ -8071,18 +8202,18 @@
|
|
|
8071
8202
|
if (disabled()) return;
|
|
8072
8203
|
if (!internal.layerHasGeometry(gui.model.getActiveLayer().layer)) return;
|
|
8073
8204
|
// zoomDrag = !!e.metaKey || !!e.ctrlKey; // meta is command on mac, windows key on windows
|
|
8074
|
-
|
|
8075
|
-
if (
|
|
8205
|
+
shiftDrag = !!e.shiftKey;
|
|
8206
|
+
if (shiftDrag) {
|
|
8076
8207
|
if (useBoxZoom()) zoomBox.turnOn();
|
|
8077
8208
|
dragStartEvt = e;
|
|
8078
|
-
gui.dispatchEvent('
|
|
8209
|
+
gui.dispatchEvent('shift_drag_start');
|
|
8079
8210
|
}
|
|
8080
8211
|
});
|
|
8081
8212
|
|
|
8082
8213
|
mouse.on('drag', function(e) {
|
|
8083
8214
|
if (disabled()) return;
|
|
8084
|
-
if (
|
|
8085
|
-
gui.dispatchEvent('
|
|
8215
|
+
if (shiftDrag) {
|
|
8216
|
+
gui.dispatchEvent('shift_drag', getBoxData(e));
|
|
8086
8217
|
} else {
|
|
8087
8218
|
ext.pan(e.dx, e.dy);
|
|
8088
8219
|
}
|
|
@@ -8091,9 +8222,9 @@
|
|
|
8091
8222
|
mouse.on('dragend', function(e) {
|
|
8092
8223
|
var bbox;
|
|
8093
8224
|
if (disabled()) return;
|
|
8094
|
-
if (
|
|
8095
|
-
|
|
8096
|
-
gui.dispatchEvent('
|
|
8225
|
+
if (shiftDrag) {
|
|
8226
|
+
shiftDrag = false;
|
|
8227
|
+
gui.dispatchEvent('shift_drag_end', getBoxData(e));
|
|
8097
8228
|
zoomBox.turnOff();
|
|
8098
8229
|
}
|
|
8099
8230
|
});
|
|
@@ -8111,7 +8242,9 @@
|
|
|
8111
8242
|
});
|
|
8112
8243
|
|
|
8113
8244
|
function useBoxZoom() {
|
|
8114
|
-
|
|
8245
|
+
var mode = gui.getMode();
|
|
8246
|
+
var disabled = ['selection_tool', 'box_tool', 'rectangle_tool'].includes(mode);
|
|
8247
|
+
return !disabled;
|
|
8115
8248
|
}
|
|
8116
8249
|
|
|
8117
8250
|
function getBoxData(e) {
|
|
@@ -8167,7 +8300,7 @@
|
|
|
8167
8300
|
|
|
8168
8301
|
function SelectionTool(gui, ext, hit) {
|
|
8169
8302
|
var popup = gui.container.findChild('.selection-tool-options');
|
|
8170
|
-
var box = new HighlightBox(gui);
|
|
8303
|
+
var box = new HighlightBox(gui, {draggable: true});
|
|
8171
8304
|
var coords = popup.findChild('.box-coords').hide();
|
|
8172
8305
|
var _on = false;
|
|
8173
8306
|
|
|
@@ -8211,6 +8344,7 @@
|
|
|
8211
8344
|
}
|
|
8212
8345
|
|
|
8213
8346
|
function turnOff() {
|
|
8347
|
+
dataBtn.turnOff();
|
|
8214
8348
|
box.turnOff();
|
|
8215
8349
|
reset();
|
|
8216
8350
|
_on = false;
|
|
@@ -8221,10 +8355,17 @@
|
|
|
8221
8355
|
}
|
|
8222
8356
|
|
|
8223
8357
|
function reset() {
|
|
8224
|
-
|
|
8358
|
+
hidePopup();
|
|
8359
|
+
setPinning(false);
|
|
8225
8360
|
hit.clearSelection();
|
|
8226
8361
|
}
|
|
8227
8362
|
|
|
8363
|
+
function setPinning(on) {
|
|
8364
|
+
hit.setPinning(on);
|
|
8365
|
+
if (on) dataBtn.turnOn();
|
|
8366
|
+
else dataBtn.turnOff();
|
|
8367
|
+
}
|
|
8368
|
+
|
|
8228
8369
|
function getIdsOpt() {
|
|
8229
8370
|
return hit.getSelectionIds().join(',');
|
|
8230
8371
|
}
|
|
@@ -8239,11 +8380,15 @@
|
|
|
8239
8380
|
popup.show();
|
|
8240
8381
|
updateCoords();
|
|
8241
8382
|
} else {
|
|
8242
|
-
|
|
8243
|
-
hideCoords();
|
|
8383
|
+
hidePopup();
|
|
8244
8384
|
}
|
|
8245
8385
|
});
|
|
8246
8386
|
|
|
8387
|
+
function hidePopup() {
|
|
8388
|
+
popup.hide();
|
|
8389
|
+
hideCoords();
|
|
8390
|
+
}
|
|
8391
|
+
|
|
8247
8392
|
new SimpleButton(popup.findChild('.delete-btn')).on('click', function() {
|
|
8248
8393
|
var cmd = '-filter invert ids=' + getIdsOpt();
|
|
8249
8394
|
runCommand(cmd);
|
|
@@ -8259,6 +8404,10 @@
|
|
|
8259
8404
|
runCommand(cmd);
|
|
8260
8405
|
});
|
|
8261
8406
|
|
|
8407
|
+
var dataBtn = new ToggleButton(popup.findChild('.data-btn')).on('click', function(e) {
|
|
8408
|
+
setPinning(e.on);
|
|
8409
|
+
});
|
|
8410
|
+
|
|
8262
8411
|
new SimpleButton(popup.findChild('.duplicate-btn')).on('click', function() {
|
|
8263
8412
|
var cmd = '-filter + name=selection ids=' + getIdsOpt();
|
|
8264
8413
|
runCommand(cmd);
|
|
@@ -8296,19 +8445,19 @@
|
|
|
8296
8445
|
hideCoords();
|
|
8297
8446
|
return;
|
|
8298
8447
|
}
|
|
8299
|
-
El(coordsBtn.node()).addClass('
|
|
8448
|
+
El(coordsBtn.node()).addClass('active');
|
|
8300
8449
|
coords.text(bbox.join(','));
|
|
8301
8450
|
coords.show();
|
|
8302
8451
|
GUI.selectElement(coords.node());
|
|
8303
8452
|
}
|
|
8304
8453
|
|
|
8305
8454
|
function hideCoords() {
|
|
8306
|
-
El(coordsBtn.node()).removeClass('
|
|
8455
|
+
El(coordsBtn.node()).removeClass('active');
|
|
8307
8456
|
coords.hide();
|
|
8308
8457
|
}
|
|
8309
8458
|
|
|
8310
8459
|
function runCommand(cmd, turnOff) {
|
|
8311
|
-
|
|
8460
|
+
hidePopup();
|
|
8312
8461
|
gui.quiet(true);
|
|
8313
8462
|
if (gui.console) gui.console.runMapshaperCommands(cmd, function(err) {
|
|
8314
8463
|
gui.quiet(false);
|
|
@@ -8318,6 +8467,55 @@
|
|
|
8318
8467
|
}
|
|
8319
8468
|
}
|
|
8320
8469
|
|
|
8470
|
+
function openAddFieldPopup(gui, ids, lyr) {
|
|
8471
|
+
var popup = showPopupAlert('', 'Add field');
|
|
8472
|
+
var el = popup.container();
|
|
8473
|
+
el.addClass('option-menu');
|
|
8474
|
+
var html = `<div><input type="text" class="field-name text-input" placeholder="field name"></div>
|
|
8475
|
+
<div><input type="text" class="field-value text-input" placeholder="value"><div>
|
|
8476
|
+
<div tabindex="0" class="btn dialog-btn">Apply</div> <span class="inline-checkbox"><input type="checkbox" class="all" />assign value to all records</span>`;
|
|
8477
|
+
el.html(html);
|
|
8478
|
+
|
|
8479
|
+
var name = el.findChild('.field-name');
|
|
8480
|
+
name.node().focus();
|
|
8481
|
+
var val = el.findChild('.field-value');
|
|
8482
|
+
var box = el.findChild('.all');
|
|
8483
|
+
var btn = el.findChild('.btn').on('click', function() {
|
|
8484
|
+
var table = internal.getLayerDataTable(lyr); // creates new table if missing
|
|
8485
|
+
var all = box.node().checked;
|
|
8486
|
+
var nameStr = name.node().value.trim();
|
|
8487
|
+
if (!nameStr) return;
|
|
8488
|
+
if (table.fieldExists(nameStr)) {
|
|
8489
|
+
name.node().value = '';
|
|
8490
|
+
return;
|
|
8491
|
+
}
|
|
8492
|
+
var valStr = val.node().value.trim();
|
|
8493
|
+
var value = internal.parseUnknownType(valStr);
|
|
8494
|
+
// table.addField(nameStr, function(d) {
|
|
8495
|
+
// // parse each time to avoid multiple references to objects
|
|
8496
|
+
// return (all || d == rec) ? parseUnknownType(valStr) : null;
|
|
8497
|
+
// });
|
|
8498
|
+
|
|
8499
|
+
var cmdStr = `-each "d['${nameStr}'] = `;
|
|
8500
|
+
if (!all) {
|
|
8501
|
+
cmdStr += ids.length == 1 ?
|
|
8502
|
+
`this.id != ${ids[0]}` :
|
|
8503
|
+
`!${JSON.stringify(ids)}.includes(this.id)`;
|
|
8504
|
+
cmdStr += ' ? null : ';
|
|
8505
|
+
}
|
|
8506
|
+
valStr = JSON.stringify(JSON.stringify(value)); // add escapes to strings
|
|
8507
|
+
cmdStr = valStr.replace('"', cmdStr);
|
|
8508
|
+
|
|
8509
|
+
gui.console.runMapshaperCommands(cmdStr, function(err) {
|
|
8510
|
+
if (!err) {
|
|
8511
|
+
popup.close();
|
|
8512
|
+
} else {
|
|
8513
|
+
console.error(err);
|
|
8514
|
+
}
|
|
8515
|
+
});
|
|
8516
|
+
});
|
|
8517
|
+
}
|
|
8518
|
+
|
|
8321
8519
|
// toNext, toPrev: trigger functions for switching between multiple records
|
|
8322
8520
|
function Popup(gui, toNext, toPrev) {
|
|
8323
8521
|
var self = new EventDispatcher();
|
|
@@ -8331,7 +8529,6 @@
|
|
|
8331
8529
|
var navInfo = El('span').addClass('popup-nav-info').appendTo(nav);
|
|
8332
8530
|
var nextLink = El('span').addClass('popup-nav-arrow colored-text').appendTo(nav).text('▶');
|
|
8333
8531
|
var refresh = null;
|
|
8334
|
-
var currIds = [];
|
|
8335
8532
|
|
|
8336
8533
|
el.addClass('rollover'); // used as a sentinel for the hover function
|
|
8337
8534
|
|
|
@@ -8342,16 +8539,20 @@
|
|
|
8342
8539
|
});
|
|
8343
8540
|
|
|
8344
8541
|
self.show = function(id, ids, lyr, pinned) {
|
|
8345
|
-
var
|
|
8542
|
+
var singleEdit = pinned && gui.interaction.getMode() == 'data';
|
|
8543
|
+
var multiEdit = pinned && gui.interaction.getMode() == 'selection';
|
|
8346
8544
|
var maxHeight = parent.node().clientHeight - 36;
|
|
8347
|
-
|
|
8545
|
+
var recIds = multiEdit ? ids : [id];
|
|
8546
|
+
|
|
8348
8547
|
// stash a function for refreshing the current popup when data changes
|
|
8349
8548
|
// while the popup is being displayed (e.g. while dragging a label)
|
|
8350
8549
|
refresh = function() {
|
|
8351
|
-
render(content,
|
|
8550
|
+
render(content, recIds, lyr, singleEdit || multiEdit);
|
|
8352
8551
|
};
|
|
8353
8552
|
refresh();
|
|
8354
|
-
if (
|
|
8553
|
+
if (multiEdit) {
|
|
8554
|
+
showRecords(ids.length);
|
|
8555
|
+
} else if (ids && ids.length > 1 && !multiEdit) {
|
|
8355
8556
|
showNav(id, ids, pinned);
|
|
8356
8557
|
} else {
|
|
8357
8558
|
tab.hide();
|
|
@@ -8365,7 +8566,6 @@
|
|
|
8365
8566
|
self.hide = function() {
|
|
8366
8567
|
if (!isOpen()) return;
|
|
8367
8568
|
refresh = null;
|
|
8368
|
-
currIds = [];
|
|
8369
8569
|
// make sure any pending edits are made before re-rendering popup
|
|
8370
8570
|
GUI.blurActiveElement(); // this should be more selective -- could cause a glitch if typing in console
|
|
8371
8571
|
content.empty();
|
|
@@ -8379,6 +8579,13 @@
|
|
|
8379
8579
|
return el.visible();
|
|
8380
8580
|
}
|
|
8381
8581
|
|
|
8582
|
+
function showRecords(n) {
|
|
8583
|
+
navInfo.text(n);
|
|
8584
|
+
nextLink.css('display','none');
|
|
8585
|
+
prevLink.css('display','none');
|
|
8586
|
+
tab.show();
|
|
8587
|
+
}
|
|
8588
|
+
|
|
8382
8589
|
function showNav(id, ids, pinned) {
|
|
8383
8590
|
var num = ids.indexOf(id) + 1;
|
|
8384
8591
|
navInfo.text(' ' + num + ' / ' + ids.length + ' ');
|
|
@@ -8387,28 +8594,12 @@
|
|
|
8387
8594
|
tab.show();
|
|
8388
8595
|
}
|
|
8389
8596
|
|
|
8390
|
-
function render(el,
|
|
8391
|
-
var recIds = [recId]; // TODO: support multiple ids
|
|
8597
|
+
function render(el, recIds, lyr, editable) {
|
|
8392
8598
|
var table = lyr.data; // table can be null (e.g. if layer has no attribute data)
|
|
8393
|
-
var
|
|
8394
|
-
var tableEl = El('table').addClass('selectable'),
|
|
8395
|
-
rows = 0;
|
|
8396
|
-
// self.hide(); // clean up if panel is already open
|
|
8599
|
+
var tableEl = table ? renderTable(recIds, table, editable) : null;
|
|
8397
8600
|
el.empty(); // clean up if panel is already open
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
// missing GeoJSON fields are set to undefined on import; skip these
|
|
8401
|
-
if (v !== undefined) {
|
|
8402
|
-
type = getFieldType(v, k, table);
|
|
8403
|
-
renderRow(tableEl, rec, k, type, editable);
|
|
8404
|
-
rows++;
|
|
8405
|
-
}
|
|
8406
|
-
});
|
|
8407
|
-
|
|
8408
|
-
tableEl.appendTo(el);
|
|
8409
|
-
if (rows > 0) {
|
|
8410
|
-
// tableEl.appendTo(el);
|
|
8411
|
-
|
|
8601
|
+
if (tableEl) {
|
|
8602
|
+
tableEl.appendTo(el);
|
|
8412
8603
|
tableEl.on('copy', function(e) {
|
|
8413
8604
|
// remove leading or trailing tabs that sometimes get copied when
|
|
8414
8605
|
// selecting from a table
|
|
@@ -8419,7 +8610,6 @@
|
|
|
8419
8610
|
e.preventDefault(); // don't copy original string with tabs
|
|
8420
8611
|
}
|
|
8421
8612
|
});
|
|
8422
|
-
|
|
8423
8613
|
} else {
|
|
8424
8614
|
// Some individual features can have undefined values for some or all of
|
|
8425
8615
|
// their data properties (properties are set to undefined when an input JSON file
|
|
@@ -8433,72 +8623,65 @@
|
|
|
8433
8623
|
var line = El('div').appendTo(el);
|
|
8434
8624
|
El('span').addClass('add-field-btn').appendTo(line).on('click', async function(e) {
|
|
8435
8625
|
// show "add field" dialog
|
|
8436
|
-
|
|
8626
|
+
openAddFieldPopup(gui, recIds, lyr);
|
|
8437
8627
|
}).text('+ add field');
|
|
8438
8628
|
}
|
|
8439
8629
|
}
|
|
8440
8630
|
|
|
8441
|
-
function
|
|
8442
|
-
var
|
|
8443
|
-
var
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8448
|
-
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
|
|
8455
|
-
var
|
|
8456
|
-
|
|
8457
|
-
|
|
8458
|
-
|
|
8459
|
-
if (table.fieldExists(nameStr)) {
|
|
8460
|
-
name.node().value = '';
|
|
8461
|
-
return;
|
|
8631
|
+
function renderTable(recIds, table, editable) {
|
|
8632
|
+
var tableEl = El('table').addClass('selectable');
|
|
8633
|
+
var rows = 0;
|
|
8634
|
+
var rec;
|
|
8635
|
+
if (recIds.length == 1) {
|
|
8636
|
+
rec = editable ?
|
|
8637
|
+
table.getReadOnlyRecordAt(recIds[0]) :
|
|
8638
|
+
table.getRecordAt(recIds[0]);
|
|
8639
|
+
} else {
|
|
8640
|
+
rec = getMultiRecord(recIds, table);
|
|
8641
|
+
}
|
|
8642
|
+
utils$1.forEachProperty(rec, function(v, k) {
|
|
8643
|
+
// missing GeoJSON fields are set to undefined on import; skip these
|
|
8644
|
+
if (v === undefined) return;
|
|
8645
|
+
var rowEl = renderRow(k, v, recIds, table, editable);
|
|
8646
|
+
if (rowEl) {
|
|
8647
|
+
rowEl.appendTo(tableEl);
|
|
8648
|
+
rows++;
|
|
8462
8649
|
}
|
|
8463
|
-
|
|
8464
|
-
|
|
8465
|
-
|
|
8466
|
-
|
|
8467
|
-
|
|
8468
|
-
|
|
8469
|
-
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8476
|
-
|
|
8477
|
-
|
|
8478
|
-
|
|
8479
|
-
|
|
8480
|
-
gui.console.runMapshaperCommands(cmdStr, function(err) {
|
|
8481
|
-
if (!err) {
|
|
8482
|
-
popup.close();
|
|
8483
|
-
} else {
|
|
8484
|
-
console.error(err);
|
|
8650
|
+
});
|
|
8651
|
+
return rows > 0 ? tableEl : null;
|
|
8652
|
+
}
|
|
8653
|
+
|
|
8654
|
+
function getMultiRecord(recIds, table) {
|
|
8655
|
+
var fields = table.getFields();
|
|
8656
|
+
var rec = {};
|
|
8657
|
+
recIds.forEach(function(id) {
|
|
8658
|
+
var d = table.getRecordAt(id) || {};
|
|
8659
|
+
var k, v;
|
|
8660
|
+
for (var i=0; i<fields.length; i++) {
|
|
8661
|
+
k = fields[i];
|
|
8662
|
+
v = d[k];
|
|
8663
|
+
if (k in rec === false) {
|
|
8664
|
+
rec[k] = v;
|
|
8665
|
+
} else if (rec[k] !== v) {
|
|
8666
|
+
rec[k] = null;
|
|
8485
8667
|
}
|
|
8486
|
-
}
|
|
8668
|
+
}
|
|
8487
8669
|
});
|
|
8670
|
+
return rec;
|
|
8488
8671
|
}
|
|
8489
8672
|
|
|
8490
|
-
|
|
8491
|
-
|
|
8673
|
+
|
|
8674
|
+
function renderRow(key, val, recIds, table, editable) {
|
|
8675
|
+
var type = getFieldType(val, key, table);
|
|
8492
8676
|
var str = formatInspectorValue(val, type);
|
|
8493
8677
|
var rowHtml = `<td class="field-name">${key}</td><td><span class="value">${utils$1.htmlEscape(str)}</span> </td>`;
|
|
8494
|
-
var
|
|
8495
|
-
|
|
8496
|
-
|
|
8497
|
-
.findChild('.value');
|
|
8498
|
-
setFieldClass(cell, val, type);
|
|
8678
|
+
var rowEl = El('tr').html(rowHtml);
|
|
8679
|
+
var cellEl = rowEl.findChild('.value');
|
|
8680
|
+
setFieldClass(cellEl, val, type);
|
|
8499
8681
|
if (editable) {
|
|
8500
|
-
editItem(
|
|
8682
|
+
editItem(cellEl, key, val, recIds, table, type);
|
|
8501
8683
|
}
|
|
8684
|
+
return rowEl;
|
|
8502
8685
|
}
|
|
8503
8686
|
|
|
8504
8687
|
function setFieldClass(el, val, type) {
|
|
@@ -8511,10 +8694,10 @@
|
|
|
8511
8694
|
el.classed('empty', isEmpty);
|
|
8512
8695
|
}
|
|
8513
8696
|
|
|
8514
|
-
function editItem(el,
|
|
8697
|
+
function editItem(el, key, val, recIds, table, type) {
|
|
8515
8698
|
var input = new ClickText2(el),
|
|
8516
|
-
strval = formatInspectorValue(
|
|
8517
|
-
parser = getInputParser(type);
|
|
8699
|
+
strval = formatInspectorValue(val, type),
|
|
8700
|
+
parser = internal.getInputParser(type);
|
|
8518
8701
|
el.parent().addClass('editable-cell');
|
|
8519
8702
|
el.addClass('colored-text dot-underline');
|
|
8520
8703
|
input.on('change', function(e) {
|
|
@@ -8526,17 +8709,27 @@
|
|
|
8526
8709
|
} else if (strval != strval2) {
|
|
8527
8710
|
// field content has changed
|
|
8528
8711
|
strval = strval2;
|
|
8529
|
-
gui.dispatchEvent('data_preupdate', {ids:
|
|
8530
|
-
rec[key] = val2;
|
|
8531
|
-
|
|
8712
|
+
gui.dispatchEvent('data_preupdate', {ids: recIds}); // for undo/redo
|
|
8713
|
+
// rec[key] = val2;
|
|
8714
|
+
updateRecords(recIds, key, val2, table);
|
|
8715
|
+
gui.dispatchEvent('data_postupdate', {ids: recIds});
|
|
8532
8716
|
input.value(strval);
|
|
8533
8717
|
setFieldClass(el, val2, type);
|
|
8534
|
-
self.dispatchEvent('data_updated', {field: key, value: val2, ids:
|
|
8718
|
+
self.dispatchEvent('data_updated', {field: key, value: val2, ids: recIds});
|
|
8535
8719
|
}
|
|
8536
8720
|
});
|
|
8537
8721
|
}
|
|
8538
8722
|
}
|
|
8539
8723
|
|
|
8724
|
+
function updateRecords(ids, f, v, table) {
|
|
8725
|
+
var records = table.getRecords();
|
|
8726
|
+
ids.forEach(function(id) {
|
|
8727
|
+
var d = records[id] || {};
|
|
8728
|
+
d[f] = v;
|
|
8729
|
+
records[id] = d;
|
|
8730
|
+
});
|
|
8731
|
+
}
|
|
8732
|
+
|
|
8540
8733
|
function formatInspectorValue(val, type) {
|
|
8541
8734
|
var str;
|
|
8542
8735
|
if (type == 'date') {
|
|
@@ -8549,60 +8742,10 @@
|
|
|
8549
8742
|
return str;
|
|
8550
8743
|
}
|
|
8551
8744
|
|
|
8552
|
-
var inputParsers = {
|
|
8553
|
-
date: function(raw) {
|
|
8554
|
-
var d = new Date(raw);
|
|
8555
|
-
return isNaN(+d) ? null : d;
|
|
8556
|
-
},
|
|
8557
|
-
string: function(raw) {
|
|
8558
|
-
return raw;
|
|
8559
|
-
},
|
|
8560
|
-
number: function(raw) {
|
|
8561
|
-
var val = Number(raw);
|
|
8562
|
-
if (raw == 'NaN') {
|
|
8563
|
-
val = NaN;
|
|
8564
|
-
} else if (isNaN(val)) {
|
|
8565
|
-
val = null;
|
|
8566
|
-
}
|
|
8567
|
-
return val;
|
|
8568
|
-
},
|
|
8569
|
-
object: function(raw) {
|
|
8570
|
-
var val = null;
|
|
8571
|
-
try {
|
|
8572
|
-
val = JSON.parse(raw);
|
|
8573
|
-
} catch(e) {}
|
|
8574
|
-
return val;
|
|
8575
|
-
},
|
|
8576
|
-
boolean: function(raw) {
|
|
8577
|
-
var val = null;
|
|
8578
|
-
if (raw == 'true') {
|
|
8579
|
-
val = true;
|
|
8580
|
-
} else if (raw == 'false') {
|
|
8581
|
-
val = false;
|
|
8582
|
-
}
|
|
8583
|
-
return val;
|
|
8584
|
-
},
|
|
8585
|
-
multiple: function(raw) {
|
|
8586
|
-
var val = Number(raw);
|
|
8587
|
-
return isNaN(val) ? raw : val;
|
|
8588
|
-
}
|
|
8589
|
-
};
|
|
8590
|
-
|
|
8591
|
-
function parseUnknownType(str) {
|
|
8592
|
-
var val = inputParsers.number(str);
|
|
8593
|
-
if (val !== null) return val;
|
|
8594
|
-
val = inputParsers.object(str);
|
|
8595
|
-
if (val !== null) return val;
|
|
8596
|
-
return str;
|
|
8597
|
-
}
|
|
8598
|
-
|
|
8599
|
-
function getInputParser(type) {
|
|
8600
|
-
return inputParsers[type || 'multiple'];
|
|
8601
|
-
}
|
|
8602
8745
|
|
|
8603
8746
|
function getFieldType(val, key, table) {
|
|
8604
8747
|
// if a field has a null value, look at entire column to identify type
|
|
8605
|
-
return internal.getValueType(val) || internal.getColumnType(key, table.getRecords());
|
|
8748
|
+
return internal.getValueType(val) || internal.getColumnType(key, table.getRecords()) ;
|
|
8606
8749
|
}
|
|
8607
8750
|
|
|
8608
8751
|
function InspectionControl2(gui, hit) {
|
|
@@ -8627,16 +8770,20 @@
|
|
|
8627
8770
|
});
|
|
8628
8771
|
|
|
8629
8772
|
hit.on('change', function(e) {
|
|
8630
|
-
var ids;
|
|
8631
8773
|
if (!inspecting()) return;
|
|
8632
|
-
|
|
8633
|
-
|
|
8774
|
+
var ids;
|
|
8775
|
+
if (e.mode == 'selection') {
|
|
8776
|
+
ids = e.pinned && e.ids || [];
|
|
8777
|
+
} else {
|
|
8778
|
+
ids = e.ids || [];
|
|
8779
|
+
}
|
|
8780
|
+
inspect(e.id, ids, e.pinned);
|
|
8634
8781
|
});
|
|
8635
8782
|
|
|
8636
8783
|
// id: Id of a feature in the active layer, or -1
|
|
8637
|
-
function inspect(id,
|
|
8784
|
+
function inspect(id, ids, pin) {
|
|
8638
8785
|
var target = hit.getHitTarget();
|
|
8639
|
-
if (id > -1 && inspecting() && target && target.layer) {
|
|
8786
|
+
if ((id > -1 || ids && ids.length > 0) && inspecting() && target && target.layer) {
|
|
8640
8787
|
_popup.show(id, ids, target.layer, pin);
|
|
8641
8788
|
} else {
|
|
8642
8789
|
_popup.hide();
|
|
@@ -8935,6 +9082,9 @@
|
|
|
8935
9082
|
hit.clearVertexOverlay();
|
|
8936
9083
|
}
|
|
8937
9084
|
|
|
9085
|
+
// return data on the nearest vertex (or identical vertices) to the pointer
|
|
9086
|
+
// (if within a distance threshold)
|
|
9087
|
+
//
|
|
8938
9088
|
function findDraggableVertices(e) {
|
|
8939
9089
|
var target = hit.getHitTarget();
|
|
8940
9090
|
var shp = target.layer.shapes[e.id];
|
|
@@ -9097,35 +9247,6 @@
|
|
|
9097
9247
|
// }
|
|
9098
9248
|
}
|
|
9099
9249
|
|
|
9100
|
-
function initPointDrawing(gui, ext, hit) {
|
|
9101
|
-
function active(e) {
|
|
9102
|
-
return e.id > -1 && gui.interaction.getMode() == 'add-points';
|
|
9103
|
-
}
|
|
9104
|
-
}
|
|
9105
|
-
|
|
9106
|
-
function Pencil(gui, mouse, hit) {
|
|
9107
|
-
var self = this;
|
|
9108
|
-
var _on = false;
|
|
9109
|
-
|
|
9110
|
-
self.turnOn = function() {
|
|
9111
|
-
_on = true;
|
|
9112
|
-
};
|
|
9113
|
-
|
|
9114
|
-
self.turnOff = function() {
|
|
9115
|
-
_on = false;
|
|
9116
|
-
};
|
|
9117
|
-
|
|
9118
|
-
|
|
9119
|
-
|
|
9120
|
-
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
}
|
|
9124
|
-
|
|
9125
|
-
function initDrawing(gui, ext, mouse, hit) {
|
|
9126
|
-
initPointDrawing(gui, new Pencil(gui, mouse, hit));
|
|
9127
|
-
}
|
|
9128
|
-
|
|
9129
9250
|
var darkStroke = "#334",
|
|
9130
9251
|
lightStroke = "#b7d9ea",
|
|
9131
9252
|
violet = "#cc6acc",
|
|
@@ -9452,13 +9573,145 @@
|
|
|
9452
9573
|
return internal.findPropertiesBySymbolGeom(fields, lyr.geometry_type);
|
|
9453
9574
|
}
|
|
9454
9575
|
|
|
9576
|
+
function initPointDrawing(gui, ext, mouse, hit) {
|
|
9577
|
+
|
|
9578
|
+
gui.on('interaction_mode_change', function(e) {
|
|
9579
|
+
gui.container.findChild('.map-layers').classed('add-points', e.mode === 'add-points');
|
|
9580
|
+
});
|
|
9581
|
+
|
|
9582
|
+
function active() {
|
|
9583
|
+
return gui.interaction.getMode() == 'add-points';
|
|
9584
|
+
}
|
|
9585
|
+
|
|
9586
|
+
mouse.on('click', function(e) {
|
|
9587
|
+
if (!active()) return;
|
|
9588
|
+
addPoint(e.x, e.y);
|
|
9589
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
9590
|
+
});
|
|
9591
|
+
|
|
9592
|
+
// x, y: pixel coordinates
|
|
9593
|
+
function addPoint(x, y) {
|
|
9594
|
+
var p = ext.translatePixelCoords(x, y);
|
|
9595
|
+
var target = hit.getHitTarget();
|
|
9596
|
+
var lyr = target.layer;
|
|
9597
|
+
var fid = lyr.shapes.length;
|
|
9598
|
+
var d = lyr.data ? getEmptyDataRecord(lyr.data) : null;
|
|
9599
|
+
if (d) {
|
|
9600
|
+
// this seems to work even for projected layers -- the data tables
|
|
9601
|
+
// of projected and original data seem to be shared.
|
|
9602
|
+
lyr.data.getRecords()[fid] = d;
|
|
9603
|
+
// TODO: handle SVG symbol layer
|
|
9604
|
+
if (internal.layerHasLabels(lyr)) {
|
|
9605
|
+
d['label-text'] = 'TBD'; // without text, new labels will be invisible
|
|
9606
|
+
} else if (layerHasCanvasDisplayStyle(lyr)) {
|
|
9607
|
+
d.r = 3; // show a black circle if layer is styled
|
|
9608
|
+
}
|
|
9609
|
+
}
|
|
9610
|
+
lyr.shapes[fid] = [p];
|
|
9611
|
+
updatePointCoords(target, fid);
|
|
9612
|
+
}
|
|
9613
|
+
|
|
9614
|
+
function getEmptyDataRecord(table) {
|
|
9615
|
+
return table.getFields().reduce(function(memo, name) {
|
|
9616
|
+
memo[name] = null;
|
|
9617
|
+
return memo;
|
|
9618
|
+
}, {});
|
|
9619
|
+
}
|
|
9620
|
+
}
|
|
9621
|
+
|
|
9622
|
+
function initLineDrawing(gui, ext, mouse, hit) {
|
|
9623
|
+
var _on = false;
|
|
9624
|
+
var _coords;
|
|
9625
|
+
var _lastClick;
|
|
9626
|
+
|
|
9627
|
+
gui.on('interaction_mode_change', function(e) {
|
|
9628
|
+
_on = e.mode === 'draw-lines';
|
|
9629
|
+
gui.container.findChild('.map-layers').classed('draw-lines', _on);
|
|
9630
|
+
});
|
|
9631
|
+
|
|
9632
|
+
function active() {
|
|
9633
|
+
return _on;
|
|
9634
|
+
}
|
|
9635
|
+
|
|
9636
|
+
function extending() {
|
|
9637
|
+
return active() && !!_coords;
|
|
9638
|
+
}
|
|
9639
|
+
|
|
9640
|
+
function startPath(e) {
|
|
9641
|
+
|
|
9642
|
+
}
|
|
9643
|
+
|
|
9644
|
+
function extendPath(e) {
|
|
9645
|
+
|
|
9646
|
+
}
|
|
9647
|
+
|
|
9648
|
+
function finishPath() {
|
|
9649
|
+
_coords = null;
|
|
9650
|
+
}
|
|
9651
|
+
|
|
9652
|
+
gui.keyboard.on('keydown', function(evt) {
|
|
9653
|
+
if (!active()) return;
|
|
9654
|
+
if (evt.keyCode == 27) { // esc
|
|
9655
|
+
finishPath();
|
|
9656
|
+
}
|
|
9657
|
+
});
|
|
9658
|
+
|
|
9659
|
+
mouse.on('click', function(e) {
|
|
9660
|
+
if (!active()) return;
|
|
9661
|
+
// console.log('[click]', e)
|
|
9662
|
+
// addPoint(e.x, e.y);
|
|
9663
|
+
// gui.dispatchEvent('map-needs-refresh');
|
|
9664
|
+
_lastClick = e;
|
|
9665
|
+
});
|
|
9666
|
+
|
|
9667
|
+
// note: second click event is fired before this
|
|
9668
|
+
mouse.on('dblclick', function(e) {
|
|
9669
|
+
if (!active()) return;
|
|
9670
|
+
// block navigation
|
|
9671
|
+
e.stopPropagation();
|
|
9672
|
+
finishPath();
|
|
9673
|
+
|
|
9674
|
+
}, null, 3); // hit detection is priority 2
|
|
9675
|
+
|
|
9676
|
+
mouse.on('hover', function(e) {
|
|
9677
|
+
if (!active()) return;
|
|
9678
|
+
});
|
|
9679
|
+
|
|
9680
|
+
// x, y: pixel coordinates
|
|
9681
|
+
function addPoint(x, y) {
|
|
9682
|
+
var p = ext.translatePixelCoords(x, y);
|
|
9683
|
+
var target = hit.getHitTarget();
|
|
9684
|
+
var lyr = target.layer;
|
|
9685
|
+
var fid = lyr.shapes.length;
|
|
9686
|
+
if (lyr.data) {
|
|
9687
|
+
// this seems to work even for projected layers -- the data tables
|
|
9688
|
+
// of projected and original data seem to be shared.
|
|
9689
|
+
lyr.data.getRecords()[fid] = getEmptyDataRecord(lyr.data);
|
|
9690
|
+
}
|
|
9691
|
+
lyr.shapes[fid] = [p];
|
|
9692
|
+
updatePointCoords(target, fid);
|
|
9693
|
+
}
|
|
9694
|
+
|
|
9695
|
+
function getEmptyDataRecord(table) {
|
|
9696
|
+
return table.getFields().reduce(function(memo, name) {
|
|
9697
|
+
memo[name] = null;
|
|
9698
|
+
return memo;
|
|
9699
|
+
}, {});
|
|
9700
|
+
}
|
|
9701
|
+
}
|
|
9702
|
+
|
|
9703
|
+
function initDrawing(gui, ext, mouse, hit) {
|
|
9704
|
+
initPointDrawing(gui, ext, mouse, hit);
|
|
9705
|
+
initLineDrawing(gui, ext, mouse, hit);
|
|
9706
|
+
}
|
|
9707
|
+
|
|
9455
9708
|
function MapExtent(_position) {
|
|
9456
9709
|
var _scale = 1,
|
|
9457
9710
|
_cx, _cy, // center in geographic units
|
|
9458
9711
|
_fullBounds, // full (zoomed-out) content bounds, including any padding
|
|
9459
9712
|
_strictBounds, // full extent must fit inside, if set
|
|
9460
9713
|
_self = this,
|
|
9461
|
-
_frame;
|
|
9714
|
+
_frame; // optional frame data (bbox, width, height)
|
|
9462
9715
|
|
|
9463
9716
|
_position.on('resize', function(e) {
|
|
9464
9717
|
if (ready()) {
|
|
@@ -9576,16 +9829,16 @@
|
|
|
9576
9829
|
return this.getTransform().transform(x, y);
|
|
9577
9830
|
};
|
|
9578
9831
|
|
|
9579
|
-
this.
|
|
9832
|
+
this.setFrameData = function(frame) {
|
|
9580
9833
|
_frame = frame || null;
|
|
9581
9834
|
};
|
|
9582
9835
|
|
|
9583
|
-
this.
|
|
9836
|
+
this.getFrameData = function() {
|
|
9584
9837
|
return _frame || null;
|
|
9585
9838
|
};
|
|
9586
9839
|
|
|
9587
9840
|
this.getSymbolScale = function() {
|
|
9588
|
-
if (!_frame) return
|
|
9841
|
+
if (!_frame) return 1;
|
|
9589
9842
|
var bounds = new Bounds(_frame.bbox);
|
|
9590
9843
|
var bounds2 = bounds.clone().transform(this.getTransform());
|
|
9591
9844
|
return bounds2.width() / _frame.width;
|
|
@@ -10198,12 +10451,12 @@
|
|
|
10198
10451
|
// (style.opacity < 1 ? '~' + style.opacity : '') +
|
|
10199
10452
|
(style.fillPattern ? '~' + style.fillPattern : '');
|
|
10200
10453
|
}
|
|
10201
|
-
|
|
10202
10454
|
return _self;
|
|
10203
10455
|
}
|
|
10204
10456
|
|
|
10205
10457
|
function getScaledLineScale(ext) {
|
|
10206
|
-
|
|
10458
|
+
var previewScale = ext.getSymbolScale();
|
|
10459
|
+
return previewScale == 1 ? getLineScale(ext) : previewScale;
|
|
10207
10460
|
}
|
|
10208
10461
|
|
|
10209
10462
|
// Vary line width according to zoom ratio.
|
|
@@ -10381,7 +10634,8 @@
|
|
|
10381
10634
|
if (pixRatio > 1) {
|
|
10382
10635
|
// bump up thin lines on retina, but not to more than 1px
|
|
10383
10636
|
// (tests on Chrome showed much faster rendering of 1px lines)
|
|
10384
|
-
strokeWidth = strokeWidth < 1 ? 1 : strokeWidth * pixRatio;
|
|
10637
|
+
// strokeWidth = strokeWidth < 1 ? 1 : strokeWidth * pixRatio;
|
|
10638
|
+
strokeWidth = strokeWidth * pixRatio;
|
|
10385
10639
|
}
|
|
10386
10640
|
ctx.lineCap = style.lineCap || 'round';
|
|
10387
10641
|
ctx.lineJoin = style.lineJoin || 'round';
|
|
@@ -10431,7 +10685,7 @@
|
|
|
10431
10685
|
|
|
10432
10686
|
function getSvgFurnitureTransform(ext) {
|
|
10433
10687
|
var scale = ext.getSymbolScale();
|
|
10434
|
-
var frame = ext.
|
|
10688
|
+
var frame = ext.getFrameData();
|
|
10435
10689
|
var p = ext.translateCoords(frame.bbox[0], frame.bbox[3]);
|
|
10436
10690
|
return internal.svg.getTransform(p, scale);
|
|
10437
10691
|
}
|
|
@@ -10442,7 +10696,7 @@
|
|
|
10442
10696
|
}
|
|
10443
10697
|
|
|
10444
10698
|
function renderFurniture(lyr, ext) {
|
|
10445
|
-
var frame = ext.
|
|
10699
|
+
var frame = ext.getFrameData(); // frame should be set if we're rendering a furniture layer
|
|
10446
10700
|
var obj = internal.getEmptyLayerForSVG(lyr, {});
|
|
10447
10701
|
if (!frame) {
|
|
10448
10702
|
stop$1('Missing map frame data');
|
|
@@ -10479,7 +10733,7 @@
|
|
|
10479
10733
|
target.svg_id = id;
|
|
10480
10734
|
resize(ext);
|
|
10481
10735
|
if (type == 'label' || type == 'symbol') {
|
|
10482
|
-
html = renderSymbols(target.layer, ext
|
|
10736
|
+
html = renderSymbols(target.layer, ext);
|
|
10483
10737
|
} else if (type == 'furniture') {
|
|
10484
10738
|
html = renderFurniture(target.layer, ext);
|
|
10485
10739
|
}
|
|
@@ -10493,13 +10747,17 @@
|
|
|
10493
10747
|
};
|
|
10494
10748
|
|
|
10495
10749
|
function reposition(target, type, ext) {
|
|
10496
|
-
var container = el.findChild('.' + target.svg_id)
|
|
10750
|
+
var container = el.findChild('.' + target.svg_id);
|
|
10751
|
+
if (!container || !container.node()) {
|
|
10752
|
+
console.error('[reposition] missing SVG container');
|
|
10753
|
+
return;
|
|
10754
|
+
}
|
|
10497
10755
|
var elements;
|
|
10498
10756
|
if (type == 'symbol') {
|
|
10499
|
-
elements = El.findAll('.mapshaper-svg-symbol', container);
|
|
10757
|
+
elements = El.findAll('.mapshaper-svg-symbol', container.node());
|
|
10500
10758
|
repositionSymbols(elements, target.layer, ext);
|
|
10501
10759
|
} else if (type == 'furniture') {
|
|
10502
|
-
repositionFurniture(container, target.layer, ext);
|
|
10760
|
+
repositionFurniture(container.node(), target.layer, ext);
|
|
10503
10761
|
} else {
|
|
10504
10762
|
// container.getElementsByTagName('text')
|
|
10505
10763
|
error('Unsupported symbol type:', type);
|
|
@@ -10514,7 +10772,7 @@
|
|
|
10514
10772
|
return el;
|
|
10515
10773
|
}
|
|
10516
10774
|
|
|
10517
|
-
function
|
|
10775
|
+
function LayerRenderer(gui, container, ext, mouse) {
|
|
10518
10776
|
var el = El(container),
|
|
10519
10777
|
_mainCanv = new DisplayCanvas().appendTo(el),
|
|
10520
10778
|
_overlayCanv = new DisplayCanvas().appendTo(el),
|
|
@@ -10534,14 +10792,12 @@
|
|
|
10534
10792
|
}
|
|
10535
10793
|
layers.forEach(function(lyr) {
|
|
10536
10794
|
var isSvgLayer = internal.layerHasSvgSymbols(lyr.layer) || internal.layerHasLabels(lyr.layer);
|
|
10537
|
-
//if (!svgType || svgType == 'label') { // svg labels may have canvas dots
|
|
10538
|
-
if (!isSvgLayer) { // svg labels may have canvas dots
|
|
10539
|
-
drawCanvasLayer(lyr, _mainCanv);
|
|
10540
|
-
}
|
|
10541
10795
|
if (isSvgLayer && !needSvgRedraw) {
|
|
10542
10796
|
_svg.reposition(lyr, 'symbol');
|
|
10543
10797
|
} else if (isSvgLayer) {
|
|
10544
10798
|
_svg.drawLayer(lyr, 'symbol');
|
|
10799
|
+
} else {
|
|
10800
|
+
drawCanvasLayer(lyr, _mainCanv);
|
|
10545
10801
|
}
|
|
10546
10802
|
});
|
|
10547
10803
|
};
|
|
@@ -10606,7 +10862,7 @@
|
|
|
10606
10862
|
//
|
|
10607
10863
|
function BoxTool(gui, ext, nav) {
|
|
10608
10864
|
var self = new EventDispatcher();
|
|
10609
|
-
var box = new HighlightBox(gui, {persistent: true, handles: true});
|
|
10865
|
+
var box = new HighlightBox(gui, {name: 'box-tool', persistent: true, handles: true, draggable: true});
|
|
10610
10866
|
var popup = gui.container.findChild('.box-tool-options');
|
|
10611
10867
|
var coords = popup.findChild('.box-coords');
|
|
10612
10868
|
var _on = false;
|
|
@@ -10639,7 +10895,8 @@
|
|
|
10639
10895
|
});
|
|
10640
10896
|
|
|
10641
10897
|
new SimpleButton(popup.findChild('.rect-btn')).on('click', function() {
|
|
10642
|
-
|
|
10898
|
+
var cmd = '-rectangle + bbox=' + box.getDataCoords().join(',');
|
|
10899
|
+
runCommand(cmd);
|
|
10643
10900
|
});
|
|
10644
10901
|
|
|
10645
10902
|
gui.addMode('box_tool', turnOn, turnOff);
|
|
@@ -10652,7 +10909,7 @@
|
|
|
10652
10909
|
}
|
|
10653
10910
|
});
|
|
10654
10911
|
|
|
10655
|
-
gui.on('
|
|
10912
|
+
gui.on('shift_drag_start', function() {
|
|
10656
10913
|
// box.classed('zooming', inZoomMode());
|
|
10657
10914
|
hideCoords();
|
|
10658
10915
|
});
|
|
@@ -10718,7 +10975,7 @@
|
|
|
10718
10975
|
}
|
|
10719
10976
|
|
|
10720
10977
|
function RectangleControl(gui, hit) {
|
|
10721
|
-
var box = new HighlightBox(gui, {persistent: true, handles: true, classname: 'rectangles'});
|
|
10978
|
+
var box = new HighlightBox(gui, {name: 'rectangle-tool', persistent: true, handles: true, classname: 'rectangles', draggable: false});
|
|
10722
10979
|
var _on = false;
|
|
10723
10980
|
var dragInfo;
|
|
10724
10981
|
|
|
@@ -10734,7 +10991,7 @@
|
|
|
10734
10991
|
|
|
10735
10992
|
hit.on('change', function(e) {
|
|
10736
10993
|
if (!_on) return;
|
|
10737
|
-
// TODO: handle multiple hits (see gui-inspection-
|
|
10994
|
+
// TODO: handle multiple hits (see gui-inspection-control)
|
|
10738
10995
|
var id = e.id;
|
|
10739
10996
|
if (e.id > -1 && e.pinned) {
|
|
10740
10997
|
var target = hit.getHitTarget();
|
|
@@ -10755,8 +11012,7 @@
|
|
|
10755
11012
|
gui.container.findChild('.map-layers').classed('dragging', true);
|
|
10756
11013
|
|
|
10757
11014
|
} else if (dragInfo) {
|
|
10758
|
-
|
|
10759
|
-
gui.dispatchEvent('rectangle_dragend', dragInfo);
|
|
11015
|
+
gui.dispatchEvent('rectangle_dragend', dragInfo); // save undo state
|
|
10760
11016
|
gui.container.findChild('.map-layers').classed('dragging', false);
|
|
10761
11017
|
reset();
|
|
10762
11018
|
} else {
|
|
@@ -11296,7 +11552,7 @@
|
|
|
11296
11552
|
_hit,
|
|
11297
11553
|
_basemap,
|
|
11298
11554
|
_intersectionLyr, _activeLyr, _overlayLyr,
|
|
11299
|
-
|
|
11555
|
+
_renderer, _dynamicCRS;
|
|
11300
11556
|
|
|
11301
11557
|
_basemap = new Basemap(gui, _ext);
|
|
11302
11558
|
|
|
@@ -11391,13 +11647,12 @@
|
|
|
11391
11647
|
clearAllDisplayArcs();
|
|
11392
11648
|
|
|
11393
11649
|
// Reproject all visible map layers
|
|
11394
|
-
|
|
11395
|
-
|
|
11396
|
-
|
|
11397
|
-
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
updateLayerStyles(getDrawableContentLayers()); // kludge to make sure all layers have styles
|
|
11650
|
+
getContentLayers().forEach(function(lyr) {
|
|
11651
|
+
projectDisplayLayer(lyr, newCRS);
|
|
11652
|
+
});
|
|
11653
|
+
|
|
11654
|
+
// kludge to make sure all layers have styles
|
|
11655
|
+
updateLayerStyles(getContentLayers());
|
|
11401
11656
|
|
|
11402
11657
|
// Update map extent (also triggers redraw)
|
|
11403
11658
|
projectMapExtent(_ext, oldCRS, this.getDisplayCRS(), calcFullBounds());
|
|
@@ -11450,19 +11705,12 @@
|
|
|
11450
11705
|
updateVisibleMapLayers();
|
|
11451
11706
|
fullBounds = calcFullBounds();
|
|
11452
11707
|
|
|
11453
|
-
if (!prevLyr || prevLyr.tabular || _activeLyr.tabular
|
|
11708
|
+
if (!prevLyr || prevLyr.tabular || _activeLyr.tabular) {
|
|
11454
11709
|
needReset = true;
|
|
11455
11710
|
} else {
|
|
11456
11711
|
needReset = mapNeedsReset(fullBounds, _ext.getFullBounds(), _ext.getBounds(), e.flags);
|
|
11457
11712
|
}
|
|
11458
11713
|
|
|
11459
|
-
if (isFrameView()) {
|
|
11460
|
-
_nav.setZoomFactor(0.05); // slow zooming way down to allow fine-tuning frame placement // 0.03
|
|
11461
|
-
_ext.setFrame(calcFullBounds()); // TODO: remove redundancy with drawLayers()
|
|
11462
|
-
needReset = true; // snap to frame extent
|
|
11463
|
-
} else {
|
|
11464
|
-
_nav.setZoomFactor(1);
|
|
11465
|
-
}
|
|
11466
11714
|
_ext.setFullBounds(fullBounds, getStrictBounds()); // update 'home' button extent
|
|
11467
11715
|
|
|
11468
11716
|
if (needReset) {
|
|
@@ -11475,7 +11723,7 @@
|
|
|
11475
11723
|
// Initialization just before displaying the map for the first time
|
|
11476
11724
|
function initMap() {
|
|
11477
11725
|
_ext.resize();
|
|
11478
|
-
|
|
11726
|
+
_renderer = new LayerRenderer(gui, el, _ext, _mouse);
|
|
11479
11727
|
gui.buttons.show();
|
|
11480
11728
|
|
|
11481
11729
|
if (opts.inspectorControl) {
|
|
@@ -11485,16 +11733,13 @@
|
|
|
11485
11733
|
new BoxTool(gui, _ext, _nav),
|
|
11486
11734
|
new RectangleControl(gui, _hit),
|
|
11487
11735
|
initInteractiveEditing(gui, _ext, _hit);
|
|
11488
|
-
|
|
11736
|
+
initDrawing(gui, _ext, _mouse, _hit);
|
|
11489
11737
|
_hit.on('change', updateOverlayLayer);
|
|
11490
11738
|
}
|
|
11491
11739
|
|
|
11492
11740
|
_ext.on('change', function(e) {
|
|
11493
11741
|
if (_basemap) _basemap.refresh(); // keep basemap synced up (if enabled)
|
|
11494
11742
|
if (e.reset) return; // don't need to redraw map here if extent has been reset
|
|
11495
|
-
if (isFrameView()) {
|
|
11496
|
-
updateFrameExtent();
|
|
11497
|
-
}
|
|
11498
11743
|
drawLayers('nav');
|
|
11499
11744
|
});
|
|
11500
11745
|
|
|
@@ -11516,7 +11761,6 @@
|
|
|
11516
11761
|
|
|
11517
11762
|
// 'hover' avoids redrawing all svg symbols when only highlight needs to refresh
|
|
11518
11763
|
drawLayers('hover');
|
|
11519
|
-
// drawLayers();
|
|
11520
11764
|
}
|
|
11521
11765
|
|
|
11522
11766
|
function getDisplayOptions() {
|
|
@@ -11525,21 +11769,6 @@
|
|
|
11525
11769
|
};
|
|
11526
11770
|
}
|
|
11527
11771
|
|
|
11528
|
-
// Update map frame after user navigates the map in frame edit mode
|
|
11529
|
-
function updateFrameExtent() {
|
|
11530
|
-
var frameLyr = internal.findFrameLayer(model);
|
|
11531
|
-
var rec = frameLyr.data.getRecordAt(0);
|
|
11532
|
-
var viewBounds = _ext.getBounds();
|
|
11533
|
-
var w = viewBounds.width() * rec.width / _ext.width();
|
|
11534
|
-
var h = w * rec.height / rec.width;
|
|
11535
|
-
var cx = viewBounds.centerX();
|
|
11536
|
-
var cy = viewBounds.centerY();
|
|
11537
|
-
rec.bbox = [cx - w/2, cy - h/2, cx + w/2, cy + h/2];
|
|
11538
|
-
_ext.setFrame(getFrameData());
|
|
11539
|
-
_ext.setFullBounds(new Bounds(rec.bbox));
|
|
11540
|
-
_ext.reset();
|
|
11541
|
-
}
|
|
11542
|
-
|
|
11543
11772
|
function getStrictBounds() {
|
|
11544
11773
|
if (internal.isWebMercator(map.getDisplayCRS())) {
|
|
11545
11774
|
return getMapboxBounds();
|
|
@@ -11551,12 +11780,9 @@
|
|
|
11551
11780
|
_ext.setFullBounds(calcFullBounds(), getStrictBounds());
|
|
11552
11781
|
}
|
|
11553
11782
|
|
|
11554
|
-
function
|
|
11555
|
-
if (isPreviewView()) {
|
|
11556
|
-
return internal.getFrameLayerBounds(internal.findFrameLayer(model));
|
|
11557
|
-
}
|
|
11783
|
+
function getContentLayerBounds() {
|
|
11558
11784
|
var b = new Bounds();
|
|
11559
|
-
var layers =
|
|
11785
|
+
var layers = getContentLayers();
|
|
11560
11786
|
layers.forEach(function(lyr) {
|
|
11561
11787
|
b.mergeBounds(lyr.bounds);
|
|
11562
11788
|
});
|
|
@@ -11565,6 +11791,11 @@
|
|
|
11565
11791
|
// assign bounds to empty layers, to prevent rendering errors downstream
|
|
11566
11792
|
b.setBounds(0,0,0,0);
|
|
11567
11793
|
}
|
|
11794
|
+
return b;
|
|
11795
|
+
}
|
|
11796
|
+
|
|
11797
|
+
function calcFullBounds() {
|
|
11798
|
+
var b = getContentLayerBounds();
|
|
11568
11799
|
|
|
11569
11800
|
// add margin
|
|
11570
11801
|
// use larger margin for small sizes
|
|
@@ -11590,33 +11821,25 @@
|
|
|
11590
11821
|
return isActiveLayer(lyr) || lyr.pinned;
|
|
11591
11822
|
}
|
|
11592
11823
|
|
|
11593
|
-
function isFrameLayer(lyr) {
|
|
11594
|
-
return !!(lyr && lyr == internal.findFrameLayer(model));
|
|
11595
|
-
}
|
|
11596
|
-
|
|
11597
11824
|
function isTableView() {
|
|
11598
11825
|
return !isPreviewView() && !!_activeLyr.tabular;
|
|
11599
11826
|
}
|
|
11600
11827
|
|
|
11601
|
-
|
|
11602
|
-
|
|
11603
|
-
|
|
11604
|
-
|
|
11605
|
-
// var frameLyr = internal.findFrameLayer(model);
|
|
11606
|
-
// return !!frameLyr; // && isVisibleLayer(frameLyr)
|
|
11828
|
+
function findFrameLayer() {
|
|
11829
|
+
return getVisibleMapLayers().find(function(lyr) {
|
|
11830
|
+
return internal.isFrameLayer(lyr.layer, lyr.arcs);
|
|
11831
|
+
});
|
|
11607
11832
|
}
|
|
11608
11833
|
|
|
11609
|
-
//
|
|
11610
|
-
|
|
11611
|
-
|
|
11612
|
-
return
|
|
11613
|
-
// var frameLyr = internal.findFrameLayer(model);
|
|
11614
|
-
// return isActiveLayer(frameLyr) && isVisibleLayer(frameLyr);
|
|
11834
|
+
// Preview view: symbols are scaled based on display size of frame layer
|
|
11835
|
+
function isPreviewView() {
|
|
11836
|
+
var data = getFrameData();
|
|
11837
|
+
return !!data;
|
|
11615
11838
|
}
|
|
11616
11839
|
|
|
11617
11840
|
function getFrameData() {
|
|
11618
|
-
var
|
|
11619
|
-
return
|
|
11841
|
+
var lyr = findFrameLayer();
|
|
11842
|
+
return lyr && internal.getFrameLayerData(lyr.layer, lyr.arcs) || null;
|
|
11620
11843
|
}
|
|
11621
11844
|
|
|
11622
11845
|
function clearAllDisplayArcs() {
|
|
@@ -11648,7 +11871,7 @@
|
|
|
11648
11871
|
});
|
|
11649
11872
|
}
|
|
11650
11873
|
|
|
11651
|
-
function
|
|
11874
|
+
function getContentLayers() {
|
|
11652
11875
|
var layers = getVisibleMapLayers();
|
|
11653
11876
|
if (isTableView()) return findActiveLayer(layers);
|
|
11654
11877
|
return layers.filter(function(o) {
|
|
@@ -11656,6 +11879,13 @@
|
|
|
11656
11879
|
});
|
|
11657
11880
|
}
|
|
11658
11881
|
|
|
11882
|
+
function getDrawableContentLayers() {
|
|
11883
|
+
return getContentLayers().filter(function(lyr) {
|
|
11884
|
+
if (isActiveLayer(lyr.layer) && lyr.layer.hidden) return false;
|
|
11885
|
+
return true;
|
|
11886
|
+
});
|
|
11887
|
+
}
|
|
11888
|
+
|
|
11659
11889
|
function getDrawableFurnitureLayers(layers) {
|
|
11660
11890
|
if (!isPreviewView()) return [];
|
|
11661
11891
|
return getVisibleMapLayers().filter(function(o) {
|
|
@@ -11706,7 +11936,7 @@
|
|
|
11706
11936
|
var layersMayHaveChanged = action != 'nav'; // !action;
|
|
11707
11937
|
var fullBounds;
|
|
11708
11938
|
var contentLayers = getDrawableContentLayers();
|
|
11709
|
-
var furnitureLayers = getDrawableFurnitureLayers();
|
|
11939
|
+
// var furnitureLayers = getDrawableFurnitureLayers();
|
|
11710
11940
|
if (!(_ext.width() > 0 && _ext.height() > 0)) {
|
|
11711
11941
|
// TODO: track down source of these errors
|
|
11712
11942
|
console.error("Collapsed map container, unable to draw.");
|
|
@@ -11714,7 +11944,7 @@
|
|
|
11714
11944
|
}
|
|
11715
11945
|
if (layersMayHaveChanged) {
|
|
11716
11946
|
// kludge to handle layer visibility toggling
|
|
11717
|
-
_ext.
|
|
11947
|
+
_ext.setFrameData(isPreviewView() ? getFrameData() : null);
|
|
11718
11948
|
updateFullBounds();
|
|
11719
11949
|
updateLayerStyles(contentLayers);
|
|
11720
11950
|
updateLayerStackOrder(model.getLayers());// update menu_order property of all layers
|
|
@@ -11725,11 +11955,11 @@
|
|
|
11725
11955
|
}
|
|
11726
11956
|
// RENDERING
|
|
11727
11957
|
// draw main content layers
|
|
11728
|
-
|
|
11958
|
+
_renderer.drawMainLayers(contentLayers, action);
|
|
11729
11959
|
// draw hover & selection overlay
|
|
11730
|
-
|
|
11960
|
+
_renderer.drawOverlayLayer(_overlayLyr, action);
|
|
11731
11961
|
// draw furniture
|
|
11732
|
-
|
|
11962
|
+
// _renderer.drawFurnitureLayers(furnitureLayers, action);
|
|
11733
11963
|
gui.dispatchEvent('map_rendered');
|
|
11734
11964
|
}
|
|
11735
11965
|
}
|