mapshaper 0.5.91 → 0.5.92
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/bin/mapshaper-gui +16 -9
- package/mapshaper.js +90 -47
- package/package.json +2 -2
- package/www/index.html +1 -1
- package/www/mapshaper-gui.js +361 -291
- package/www/mapshaper.js +90 -47
package/www/mapshaper-gui.js
CHANGED
|
@@ -1232,6 +1232,7 @@
|
|
|
1232
1232
|
}
|
|
1233
1233
|
}
|
|
1234
1234
|
model.updated({select: true});
|
|
1235
|
+
|
|
1235
1236
|
}
|
|
1236
1237
|
|
|
1237
1238
|
function clearQueuedFiles() {
|
|
@@ -2187,6 +2188,13 @@
|
|
|
2187
2188
|
// expose this function, so other components can run commands (e.g. box tool)
|
|
2188
2189
|
this.runMapshaperCommands = runMapshaperCommands;
|
|
2189
2190
|
|
|
2191
|
+
this.runInitialCommands = function(str) {
|
|
2192
|
+
str = str.trim();
|
|
2193
|
+
if (!str) return;
|
|
2194
|
+
turnOn();
|
|
2195
|
+
submit(str);
|
|
2196
|
+
};
|
|
2197
|
+
|
|
2190
2198
|
consoleMessage(PROMPT);
|
|
2191
2199
|
gui.keyboard.on('keydown', onKeyDown);
|
|
2192
2200
|
window.addEventListener('beforeunload', saveHistory); // save history if console is open on refresh
|
|
@@ -3549,7 +3557,7 @@
|
|
|
3549
3557
|
|
|
3550
3558
|
// import { cloneShape } from '../paths/mapshaper-shape-utils';
|
|
3551
3559
|
// import { copyRecord } from '../datatable/mapshaper-data-utils';
|
|
3552
|
-
var snapVerticesToPoint
|
|
3560
|
+
var snapVerticesToPoint = internal.snapVerticesToPoint;
|
|
3553
3561
|
var cloneShape = internal.cloneShape;
|
|
3554
3562
|
var copyRecord = internal.copyRecord;
|
|
3555
3563
|
|
|
@@ -3658,7 +3666,7 @@
|
|
|
3658
3666
|
var arcs = target.dataset.arcs;
|
|
3659
3667
|
var p = internal.getVertexCoords(ids[0], arcs);
|
|
3660
3668
|
return function() {
|
|
3661
|
-
snapVerticesToPoint
|
|
3669
|
+
snapVerticesToPoint(ids, p, arcs, true);
|
|
3662
3670
|
};
|
|
3663
3671
|
};
|
|
3664
3672
|
|
|
@@ -4098,13 +4106,38 @@
|
|
|
4098
4106
|
return self;
|
|
4099
4107
|
}
|
|
4100
4108
|
|
|
4101
|
-
function
|
|
4109
|
+
function absArcId(arcId) {
|
|
4110
|
+
return arcId >= 0 ? arcId : ~arcId;
|
|
4111
|
+
}
|
|
4112
|
+
|
|
4113
|
+
function calcArcBounds(xx, yy, start, len) {
|
|
4114
|
+
var i = start | 0,
|
|
4115
|
+
n = isNaN(len) ? xx.length - i : len + i,
|
|
4116
|
+
x, y, xmin, ymin, xmax, ymax;
|
|
4117
|
+
if (n > 0) {
|
|
4118
|
+
xmin = xmax = xx[i];
|
|
4119
|
+
ymin = ymax = yy[i];
|
|
4120
|
+
}
|
|
4121
|
+
for (i++; i<n; i++) {
|
|
4122
|
+
x = xx[i];
|
|
4123
|
+
y = yy[i];
|
|
4124
|
+
if (x < xmin) xmin = x;
|
|
4125
|
+
if (x > xmax) xmax = x;
|
|
4126
|
+
if (y < ymin) ymin = y;
|
|
4127
|
+
if (y > ymax) ymax = y;
|
|
4128
|
+
}
|
|
4129
|
+
return [xmin, ymin, xmax, ymax];
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
function getShapeHitTest(displayLayer, ext, interactionMode) {
|
|
4102
4133
|
var geoType = displayLayer.layer.geometry_type;
|
|
4103
4134
|
var test;
|
|
4104
4135
|
if (geoType == 'point' && displayLayer.style.type == 'styled') {
|
|
4105
4136
|
test = getGraduatedCircleTest(getRadiusFunction(displayLayer.style));
|
|
4106
4137
|
} else if (geoType == 'point') {
|
|
4107
4138
|
test = pointTest;
|
|
4139
|
+
} else if (interactionMode == 'vertices') {
|
|
4140
|
+
test = vertexTest;
|
|
4108
4141
|
} else if (geoType == 'polyline') {
|
|
4109
4142
|
test = polylineTest;
|
|
4110
4143
|
} else if (geoType == 'polygon') {
|
|
@@ -4130,14 +4163,14 @@
|
|
|
4130
4163
|
}
|
|
4131
4164
|
|
|
4132
4165
|
function polygonTest(x, y) {
|
|
4133
|
-
var maxDist = getZoomAdjustedHitBuffer(
|
|
4166
|
+
var maxDist = getZoomAdjustedHitBuffer(10, 1),
|
|
4134
4167
|
cands = findHitCandidates(x, y, maxDist),
|
|
4135
4168
|
hits = [],
|
|
4136
4169
|
cand, hitId;
|
|
4137
4170
|
for (var i=0; i<cands.length; i++) {
|
|
4138
4171
|
cand = cands[i];
|
|
4139
4172
|
if (geom.testPointInPolygon(x, y, cand.shape, displayLayer.arcs)) {
|
|
4140
|
-
hits.push(cand
|
|
4173
|
+
hits.push(cand);
|
|
4141
4174
|
}
|
|
4142
4175
|
}
|
|
4143
4176
|
if (cands.length > 0 && hits.length === 0) {
|
|
@@ -4145,7 +4178,9 @@
|
|
|
4145
4178
|
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
4146
4179
|
hits = pickNearestCandidates(cands, 0, maxDist);
|
|
4147
4180
|
}
|
|
4148
|
-
return
|
|
4181
|
+
return {
|
|
4182
|
+
ids: utils.pluck(hits, 'id')
|
|
4183
|
+
};
|
|
4149
4184
|
}
|
|
4150
4185
|
|
|
4151
4186
|
function pickNearestCandidates(sorted, bufDist, maxDist) {
|
|
@@ -4160,22 +4195,41 @@
|
|
|
4160
4195
|
} else if (cand.dist - minDist > bufDist) {
|
|
4161
4196
|
break;
|
|
4162
4197
|
}
|
|
4163
|
-
hits.push(cand
|
|
4198
|
+
hits.push(cand);
|
|
4164
4199
|
}
|
|
4165
4200
|
return hits;
|
|
4166
4201
|
}
|
|
4167
4202
|
|
|
4203
|
+
function vertexTest(x, y) {
|
|
4204
|
+
var maxDist = getZoomAdjustedHitBuffer(15, 2),
|
|
4205
|
+
bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
|
|
4206
|
+
cands = findHitCandidates(x, y, maxDist);
|
|
4207
|
+
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
4208
|
+
cands = pickNearestCandidates(cands, bufDist, maxDist);
|
|
4209
|
+
var arcs = cands.map(function(cand) { return absArcId(cand.info.arcId); });
|
|
4210
|
+
return {
|
|
4211
|
+
arcs: utils.uniq(arcs),
|
|
4212
|
+
ids: utils.pluck(cands, 'id')
|
|
4213
|
+
};
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4168
4216
|
function polylineTest(x, y) {
|
|
4169
4217
|
var maxDist = getZoomAdjustedHitBuffer(15, 2),
|
|
4170
4218
|
bufDist = getZoomAdjustedHitBuffer(0.05), // tiny threshold for hitting almost-identical lines
|
|
4171
4219
|
cands = findHitCandidates(x, y, maxDist);
|
|
4172
4220
|
sortByDistance(x, y, cands, displayLayer.arcs);
|
|
4173
|
-
|
|
4221
|
+
cands = pickNearestCandidates(cands, bufDist, maxDist);
|
|
4222
|
+
return {
|
|
4223
|
+
ids: utils.pluck(cands, 'id')
|
|
4224
|
+
};
|
|
4174
4225
|
}
|
|
4175
4226
|
|
|
4176
4227
|
function sortByDistance(x, y, cands, arcs) {
|
|
4228
|
+
var cand;
|
|
4177
4229
|
for (var i=0; i<cands.length; i++) {
|
|
4178
|
-
|
|
4230
|
+
cand = cands[i];
|
|
4231
|
+
cand.info = geom.getPointToShapeInfo(x, y, cands[i].shape, arcs);
|
|
4232
|
+
cand.dist = cand.info.distance;
|
|
4179
4233
|
}
|
|
4180
4234
|
utils.sortOn(cands, 'dist');
|
|
4181
4235
|
}
|
|
@@ -4203,7 +4257,9 @@
|
|
|
4203
4257
|
}
|
|
4204
4258
|
});
|
|
4205
4259
|
// console.log(hitThreshold, bullseye);
|
|
4206
|
-
return
|
|
4260
|
+
return {
|
|
4261
|
+
ids: utils.uniq(hits) // multipoint features can register multiple hits
|
|
4262
|
+
};
|
|
4207
4263
|
}
|
|
4208
4264
|
|
|
4209
4265
|
function getRadiusFunction(style) {
|
|
@@ -4257,7 +4313,9 @@
|
|
|
4257
4313
|
hits.push(id);
|
|
4258
4314
|
}
|
|
4259
4315
|
});
|
|
4260
|
-
return
|
|
4316
|
+
return {
|
|
4317
|
+
ids: hits
|
|
4318
|
+
};
|
|
4261
4319
|
};
|
|
4262
4320
|
}
|
|
4263
4321
|
|
|
@@ -4394,20 +4452,18 @@
|
|
|
4394
4452
|
|
|
4395
4453
|
}
|
|
4396
4454
|
|
|
4397
|
-
function getPointerHitTest(mapLayer, ext) {
|
|
4455
|
+
function getPointerHitTest(mapLayer, ext, interactionMode) {
|
|
4398
4456
|
var shapeTest, svgTest, targetLayer;
|
|
4399
4457
|
if (!mapLayer || !internal.layerHasGeometry(mapLayer.layer)) {
|
|
4400
|
-
return
|
|
4458
|
+
return function() {return {ids: []};};
|
|
4401
4459
|
}
|
|
4402
|
-
shapeTest = getShapeHitTest(mapLayer, ext);
|
|
4460
|
+
shapeTest = getShapeHitTest(mapLayer, ext, interactionMode);
|
|
4403
4461
|
svgTest = getSvgHitTest(mapLayer);
|
|
4404
4462
|
|
|
4405
4463
|
// e: pointer event
|
|
4406
4464
|
return function(e) {
|
|
4407
4465
|
var p = ext.translatePixelCoords(e.x, e.y);
|
|
4408
|
-
var data = {
|
|
4409
|
-
ids: shapeTest(p[0], p[1]) || []
|
|
4410
|
-
};
|
|
4466
|
+
var data = shapeTest(p[0], p[1]) || {ids:[]};
|
|
4411
4467
|
var svgData = svgTest(e); // null or a data object
|
|
4412
4468
|
if (svgData) { // mouse is over an SVG symbol
|
|
4413
4469
|
utils.extend(data, svgData);
|
|
@@ -4467,22 +4523,25 @@
|
|
|
4467
4523
|
}, !!'capture'); // preempt the layer control's arrow key handler
|
|
4468
4524
|
|
|
4469
4525
|
self.setLayer = function(mapLayer) {
|
|
4470
|
-
hitTest = getPointerHitTest(mapLayer, ext);
|
|
4471
|
-
if (!hitTest) {
|
|
4472
|
-
hitTest = function() {return {ids: []};};
|
|
4473
|
-
}
|
|
4474
4526
|
targetLayer = mapLayer;
|
|
4527
|
+
updateHitTest();
|
|
4475
4528
|
};
|
|
4476
4529
|
|
|
4530
|
+
function updateHitTest() {
|
|
4531
|
+
hitTest = getPointerHitTest(targetLayer, ext, interactionMode);
|
|
4532
|
+
}
|
|
4533
|
+
|
|
4477
4534
|
function turnOn(mode) {
|
|
4478
4535
|
interactionMode = mode;
|
|
4479
4536
|
active = true;
|
|
4537
|
+
updateHitTest();
|
|
4480
4538
|
}
|
|
4481
4539
|
|
|
4482
4540
|
function turnOff() {
|
|
4483
4541
|
if (active) {
|
|
4484
4542
|
updateSelectionState(null); // no hit data, no event
|
|
4485
4543
|
active = false;
|
|
4544
|
+
hitTest = null;
|
|
4486
4545
|
}
|
|
4487
4546
|
}
|
|
4488
4547
|
|
|
@@ -4526,6 +4585,20 @@
|
|
|
4526
4585
|
}
|
|
4527
4586
|
};
|
|
4528
4587
|
|
|
4588
|
+
self.setHoverVertex = function(p) {
|
|
4589
|
+
var p2 = storedData.hit_coordinates;
|
|
4590
|
+
if (!active || !p) return;
|
|
4591
|
+
if (p2 && p2[0] == p[0] && p2[1] == p[1]) return;
|
|
4592
|
+
storedData.hit_coordinates = p;
|
|
4593
|
+
triggerHitEvent('change');
|
|
4594
|
+
};
|
|
4595
|
+
|
|
4596
|
+
self.clearVertexOverlay = function() {
|
|
4597
|
+
if (!storedData.hit_coordinates) return;
|
|
4598
|
+
delete storedData.hit_coordinates;
|
|
4599
|
+
triggerHitEvent('change');
|
|
4600
|
+
};
|
|
4601
|
+
|
|
4529
4602
|
self.clearSelection = function() {
|
|
4530
4603
|
updateSelectionState(null);
|
|
4531
4604
|
};
|
|
@@ -5866,50 +5939,108 @@
|
|
|
5866
5939
|
rec[key] = isString ? String(newVal) : newVal;
|
|
5867
5940
|
}
|
|
5868
5941
|
|
|
5869
|
-
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
var
|
|
5873
|
-
return ext.translateCoords(coords[0], coords[1]);
|
|
5874
|
-
}
|
|
5942
|
+
function initLabelDragging(gui, ext, hit) {
|
|
5943
|
+
var downEvt;
|
|
5944
|
+
var activeId;
|
|
5945
|
+
var activeRecord;
|
|
5875
5946
|
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
if (!coords || coords.length != 1) {
|
|
5879
|
-
return null;
|
|
5947
|
+
function active(e) {
|
|
5948
|
+
return e.id > -1 && gui.interaction.getMode() == 'labels';
|
|
5880
5949
|
}
|
|
5881
|
-
return coords[0];
|
|
5882
|
-
}
|
|
5883
5950
|
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
|
|
5888
|
-
|
|
5951
|
+
hit.on('dragstart', function(e) {
|
|
5952
|
+
if (!active(e)) return;
|
|
5953
|
+
var textNode = getTextTarget3(e);
|
|
5954
|
+
var table = hit.getTargetDataTable();
|
|
5955
|
+
if (!textNode || !table) return false;
|
|
5956
|
+
activeId = e.id;
|
|
5957
|
+
activeRecord = getLabelRecordById(activeId);
|
|
5958
|
+
downEvt = e;
|
|
5959
|
+
gui.dispatchEvent('label_dragstart', {FID: activeId});
|
|
5960
|
+
});
|
|
5889
5961
|
|
|
5962
|
+
hit.on('drag', function(e) {
|
|
5963
|
+
if (!active(e)) return;
|
|
5964
|
+
if (e.id != activeId) {
|
|
5965
|
+
error("Mismatched hit ids:", e.id, activeId);
|
|
5966
|
+
}
|
|
5967
|
+
var scale = ext.getSymbolScale() || 1;
|
|
5968
|
+
var textNode;
|
|
5969
|
+
applyDelta(activeRecord, 'dx', e.dx / scale);
|
|
5970
|
+
applyDelta(activeRecord, 'dy', e.dy / scale);
|
|
5971
|
+
textNode = getTextTarget3(e);
|
|
5972
|
+
if (!isMultilineLabel(textNode)) {
|
|
5973
|
+
// update anchor position of single-line labels based on label position
|
|
5974
|
+
// relative to anchor point, for better placement when eventual display font is
|
|
5975
|
+
// different from mapshaper's font.
|
|
5976
|
+
autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget().layer, ext));
|
|
5977
|
+
}
|
|
5978
|
+
// updateSymbol(targetTextNode, activeRecord);
|
|
5979
|
+
updateSymbol2(textNode, activeRecord, activeId);
|
|
5980
|
+
});
|
|
5890
5981
|
|
|
5891
|
-
|
|
5892
|
-
|
|
5893
|
-
|
|
5894
|
-
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5982
|
+
hit.on('dragend', function(e) {
|
|
5983
|
+
if (!active(e)) return;
|
|
5984
|
+
gui.dispatchEvent('label_dragend', {FID: e.id});
|
|
5985
|
+
activeId = -1;
|
|
5986
|
+
activeRecord = null;
|
|
5987
|
+
downEvt = null;
|
|
5988
|
+
});
|
|
5898
5989
|
|
|
5899
|
-
|
|
5990
|
+
function getDisplayCoordsById(id, layer, ext) {
|
|
5991
|
+
var coords = getPointCoordsById(id, layer);
|
|
5992
|
+
return ext.translateCoords(coords[0], coords[1]);
|
|
5993
|
+
}
|
|
5900
5994
|
|
|
5901
|
-
|
|
5995
|
+
function getPointCoordsById(id, layer) {
|
|
5996
|
+
var coords = layer && layer.geometry_type == 'point' && layer.shapes[id];
|
|
5997
|
+
if (!coords || coords.length != 1) {
|
|
5998
|
+
return null;
|
|
5999
|
+
}
|
|
6000
|
+
return coords[0];
|
|
6001
|
+
}
|
|
6002
|
+
|
|
6003
|
+
function getTextTarget3(e) {
|
|
6004
|
+
if (e.id > -1 === false || !e.container) return null;
|
|
6005
|
+
return getSymbolNodeById(e.id, e.container);
|
|
6006
|
+
}
|
|
6007
|
+
|
|
6008
|
+
function getSymbolNodeById(id, parent) {
|
|
6009
|
+
// TODO: optimize selector
|
|
6010
|
+
var sel = '[data-id="' + id + '"]';
|
|
6011
|
+
return parent.querySelector(sel);
|
|
6012
|
+
}
|
|
5902
6013
|
|
|
5903
|
-
function
|
|
5904
|
-
|
|
6014
|
+
function getTextTarget2(e) {
|
|
6015
|
+
var el = e && e.targetSymbol || null;
|
|
6016
|
+
if (el && el.tagName == 'tspan') {
|
|
6017
|
+
el = el.parentNode;
|
|
6018
|
+
}
|
|
6019
|
+
return el && el.tagName == 'text' ? el : null;
|
|
5905
6020
|
}
|
|
5906
6021
|
|
|
5907
|
-
function
|
|
5908
|
-
|
|
6022
|
+
function getTextTarget(e) {
|
|
6023
|
+
var el = e.target;
|
|
6024
|
+
if (el.tagName == 'tspan') {
|
|
6025
|
+
el = el.parentNode;
|
|
6026
|
+
}
|
|
6027
|
+
return el.tagName == 'text' ? el : null;
|
|
5909
6028
|
}
|
|
5910
6029
|
|
|
5911
|
-
function
|
|
5912
|
-
|
|
6030
|
+
function getLabelRecordById(id) {
|
|
6031
|
+
var table = hit.getTargetDataTable();
|
|
6032
|
+
if (id >= 0 === false || !table) return null;
|
|
6033
|
+
// add dx and dy properties, if not available
|
|
6034
|
+
if (!table.fieldExists('dx')) {
|
|
6035
|
+
table.addField('dx', 0);
|
|
6036
|
+
}
|
|
6037
|
+
if (!table.fieldExists('dy')) {
|
|
6038
|
+
table.addField('dy', 0);
|
|
6039
|
+
}
|
|
6040
|
+
if (!table.fieldExists('text-anchor')) {
|
|
6041
|
+
table.addField('text-anchor', '');
|
|
6042
|
+
}
|
|
6043
|
+
return table.getRecordAt(id);
|
|
5913
6044
|
}
|
|
5914
6045
|
|
|
5915
6046
|
// update symbol by setting attributes
|
|
@@ -5936,249 +6067,167 @@
|
|
|
5936
6067
|
gui.dispatchEvent('popup-needs-refresh');
|
|
5937
6068
|
return node2;
|
|
5938
6069
|
}
|
|
6070
|
+
}
|
|
5939
6071
|
|
|
5940
|
-
|
|
5941
|
-
var downEvt;
|
|
5942
|
-
var eventPriority = 1;
|
|
5943
|
-
|
|
5944
|
-
// inspector and label editing aren't fully synced - stop editing if inspector opens
|
|
5945
|
-
// gui.on('inspector_on', function() {
|
|
5946
|
-
// stopEditing();
|
|
5947
|
-
// });
|
|
5948
|
-
|
|
5949
|
-
gui.on('interaction_mode_change', function(e) {
|
|
5950
|
-
if (e.mode != 'labels') {
|
|
5951
|
-
stopDragging();
|
|
5952
|
-
}
|
|
5953
|
-
gui.undo.clear(); // TODO: put this elsewhere?
|
|
5954
|
-
});
|
|
5955
|
-
|
|
5956
|
-
// down event on svg
|
|
5957
|
-
// a: off text
|
|
5958
|
-
// -> stop editing
|
|
5959
|
-
// b: on text
|
|
5960
|
-
// 1: not editing -> nop
|
|
5961
|
-
// 2: on selected text -> start dragging
|
|
5962
|
-
// 3: on other text -> stop dragging, select new text
|
|
5963
|
-
|
|
5964
|
-
hit.on('dragstart', function(e) {
|
|
5965
|
-
if (e.id >= 0 === false) return;
|
|
5966
|
-
if (labelEditingEnabled() && onLabelDragStart(e)) {
|
|
5967
|
-
triggerGlobalEvent('label_dragstart', e);
|
|
5968
|
-
startDragging();
|
|
5969
|
-
} else if (locationEditingEnabled()) {
|
|
5970
|
-
triggerGlobalEvent('symbol_dragstart', e);
|
|
5971
|
-
startDragging();
|
|
5972
|
-
} else if (vertexEditingEnabled()) {
|
|
5973
|
-
onVertexDragStart(e);
|
|
5974
|
-
triggerGlobalEvent('vertex_dragstart', e);
|
|
5975
|
-
startDragging();
|
|
5976
|
-
}
|
|
5977
|
-
});
|
|
5978
|
-
|
|
5979
|
-
hit.on('drag', function(e) {
|
|
5980
|
-
if (labelEditingEnabled()) {
|
|
5981
|
-
onLabelDrag(e);
|
|
5982
|
-
} else if (locationEditingEnabled()) {
|
|
5983
|
-
onLocationDrag(e);
|
|
5984
|
-
} else if (vertexEditingEnabled()) {
|
|
5985
|
-
onVertexDrag(e);
|
|
5986
|
-
}
|
|
5987
|
-
});
|
|
5988
|
-
|
|
5989
|
-
hit.on('dragend', function(e) {
|
|
5990
|
-
if (locationEditingEnabled()) {
|
|
5991
|
-
triggerGlobalEvent('symbol_dragend', e);
|
|
5992
|
-
stopDragging();
|
|
5993
|
-
} else if (labelEditingEnabled()) {
|
|
5994
|
-
triggerGlobalEvent('label_dragend', e);
|
|
5995
|
-
stopDragging();
|
|
5996
|
-
} else if (vertexEditingEnabled()) {
|
|
5997
|
-
// kludge to get dataset to recalculate internal bounding boxes
|
|
5998
|
-
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
5999
|
-
triggerGlobalEvent('vertex_dragend', e);
|
|
6000
|
-
stopDragging();
|
|
6001
|
-
}
|
|
6002
|
-
});
|
|
6003
|
-
|
|
6004
|
-
hit.on('click', function(e) {
|
|
6005
|
-
if (labelEditingEnabled()) {
|
|
6006
|
-
var target = hit.getHitTarget();
|
|
6007
|
-
onLabelClick(e);
|
|
6008
|
-
}
|
|
6009
|
-
});
|
|
6072
|
+
function initPointDragging(gui, ext, hit) {
|
|
6010
6073
|
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
onVertexHover(e);
|
|
6015
|
-
}
|
|
6016
|
-
}, null, 100);
|
|
6074
|
+
function active(e) {
|
|
6075
|
+
return e.id > -1 && gui.interaction.getMode() == 'location';
|
|
6076
|
+
}
|
|
6017
6077
|
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
var p = ext.translatePixelCoords(e.x, e.y);
|
|
6023
|
-
var o = internal.findInsertionPoint(p, shp, target.arcs, ext.getPixelSize());
|
|
6024
|
-
}
|
|
6078
|
+
hit.on('dragstart', function(e) {
|
|
6079
|
+
if (!active(e)) return;
|
|
6080
|
+
gui.dispatchEvent('symbol_dragstart', {FID: e.id});
|
|
6081
|
+
});
|
|
6025
6082
|
|
|
6083
|
+
hit.on('drag', function(e) {
|
|
6084
|
+
if (!active(e)) return;
|
|
6085
|
+
var lyr = hit.getHitTarget().layer;
|
|
6086
|
+
var p = getPointCoordsById(e.id, lyr);
|
|
6087
|
+
if (!p) return;
|
|
6088
|
+
var diff = translateDeltaDisplayCoords(e.dx, e.dy, ext);
|
|
6089
|
+
p[0] += diff[0];
|
|
6090
|
+
p[1] += diff[1];
|
|
6091
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
6092
|
+
gui.dispatchEvent('symbol_drag', {FID: e.id});
|
|
6093
|
+
});
|
|
6026
6094
|
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
};
|
|
6032
|
-
}
|
|
6095
|
+
hit.on('dragend', function(e) {
|
|
6096
|
+
if (!active(e)) return;
|
|
6097
|
+
gui.dispatchEvent('symbol_dragend', {FID: e.id});
|
|
6098
|
+
});
|
|
6033
6099
|
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
p[0] += diff[0];
|
|
6040
|
-
p[1] += diff[1];
|
|
6041
|
-
triggerRedraw();
|
|
6042
|
-
triggerGlobalEvent('symbol_drag', e);
|
|
6043
|
-
}
|
|
6100
|
+
function translateDeltaDisplayCoords(dx, dy, ext) {
|
|
6101
|
+
var a = ext.translatePixelCoords(0, 0);
|
|
6102
|
+
var b = ext.translatePixelCoords(dx, dy);
|
|
6103
|
+
return [b[0] - a[0], b[1] - a[1]];
|
|
6104
|
+
}
|
|
6044
6105
|
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6049
|
-
activeVertexIds = internal.findNearestVertices(p, shp, target.arcs);
|
|
6050
|
-
activeId = e.id;
|
|
6106
|
+
function getPointCoordsById(id, layer) {
|
|
6107
|
+
var coords = layer && layer.geometry_type == 'point' && layer.shapes[id];
|
|
6108
|
+
if (!coords || coords.length != 1) {
|
|
6109
|
+
return null;
|
|
6051
6110
|
}
|
|
6111
|
+
return coords[0];
|
|
6112
|
+
}
|
|
6113
|
+
}
|
|
6052
6114
|
|
|
6053
|
-
|
|
6054
|
-
|
|
6055
|
-
|
|
6056
|
-
|
|
6057
|
-
if (gui.keyboard.shiftIsPressed()) {
|
|
6058
|
-
internal.snapPointToArcEndpoint(p, activeVertexIds, target.arcs);
|
|
6059
|
-
}
|
|
6060
|
-
snapVerticesToPoint(activeVertexIds, p, target.arcs);
|
|
6061
|
-
triggerRedraw();
|
|
6062
|
-
}
|
|
6115
|
+
function initVertexDragging(gui, ext, hit) {
|
|
6116
|
+
var activeShapeId = -1;
|
|
6117
|
+
var draggedVertexIds = null;
|
|
6118
|
+
var selectedVertexIds = null;
|
|
6063
6119
|
|
|
6064
|
-
|
|
6065
|
-
|
|
6066
|
-
|
|
6067
|
-
if (textNode && rec && isMultilineLabel(textNode)) {
|
|
6068
|
-
toggleTextAlign(textNode, rec);
|
|
6069
|
-
updateSymbol2(textNode, rec, e.id);
|
|
6070
|
-
// e.stopPropagation(); // prevent pin/unpin on popup
|
|
6071
|
-
}
|
|
6072
|
-
}
|
|
6120
|
+
function active(e) {
|
|
6121
|
+
return e.id > -1 && gui.interaction.getMode() == 'vertices';
|
|
6122
|
+
}
|
|
6073
6123
|
|
|
6074
|
-
|
|
6075
|
-
|
|
6076
|
-
|
|
6124
|
+
function fire(type) {
|
|
6125
|
+
gui.dispatchEvent(type, {
|
|
6126
|
+
FID: activeShapeId,
|
|
6127
|
+
vertex_ids: draggedVertexIds
|
|
6128
|
+
});
|
|
6129
|
+
}
|
|
6077
6130
|
|
|
6078
|
-
|
|
6079
|
-
|
|
6080
|
-
|
|
6081
|
-
|
|
6082
|
-
layer_name: hit.getHitTarget().layer.name,
|
|
6083
|
-
vertex_ids: activeVertexIds
|
|
6084
|
-
};
|
|
6085
|
-
// fire event to signal external editor that symbol coords have changed
|
|
6086
|
-
gui.dispatchEvent(type, o);
|
|
6087
|
-
}
|
|
6131
|
+
function setHoverVertex(id) {
|
|
6132
|
+
var target = hit.getHitTarget();
|
|
6133
|
+
hit.setHoverVertex(target.arcs.getVertex2(id));
|
|
6134
|
+
}
|
|
6088
6135
|
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
|
|
6092
|
-
|
|
6093
|
-
if (!table.fieldExists('dx')) {
|
|
6094
|
-
table.addField('dx', 0);
|
|
6095
|
-
}
|
|
6096
|
-
if (!table.fieldExists('dy')) {
|
|
6097
|
-
table.addField('dy', 0);
|
|
6098
|
-
}
|
|
6099
|
-
if (!table.fieldExists('text-anchor')) {
|
|
6100
|
-
table.addField('text-anchor', '');
|
|
6101
|
-
}
|
|
6102
|
-
return table.getRecordAt(id);
|
|
6103
|
-
}
|
|
6136
|
+
function clearHoverVertex() {
|
|
6137
|
+
hit.clearVertexOverlay();
|
|
6138
|
+
// gui.state.vertex_overlay = null;
|
|
6139
|
+
}
|
|
6104
6140
|
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
|
|
6110
|
-
|
|
6111
|
-
|
|
6112
|
-
|
|
6141
|
+
function findDraggableVertices(e) {
|
|
6142
|
+
var target = hit.getHitTarget();
|
|
6143
|
+
var shp = target.layer.shapes[e.id];
|
|
6144
|
+
var p = ext.translatePixelCoords(e.x, e.y);
|
|
6145
|
+
var nearestIds = internal.findNearestVertices(p, shp, target.arcs);
|
|
6146
|
+
var p2 = target.arcs.getVertex2(nearestIds[0]);
|
|
6147
|
+
var dist = geom.distance2D(p[0], p[1], p2[0], p2[1]);
|
|
6148
|
+
var pixelDist = dist / ext.getPixelSize();
|
|
6149
|
+
if (pixelDist > 5) {
|
|
6150
|
+
draggedVertexIds = null;
|
|
6151
|
+
return null;
|
|
6113
6152
|
}
|
|
6153
|
+
return nearestIds;
|
|
6154
|
+
}
|
|
6114
6155
|
|
|
6115
|
-
|
|
6116
|
-
|
|
6117
|
-
|
|
6118
|
-
|
|
6119
|
-
|
|
6120
|
-
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
applyDelta(activeRecord, 'dy', e.dy / scale);
|
|
6124
|
-
textNode = getTextTarget3(e);
|
|
6125
|
-
if (!isMultilineLabel(textNode)) {
|
|
6126
|
-
// update anchor position of single-line labels based on label position
|
|
6127
|
-
// relative to anchor point, for better placement when eventual display font is
|
|
6128
|
-
// different from mapshaper's font.
|
|
6129
|
-
autoUpdateTextAnchor(textNode, activeRecord, getDisplayCoordsById(activeId, hit.getHitTarget().layer, ext));
|
|
6130
|
-
}
|
|
6131
|
-
// updateSymbol(targetTextNode, activeRecord);
|
|
6132
|
-
updateSymbol2(textNode, activeRecord, activeId);
|
|
6133
|
-
}
|
|
6156
|
+
hit.on('dragstart', function(e) {
|
|
6157
|
+
if (!active(e)) return;
|
|
6158
|
+
draggedVertexIds = findDraggableVertices(e);
|
|
6159
|
+
if (!draggedVertexIds) return;
|
|
6160
|
+
setHoverVertex(draggedVertexIds[0]);
|
|
6161
|
+
activeShapeId = e.id;
|
|
6162
|
+
fire('vertex_dragstart');
|
|
6163
|
+
});
|
|
6134
6164
|
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6165
|
+
hit.on('drag', function(e) {
|
|
6166
|
+
if (!active(e) || !draggedVertexIds) return;
|
|
6167
|
+
var target = hit.getHitTarget();
|
|
6168
|
+
var p = ext.translatePixelCoords(e.x, e.y);
|
|
6169
|
+
if (gui.keyboard.shiftIsPressed()) {
|
|
6170
|
+
internal.snapPointToArcEndpoint(p, draggedVertexIds, target.arcs);
|
|
6139
6171
|
}
|
|
6172
|
+
internal.snapVerticesToPoint(draggedVertexIds, p, target.arcs);
|
|
6173
|
+
setHoverVertex(draggedVertexIds[0]);
|
|
6174
|
+
// redrawing the whole map updates the data layer as well as the overlay layer
|
|
6175
|
+
// gui.dispatchEvent('map-needs-refresh');
|
|
6176
|
+
});
|
|
6140
6177
|
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
}
|
|
6178
|
+
hit.on('dragend', function(e) {
|
|
6179
|
+
if (!active(e) || !draggedVertexIds) return;
|
|
6180
|
+
// kludge to get dataset to recalculate internal bounding boxes
|
|
6181
|
+
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
6182
|
+
clearHoverVertex();
|
|
6183
|
+
fire('vertex_dragend');
|
|
6184
|
+
draggedVertexIds = null;
|
|
6185
|
+
activeShapeId = -1;
|
|
6186
|
+
// redraw data layer
|
|
6187
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
6188
|
+
});
|
|
6145
6189
|
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
}
|
|
6190
|
+
// select clicked vertices
|
|
6191
|
+
hit.on('click', function(e) {
|
|
6192
|
+
if (!active(e)) return;
|
|
6193
|
+
var vertices = findDraggableVertices(e); // same selection criteria as for dragging
|
|
6194
|
+
// TODO
|
|
6195
|
+
});
|
|
6153
6196
|
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6197
|
+
// highlight hit vertex in path edit mode
|
|
6198
|
+
hit.on('hover', function(e) {
|
|
6199
|
+
if (!active(e) || draggedVertexIds) return; // no hover effect while dragging
|
|
6200
|
+
var vertexIds = findDraggableVertices(e);
|
|
6201
|
+
if (vertexIds) {
|
|
6202
|
+
setHoverVertex(vertexIds[0]);
|
|
6203
|
+
return;
|
|
6160
6204
|
}
|
|
6161
|
-
|
|
6205
|
+
var target = hit.getHitTarget();
|
|
6206
|
+
var shp = target.layer.shapes[e.id];
|
|
6207
|
+
var p = ext.translatePixelCoords(e.x, e.y);
|
|
6208
|
+
var o = internal.findInsertionPoint(p, shp, target.arcs, ext.getPixelSize());
|
|
6209
|
+
console.log('*', o, p);
|
|
6210
|
+
clearHoverVertex();
|
|
6211
|
+
}, null, 100);
|
|
6162
6212
|
|
|
6163
|
-
|
|
6164
|
-
dragging = true;
|
|
6165
|
-
}
|
|
6213
|
+
}
|
|
6166
6214
|
|
|
6167
|
-
|
|
6168
|
-
|
|
6169
|
-
|
|
6170
|
-
|
|
6171
|
-
activeVertexIds = null;
|
|
6172
|
-
}
|
|
6215
|
+
function initInteractiveEditing(gui, ext, hit) {
|
|
6216
|
+
initLabelDragging(gui, ext, hit);
|
|
6217
|
+
initPointDragging(gui, ext, hit);
|
|
6218
|
+
initVertexDragging(gui, ext, hit);
|
|
6173
6219
|
|
|
6174
|
-
|
|
6175
|
-
|
|
6176
|
-
|
|
6177
|
-
var dy = up.screenY - down.screenY;
|
|
6178
|
-
var dist = Math.sqrt(dx * dx + dy * dy);
|
|
6179
|
-
return dist <= 4 && elapsed < 300;
|
|
6180
|
-
}
|
|
6220
|
+
gui.on('interaction_mode_change', function(e) {
|
|
6221
|
+
gui.undo.clear(); // TODO: put this elsewhere?
|
|
6222
|
+
});
|
|
6181
6223
|
|
|
6224
|
+
// function isClickEvent(up, down) {
|
|
6225
|
+
// var elapsed = Math.abs(down.timeStamp - up.timeStamp);
|
|
6226
|
+
// var dx = up.screenX - down.screenX;
|
|
6227
|
+
// var dy = up.screenY - down.screenY;
|
|
6228
|
+
// var dist = Math.sqrt(dx * dx + dy * dy);
|
|
6229
|
+
// return dist <= 4 && elapsed < 300;
|
|
6230
|
+
// }
|
|
6182
6231
|
}
|
|
6183
6232
|
|
|
6184
6233
|
var darkStroke = "#334",
|
|
@@ -6349,8 +6398,14 @@
|
|
|
6349
6398
|
var geomType = lyr.geometry_type;
|
|
6350
6399
|
var topId = o.id; // pinned id (if pinned) or hover id
|
|
6351
6400
|
var topIdx = -1;
|
|
6352
|
-
var styler = function(
|
|
6353
|
-
utils.extend(
|
|
6401
|
+
var styler = function(style, i) {
|
|
6402
|
+
utils.extend(style, i === topIdx ? topStyle: baseStyle);
|
|
6403
|
+
// kludge to show vertices when editing path shapes
|
|
6404
|
+
if (o.mode == 'vertices') {
|
|
6405
|
+
style.vertices = true;
|
|
6406
|
+
style.vertex_overlay = o.hit_coordinates || null;
|
|
6407
|
+
style.fillColor = null;
|
|
6408
|
+
}
|
|
6354
6409
|
};
|
|
6355
6410
|
var baseStyle = getDefaultStyle(lyr, selectionStyles[geomType]);
|
|
6356
6411
|
var topStyle;
|
|
@@ -6821,19 +6876,25 @@
|
|
|
6821
6876
|
_self.drawVertices = function(shapes, arcs, style, filter) {
|
|
6822
6877
|
var iter = new internal.ShapeIter(arcs);
|
|
6823
6878
|
var t = getScaledTransform(_ext);
|
|
6824
|
-
var radius = (style.strokeWidth * 0.9
|
|
6879
|
+
var radius = (style.strokeWidth > 2 ? style.strokeWidth * 0.9 : 2) * GUI.getPixelRatio() * getScaledLineScale(_ext);
|
|
6825
6880
|
var color = style.strokeColor || 'black';
|
|
6826
|
-
var
|
|
6881
|
+
var radius2 = radius * 2;
|
|
6827
6882
|
_ctx.beginPath();
|
|
6828
6883
|
_ctx.fillStyle = color;
|
|
6829
6884
|
for (var i=0; i<shapes.length; i++) {
|
|
6830
|
-
shp = shapes[i];
|
|
6885
|
+
var shp = shapes[i];
|
|
6831
6886
|
if (!shp || filter && !filter(shp)) continue;
|
|
6832
|
-
|
|
6833
|
-
|
|
6834
|
-
|
|
6887
|
+
for (var j=0; j<shp.length; j++) {
|
|
6888
|
+
iter.init(shp[j]);
|
|
6889
|
+
while (iter.hasNext()) {
|
|
6890
|
+
drawCircle(iter.x * t.mx + t.bx, iter.y * t.my + t.by, radius, _ctx);
|
|
6891
|
+
}
|
|
6835
6892
|
}
|
|
6836
6893
|
}
|
|
6894
|
+
if (style.vertex_overlay) {
|
|
6895
|
+
var p = style.vertex_overlay;
|
|
6896
|
+
drawCircle(p[0] * t.mx + t.bx, p[1] * t.my + t.by, radius2, _ctx);
|
|
6897
|
+
}
|
|
6837
6898
|
_ctx.fill();
|
|
6838
6899
|
_ctx.closePath();
|
|
6839
6900
|
};
|
|
@@ -7886,7 +7947,7 @@
|
|
|
7886
7947
|
_visibleLayers = [], // cached visible map layers
|
|
7887
7948
|
_fullBounds = null,
|
|
7888
7949
|
_intersectionLyr, _activeLyr, _overlayLyr,
|
|
7889
|
-
_inspector, _stack,
|
|
7950
|
+
_inspector, _stack,
|
|
7890
7951
|
_dynamicCRS;
|
|
7891
7952
|
|
|
7892
7953
|
if (gui.options.showMouseCoordinates) {
|
|
@@ -8069,7 +8130,9 @@
|
|
|
8069
8130
|
});
|
|
8070
8131
|
}
|
|
8071
8132
|
|
|
8072
|
-
|
|
8133
|
+
if (gui.interaction) {
|
|
8134
|
+
initInteractiveEditing(gui, _ext, _hit);
|
|
8135
|
+
}
|
|
8073
8136
|
|
|
8074
8137
|
_ext.on('change', function(e) {
|
|
8075
8138
|
if (e.reset) return; // don't need to redraw map here if extent has been reset
|
|
@@ -8089,10 +8152,6 @@
|
|
|
8089
8152
|
function updateOverlayLayer(e) {
|
|
8090
8153
|
var style = getOverlayStyle(_activeLyr.layer, e);
|
|
8091
8154
|
if (style) {
|
|
8092
|
-
// kludge to show vertices when editing path shapes
|
|
8093
|
-
if (gui.state.interaction_mode == 'vertices') {
|
|
8094
|
-
style.vertices = true;
|
|
8095
|
-
}
|
|
8096
8155
|
_overlayLyr = utils.defaults({
|
|
8097
8156
|
layer: filterLayerByIds(_activeLyr.layer, style.ids),
|
|
8098
8157
|
style: style
|
|
@@ -8396,14 +8455,14 @@
|
|
|
8396
8455
|
startEditing();
|
|
8397
8456
|
});
|
|
8398
8457
|
|
|
8399
|
-
function
|
|
8458
|
+
function getManifest() {
|
|
8459
|
+
return window.mapshaper.manifest || {}; // kludge -- bin/mapshaper-gui sets this
|
|
8460
|
+
}
|
|
8461
|
+
|
|
8462
|
+
function getImportOpts(manifest) {
|
|
8400
8463
|
var vars = GUI.getUrlVars();
|
|
8401
8464
|
var opts = {};
|
|
8402
|
-
|
|
8403
|
-
if (Array.isArray(manifest)) {
|
|
8404
|
-
// old-style manifest: an array of filenames
|
|
8405
|
-
opts.files = manifest;
|
|
8406
|
-
} else if (manifest.files) {
|
|
8465
|
+
if (manifest.files) {
|
|
8407
8466
|
opts.files = manifest.files.concat();
|
|
8408
8467
|
} else {
|
|
8409
8468
|
opts.files = [];
|
|
@@ -8421,11 +8480,20 @@
|
|
|
8421
8480
|
return opts;
|
|
8422
8481
|
}
|
|
8423
8482
|
|
|
8483
|
+
function getInitialConsoleCommands() {
|
|
8484
|
+
return getManifest().commands || '';
|
|
8485
|
+
}
|
|
8486
|
+
|
|
8424
8487
|
var startEditing = function() {
|
|
8425
8488
|
var dataLoaded = false,
|
|
8426
|
-
|
|
8489
|
+
manifest = getManifest(),
|
|
8490
|
+
importOpts = getImportOpts(manifest),
|
|
8427
8491
|
gui = new GuiInstance('body');
|
|
8428
8492
|
|
|
8493
|
+
if (manifest.blurb) {
|
|
8494
|
+
El('#splash-screen-blurb').text(manifest.blurb);
|
|
8495
|
+
}
|
|
8496
|
+
|
|
8429
8497
|
new AlertControl(gui);
|
|
8430
8498
|
new RepairControl(gui);
|
|
8431
8499
|
new SimplifyControl(gui);
|
|
@@ -8462,6 +8530,8 @@
|
|
|
8462
8530
|
gui.map.setLayerPinning(o, true);
|
|
8463
8531
|
});
|
|
8464
8532
|
}
|
|
8533
|
+
gui.console.runInitialCommands(getInitialConsoleCommands());
|
|
8534
|
+
|
|
8465
8535
|
});
|
|
8466
8536
|
};
|
|
8467
8537
|
|