mapshaper 0.6.98 → 0.6.100
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 +793 -610
- package/package.json +1 -1
- package/www/mapshaper-gui.js +366 -263
- package/www/mapshaper.js +793 -610
- package/www/page.css +4 -3
package/www/mapshaper-gui.js
CHANGED
|
@@ -876,16 +876,36 @@
|
|
|
876
876
|
};
|
|
877
877
|
|
|
878
878
|
// Filter out delayed click events, e.g. so users can highlight and copy text
|
|
879
|
+
// Filter out context menu clicks
|
|
879
880
|
GUI.onClick = function(el, cb) {
|
|
880
881
|
var time;
|
|
881
882
|
el.on('mousedown', function() {
|
|
882
883
|
time = +new Date();
|
|
883
884
|
});
|
|
884
885
|
el.on('mouseup', function(e) {
|
|
885
|
-
if (
|
|
886
|
+
if (looksLikeContextClick(e)) {
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
889
|
+
if (+new Date() - time < 300) {
|
|
890
|
+
cb(e);
|
|
891
|
+
}
|
|
886
892
|
});
|
|
887
893
|
};
|
|
888
894
|
|
|
895
|
+
GUI.onContextClick = function(el, cb) {
|
|
896
|
+
el.on('mouseup', function(e) {
|
|
897
|
+
if (looksLikeContextClick(e)) {
|
|
898
|
+
e.stopPropagation();
|
|
899
|
+
e.preventDefault();
|
|
900
|
+
cb(e);
|
|
901
|
+
}
|
|
902
|
+
});
|
|
903
|
+
};
|
|
904
|
+
|
|
905
|
+
function looksLikeContextClick(e) {
|
|
906
|
+
return e.button > 1 || e.ctrlKey;
|
|
907
|
+
}
|
|
908
|
+
|
|
889
909
|
// tests if filename is a type that can be used
|
|
890
910
|
// GUI.isReadableFileType = function(filename) {
|
|
891
911
|
// return !!internal.guessInputFileType(filename) || internal.couldBeDsvFile(filename) ||
|
|
@@ -1089,6 +1109,103 @@
|
|
|
1089
1109
|
return _el;
|
|
1090
1110
|
}
|
|
1091
1111
|
|
|
1112
|
+
function filterLayerByIds(lyr, ids) {
|
|
1113
|
+
var shapes;
|
|
1114
|
+
if (lyr.shapes) {
|
|
1115
|
+
shapes = ids.map(function(id) {
|
|
1116
|
+
return lyr.shapes[id];
|
|
1117
|
+
});
|
|
1118
|
+
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
1119
|
+
}
|
|
1120
|
+
return lyr;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
function formatLayerNameForDisplay(name) {
|
|
1124
|
+
return name || '[unnamed]';
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
function cleanLayerName(raw) {
|
|
1128
|
+
return raw.replace(/[\n\t/\\]/g, '')
|
|
1129
|
+
.replace(/^[.\s]+/, '').replace(/[.\s]+$/, '');
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
function updateLayerStackOrder(layers) {
|
|
1133
|
+
// 1. assign ascending ids to unassigned layers above the range of other layers
|
|
1134
|
+
layers.forEach(function(o, i) {
|
|
1135
|
+
if (!o.layer.menu_order) o.layer.menu_order = 1e6 + i;
|
|
1136
|
+
});
|
|
1137
|
+
// 2. sort in ascending order
|
|
1138
|
+
layers.sort(function(a, b) {
|
|
1139
|
+
return a.layer.menu_order - b.layer.menu_order;
|
|
1140
|
+
});
|
|
1141
|
+
// 3. assign consecutve ids
|
|
1142
|
+
layers.forEach(function(o, i) {
|
|
1143
|
+
o.layer.menu_order = i + 1;
|
|
1144
|
+
});
|
|
1145
|
+
return layers;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function sortLayersForMenuDisplay(layers) {
|
|
1149
|
+
layers = updateLayerStackOrder(layers);
|
|
1150
|
+
return layers.reverse();
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
function setLayerPinning(lyr, pinned) {
|
|
1154
|
+
lyr.pinned = !!pinned;
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
|
|
1158
|
+
function adjustPointSymbolSizes(layers, overlayLyr, ext) {
|
|
1159
|
+
var bbox = ext.getBounds().scale(1.5).toArray();
|
|
1160
|
+
var testInBounds = function(p) {
|
|
1161
|
+
return p[0] > bbox[0] && p[0] < bbox[2] && p[1] > bbox[1] && p[1] < bbox[3];
|
|
1162
|
+
};
|
|
1163
|
+
var topTier = 50000;
|
|
1164
|
+
var count = 0;
|
|
1165
|
+
layers = layers.filter(function(lyr) {
|
|
1166
|
+
return lyr.geometry_type == 'point' && lyr.gui.style.dotSize > 0;
|
|
1167
|
+
});
|
|
1168
|
+
layers.forEach(function(lyr) {
|
|
1169
|
+
// short-circuit point counting above top threshold
|
|
1170
|
+
count += countPoints(lyr.gui.displayLayer.shapes, topTier, testInBounds);
|
|
1171
|
+
});
|
|
1172
|
+
count = Math.min(topTier, count) || 1;
|
|
1173
|
+
var k = Math.pow(6 - utils$1.clamp(Math.log10(count), 1, 5), 1.3);
|
|
1174
|
+
|
|
1175
|
+
// zoom adjustments
|
|
1176
|
+
var mapScale = ext.scale();
|
|
1177
|
+
if (mapScale < 0.5) {
|
|
1178
|
+
k *= Math.pow(mapScale + 0.5, 0.35);
|
|
1179
|
+
} else if (mapScale > 1) {
|
|
1180
|
+
// scale faster at first
|
|
1181
|
+
k *= Math.pow(Math.min(mapScale, 4), 0.15);
|
|
1182
|
+
k *= Math.pow(mapScale, 0.05);
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
// scale down when map is small
|
|
1186
|
+
var smallSide = Math.min(ext.width(), ext.height());
|
|
1187
|
+
k *= utils$1.clamp(smallSide / 500, 0.5, 1);
|
|
1188
|
+
|
|
1189
|
+
layers.forEach(function(lyr) {
|
|
1190
|
+
lyr.gui.style.dotScale = k;
|
|
1191
|
+
});
|
|
1192
|
+
if (overlayLyr && overlayLyr.geometry_type == 'point' && overlayLyr.gui.style.dotSize > 0) {
|
|
1193
|
+
overlayLyr.gui.style.dotScale = k;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
function countPoints(shapes, max, filter) {
|
|
1198
|
+
var count = 0;
|
|
1199
|
+
var i, j, n, m, shp;
|
|
1200
|
+
for (i=0, n=shapes.length; i<n && count<max; i++) {
|
|
1201
|
+
shp = shapes[i];
|
|
1202
|
+
for (j=0, m=(shp ? shp.length : 0); j<m; j++) {
|
|
1203
|
+
count += filter(shp[j]) ? 1 : 0;
|
|
1204
|
+
}
|
|
1205
|
+
}
|
|
1206
|
+
return count;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1092
1209
|
async function showPrompt(msg, title) {
|
|
1093
1210
|
var popup = showPopupAlert(msg, title);
|
|
1094
1211
|
return new Promise(function(resolve) {
|
|
@@ -1971,7 +2088,12 @@
|
|
|
1971
2088
|
model.setDefaultTarget([target.layers[0]], target.dataset);
|
|
1972
2089
|
}
|
|
1973
2090
|
}
|
|
1974
|
-
|
|
2091
|
+
if (opts.display_all && importTotal === 0) {
|
|
2092
|
+
model.getLayers().forEach(function(o) {
|
|
2093
|
+
setLayerPinning(o.layer, true);
|
|
2094
|
+
});
|
|
2095
|
+
}
|
|
2096
|
+
model.updated({select: true}); // trigger redraw
|
|
1975
2097
|
}
|
|
1976
2098
|
|
|
1977
2099
|
function clearQueuedFiles() {
|
|
@@ -3206,99 +3328,6 @@
|
|
|
3206
3328
|
}
|
|
3207
3329
|
}
|
|
3208
3330
|
|
|
3209
|
-
function filterLayerByIds(lyr, ids) {
|
|
3210
|
-
var shapes;
|
|
3211
|
-
if (lyr.shapes) {
|
|
3212
|
-
shapes = ids.map(function(id) {
|
|
3213
|
-
return lyr.shapes[id];
|
|
3214
|
-
});
|
|
3215
|
-
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
3216
|
-
}
|
|
3217
|
-
return lyr;
|
|
3218
|
-
}
|
|
3219
|
-
|
|
3220
|
-
function formatLayerNameForDisplay(name) {
|
|
3221
|
-
return name || '[unnamed]';
|
|
3222
|
-
}
|
|
3223
|
-
|
|
3224
|
-
function cleanLayerName(raw) {
|
|
3225
|
-
return raw.replace(/[\n\t/\\]/g, '')
|
|
3226
|
-
.replace(/^[.\s]+/, '').replace(/[.\s]+$/, '');
|
|
3227
|
-
}
|
|
3228
|
-
|
|
3229
|
-
function updateLayerStackOrder(layers) {
|
|
3230
|
-
// 1. assign ascending ids to unassigned layers above the range of other layers
|
|
3231
|
-
layers.forEach(function(o, i) {
|
|
3232
|
-
if (!o.layer.menu_order) o.layer.menu_order = 1e6 + i;
|
|
3233
|
-
});
|
|
3234
|
-
// 2. sort in ascending order
|
|
3235
|
-
layers.sort(function(a, b) {
|
|
3236
|
-
return a.layer.menu_order - b.layer.menu_order;
|
|
3237
|
-
});
|
|
3238
|
-
// 3. assign consecutve ids
|
|
3239
|
-
layers.forEach(function(o, i) {
|
|
3240
|
-
o.layer.menu_order = i + 1;
|
|
3241
|
-
});
|
|
3242
|
-
return layers;
|
|
3243
|
-
}
|
|
3244
|
-
|
|
3245
|
-
function sortLayersForMenuDisplay(layers) {
|
|
3246
|
-
layers = updateLayerStackOrder(layers);
|
|
3247
|
-
return layers.reverse();
|
|
3248
|
-
}
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
function adjustPointSymbolSizes(layers, overlayLyr, ext) {
|
|
3252
|
-
var bbox = ext.getBounds().scale(1.5).toArray();
|
|
3253
|
-
var testInBounds = function(p) {
|
|
3254
|
-
return p[0] > bbox[0] && p[0] < bbox[2] && p[1] > bbox[1] && p[1] < bbox[3];
|
|
3255
|
-
};
|
|
3256
|
-
var topTier = 50000;
|
|
3257
|
-
var count = 0;
|
|
3258
|
-
layers = layers.filter(function(lyr) {
|
|
3259
|
-
return lyr.geometry_type == 'point' && lyr.gui.style.dotSize > 0;
|
|
3260
|
-
});
|
|
3261
|
-
layers.forEach(function(lyr) {
|
|
3262
|
-
// short-circuit point counting above top threshold
|
|
3263
|
-
count += countPoints(lyr.gui.displayLayer.shapes, topTier, testInBounds);
|
|
3264
|
-
});
|
|
3265
|
-
count = Math.min(topTier, count) || 1;
|
|
3266
|
-
var k = Math.pow(6 - utils$1.clamp(Math.log10(count), 1, 5), 1.3);
|
|
3267
|
-
|
|
3268
|
-
// zoom adjustments
|
|
3269
|
-
var mapScale = ext.scale();
|
|
3270
|
-
if (mapScale < 0.5) {
|
|
3271
|
-
k *= Math.pow(mapScale + 0.5, 0.35);
|
|
3272
|
-
} else if (mapScale > 1) {
|
|
3273
|
-
// scale faster at first
|
|
3274
|
-
k *= Math.pow(Math.min(mapScale, 4), 0.15);
|
|
3275
|
-
k *= Math.pow(mapScale, 0.05);
|
|
3276
|
-
}
|
|
3277
|
-
|
|
3278
|
-
// scale down when map is small
|
|
3279
|
-
var smallSide = Math.min(ext.width(), ext.height());
|
|
3280
|
-
k *= utils$1.clamp(smallSide / 500, 0.5, 1);
|
|
3281
|
-
|
|
3282
|
-
layers.forEach(function(lyr) {
|
|
3283
|
-
lyr.gui.style.dotScale = k;
|
|
3284
|
-
});
|
|
3285
|
-
if (overlayLyr && overlayLyr.geometry_type == 'point' && overlayLyr.gui.style.dotSize > 0) {
|
|
3286
|
-
overlayLyr.gui.style.dotScale = k;
|
|
3287
|
-
}
|
|
3288
|
-
}
|
|
3289
|
-
|
|
3290
|
-
function countPoints(shapes, max, filter) {
|
|
3291
|
-
var count = 0;
|
|
3292
|
-
var i, j, n, m, shp;
|
|
3293
|
-
for (i=0, n=shapes.length; i<n && count<max; i++) {
|
|
3294
|
-
shp = shapes[i];
|
|
3295
|
-
for (j=0, m=(shp ? shp.length : 0); j<m; j++) {
|
|
3296
|
-
count += filter(shp[j]) ? 1 : 0;
|
|
3297
|
-
}
|
|
3298
|
-
}
|
|
3299
|
-
return count;
|
|
3300
|
-
}
|
|
3301
|
-
|
|
3302
3331
|
// lyr: a map layer with gui property
|
|
3303
3332
|
// displayCRS: CRS to use for display, or null (which clears any current display CRS)
|
|
3304
3333
|
function projectLayerForDisplay(lyr, displayCRS) {
|
|
@@ -4994,6 +5023,201 @@
|
|
|
4994
5023
|
};
|
|
4995
5024
|
}
|
|
4996
5025
|
|
|
5026
|
+
var openMenu;
|
|
5027
|
+
|
|
5028
|
+
document.addEventListener('mousedown', function(e) {
|
|
5029
|
+
if (e.target.classList.contains('contextmenu-item')) {
|
|
5030
|
+
return; // don't close menu if clicking on a menu link
|
|
5031
|
+
}
|
|
5032
|
+
closeOpenMenu();
|
|
5033
|
+
});
|
|
5034
|
+
|
|
5035
|
+
function closeOpenMenu() {
|
|
5036
|
+
if (openMenu) {
|
|
5037
|
+
openMenu.close();
|
|
5038
|
+
openMenu = null;
|
|
5039
|
+
}
|
|
5040
|
+
}
|
|
5041
|
+
|
|
5042
|
+
function openContextMenu(e, lyr, parent) {
|
|
5043
|
+
var menu = new ContextMenu(parent);
|
|
5044
|
+
closeOpenMenu();
|
|
5045
|
+
menu.open(e, lyr);
|
|
5046
|
+
}
|
|
5047
|
+
|
|
5048
|
+
function ContextMenu(parentArg) {
|
|
5049
|
+
var body = document.querySelector('body');
|
|
5050
|
+
var parent = parentArg || body;
|
|
5051
|
+
// var menu = El('div').addClass('contextmenu rollover').appendTo(body);
|
|
5052
|
+
var menu = El('div').addClass('contextmenu rollover').appendTo(parent);
|
|
5053
|
+
var _open = false;
|
|
5054
|
+
var _openCount = 0;
|
|
5055
|
+
|
|
5056
|
+
this.isOpen = function() {
|
|
5057
|
+
return _open;
|
|
5058
|
+
};
|
|
5059
|
+
|
|
5060
|
+
this.close = close;
|
|
5061
|
+
|
|
5062
|
+
function close() {
|
|
5063
|
+
var count = _openCount;
|
|
5064
|
+
if (!_open) return;
|
|
5065
|
+
setTimeout(function() {
|
|
5066
|
+
if (count == _openCount) {
|
|
5067
|
+
menu.hide();
|
|
5068
|
+
_open = false;
|
|
5069
|
+
}
|
|
5070
|
+
}, 200);
|
|
5071
|
+
}
|
|
5072
|
+
|
|
5073
|
+
function addMenuItem(label, func, prefixArg) {
|
|
5074
|
+
var prefix = prefixArg === undefined ? '• ' : prefixArg;
|
|
5075
|
+
var item = El('div')
|
|
5076
|
+
.appendTo(menu)
|
|
5077
|
+
.addClass('contextmenu-item')
|
|
5078
|
+
.html(prefix + label)
|
|
5079
|
+
.show();
|
|
5080
|
+
|
|
5081
|
+
GUI.onClick(item, function(e) {
|
|
5082
|
+
func();
|
|
5083
|
+
closeOpenMenu();
|
|
5084
|
+
});
|
|
5085
|
+
}
|
|
5086
|
+
|
|
5087
|
+
function addMenuLabel(label) {
|
|
5088
|
+
El('div')
|
|
5089
|
+
.appendTo(menu)
|
|
5090
|
+
.addClass('contextmenu-label')
|
|
5091
|
+
.html(label);
|
|
5092
|
+
}
|
|
5093
|
+
|
|
5094
|
+
this.open = function(e, lyr) {
|
|
5095
|
+
var copyable = e.ids?.length;
|
|
5096
|
+
if (_open) close();
|
|
5097
|
+
menu.empty();
|
|
5098
|
+
|
|
5099
|
+
if (openMenu && openMenu != this) {
|
|
5100
|
+
openMenu.close();
|
|
5101
|
+
}
|
|
5102
|
+
openMenu = this;
|
|
5103
|
+
|
|
5104
|
+
if (e.deleteLayer) {
|
|
5105
|
+
addMenuItem('delete layer', e.deleteLayer, '');
|
|
5106
|
+
}
|
|
5107
|
+
if (e.selectLayer) {
|
|
5108
|
+
addMenuItem('select layer', e.selectLayer, '');
|
|
5109
|
+
}
|
|
5110
|
+
|
|
5111
|
+
if (lyr && lyr.gui.geographic) {
|
|
5112
|
+
if (e.deleteVertex || e.deletePoint || copyable || e.deleteFeature) {
|
|
5113
|
+
|
|
5114
|
+
addMenuLabel('selection');
|
|
5115
|
+
if (e.deleteVertex) {
|
|
5116
|
+
addMenuItem('delete vertex', e.deleteVertex);
|
|
5117
|
+
}
|
|
5118
|
+
if (e.deletePoint) {
|
|
5119
|
+
addMenuItem('delete point', e.deletePoint);
|
|
5120
|
+
}
|
|
5121
|
+
if (e.ids?.length) {
|
|
5122
|
+
addMenuItem('copy as GeoJSON', copyGeoJSON);
|
|
5123
|
+
}
|
|
5124
|
+
if (e.deleteFeature) {
|
|
5125
|
+
addMenuItem(getDeleteLabel(), e.deleteFeature);
|
|
5126
|
+
}
|
|
5127
|
+
}
|
|
5128
|
+
|
|
5129
|
+
if (e.lonlat_coordinates) {
|
|
5130
|
+
addMenuLabel('longitude, latitude');
|
|
5131
|
+
addCoords(e.lonlat_coordinates);
|
|
5132
|
+
}
|
|
5133
|
+
if (e.projected_coordinates) {
|
|
5134
|
+
addMenuLabel('x, y');
|
|
5135
|
+
addCoords(e.projected_coordinates);
|
|
5136
|
+
}
|
|
5137
|
+
}
|
|
5138
|
+
|
|
5139
|
+
if (menu.node().childNodes.length === 0) {
|
|
5140
|
+
return;
|
|
5141
|
+
}
|
|
5142
|
+
|
|
5143
|
+
var rspace = body.clientWidth - e.pageX;
|
|
5144
|
+
var offs = getParentOffset();
|
|
5145
|
+
var xoffs = 10;
|
|
5146
|
+
if (rspace > 150) {
|
|
5147
|
+
menu.css('left', e.pageX - offs.left + xoffs + 'px');
|
|
5148
|
+
menu.css('right', null);
|
|
5149
|
+
} else {
|
|
5150
|
+
menu.css('right', (body.clientWidth - e.pageX - offs.left + xoffs) + 'px');
|
|
5151
|
+
menu.css('left', null);
|
|
5152
|
+
}
|
|
5153
|
+
menu.css('top', (e.pageY - offs.top - 15) + 'px');
|
|
5154
|
+
menu.show();
|
|
5155
|
+
|
|
5156
|
+
_open = true;
|
|
5157
|
+
_openCount++;
|
|
5158
|
+
|
|
5159
|
+
function getParentOffset() { // crossbrowser version
|
|
5160
|
+
if (parent == body) {
|
|
5161
|
+
return {top: 0, left: 0};
|
|
5162
|
+
}
|
|
5163
|
+
|
|
5164
|
+
var box = parent.getBoundingClientRect();
|
|
5165
|
+
var docEl = document.documentElement;
|
|
5166
|
+
|
|
5167
|
+
var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
|
|
5168
|
+
var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
|
5169
|
+
|
|
5170
|
+
var clientTop = docEl.clientTop || body.clientTop || 0;
|
|
5171
|
+
var clientLeft = docEl.clientLeft || body.clientLeft || 0;
|
|
5172
|
+
|
|
5173
|
+
var top = box.top + scrollTop - clientTop;
|
|
5174
|
+
var left = box.left + scrollLeft - clientLeft;
|
|
5175
|
+
|
|
5176
|
+
return { top: Math.round(top), left: Math.round(left) };
|
|
5177
|
+
}
|
|
5178
|
+
|
|
5179
|
+
function getDeleteLabel() {
|
|
5180
|
+
return 'delete ' + (lyr.geometry_type == 'point' ? 'point' : 'shape');
|
|
5181
|
+
}
|
|
5182
|
+
|
|
5183
|
+
function addCoords(p) {
|
|
5184
|
+
var coordStr = p[0] + ',' + p[1];
|
|
5185
|
+
// var displayStr = '• ' + coordStr.replace(/-/g, '–').replace(',', ', ');
|
|
5186
|
+
var displayStr = coordStr.replace(/-/g, '–').replace(',', ', ');
|
|
5187
|
+
addMenuItem(displayStr, function() {
|
|
5188
|
+
saveFileContentToClipboard(coordStr);
|
|
5189
|
+
});
|
|
5190
|
+
}
|
|
5191
|
+
|
|
5192
|
+
function copyGeoJSON() {
|
|
5193
|
+
var opts = {
|
|
5194
|
+
no_replace: true,
|
|
5195
|
+
ids: e.ids,
|
|
5196
|
+
quiet: true
|
|
5197
|
+
};
|
|
5198
|
+
var dataset = lyr.gui.source.dataset;
|
|
5199
|
+
var layer = mapshaper.cmd.filterFeatures(lyr, dataset.arcs, opts);
|
|
5200
|
+
// the drawing tool can send open paths with 'polygon' geometry type,
|
|
5201
|
+
// should be changed to 'polyline'
|
|
5202
|
+
if (layer.geometry_type == 'polygon' && layerHasOpenPaths(layer, dataset.arcs)) {
|
|
5203
|
+
layer.geometry_type = 'polyline';
|
|
5204
|
+
}
|
|
5205
|
+
var features = internal.exportLayerAsGeoJSON(layer, dataset, {rfc7946: true, prettify: true}, true, 'string');
|
|
5206
|
+
var str = internal.geojson.formatCollection({"type": "FeatureCollection"}, features);
|
|
5207
|
+
saveFileContentToClipboard(str);
|
|
5208
|
+
}
|
|
5209
|
+
};
|
|
5210
|
+
}
|
|
5211
|
+
|
|
5212
|
+
|
|
5213
|
+
function layerHasOpenPaths(layer, arcs) {
|
|
5214
|
+
var retn = false;
|
|
5215
|
+
internal.editShapes(layer.shapes, function(part) {
|
|
5216
|
+
if (!geom.pathIsClosed(part, arcs)) retn = true;
|
|
5217
|
+
});
|
|
5218
|
+
return retn;
|
|
5219
|
+
}
|
|
5220
|
+
|
|
4997
5221
|
function LayerControl(gui) {
|
|
4998
5222
|
var model = gui.model;
|
|
4999
5223
|
var map = gui.map;
|
|
@@ -5029,7 +5253,7 @@
|
|
|
5029
5253
|
pinAll.on('click', function() {
|
|
5030
5254
|
var allOn = testAllLayersPinned();
|
|
5031
5255
|
model.getLayers().forEach(function(target) {
|
|
5032
|
-
|
|
5256
|
+
setLayerPinning(target.layer, !allOn);
|
|
5033
5257
|
});
|
|
5034
5258
|
El.findAll('.pinnable', el.node()).forEach(function(item) {
|
|
5035
5259
|
El(item).classed('pinned', !allOn);
|
|
@@ -5200,8 +5424,8 @@
|
|
|
5200
5424
|
|
|
5201
5425
|
html = '<!-- ' + lyr.menu_id + '--><div class="' + classes + '">';
|
|
5202
5426
|
html += rowHTML('name', '<span class="layer-name colored-text dot-underline">' + formatLayerNameForDisplay(lyr.name) + '</span>', 'row1');
|
|
5203
|
-
html += rowHTML('contents', describeLyr(lyr));
|
|
5204
|
-
html += '<img class="close-btn" draggable="false" src="images/close.png">';
|
|
5427
|
+
html += rowHTML('contents', describeLyr(lyr, dataset));
|
|
5428
|
+
// html += '<img class="close-btn" draggable="false" src="images/close.png">';
|
|
5205
5429
|
if (opts.pinnable) {
|
|
5206
5430
|
html += '<img class="eye-btn black-eye" draggable="false" src="images/eye.png">';
|
|
5207
5431
|
html += '<img class="eye-btn green-eye" draggable="false" src="images/eye2.png">';
|
|
@@ -5259,16 +5483,35 @@
|
|
|
5259
5483
|
function initMouseEvents2(entry, id, pinnable) {
|
|
5260
5484
|
initLayerDragging(entry, id);
|
|
5261
5485
|
|
|
5262
|
-
|
|
5263
|
-
GUI.onClick(entry.findChild('img.close-btn'), function(e) {
|
|
5486
|
+
function deleteLayer() {
|
|
5264
5487
|
var target = findLayerById(id);
|
|
5265
|
-
e.stopPropagation();
|
|
5266
5488
|
if (map.isVisibleLayer(target.layer)) {
|
|
5267
5489
|
// TODO: check for double map refresh after model.deleteLayer() below
|
|
5268
|
-
|
|
5490
|
+
setLayerPinning(target.layer, false);
|
|
5269
5491
|
}
|
|
5270
5492
|
model.deleteLayer(target.layer, target.dataset);
|
|
5271
|
-
}
|
|
5493
|
+
}
|
|
5494
|
+
|
|
5495
|
+
function selectLayer(closeMenu) {
|
|
5496
|
+
var target = findLayerById(id);
|
|
5497
|
+
// don't select if user is typing or dragging
|
|
5498
|
+
if (GUI.textIsSelected() || dragging) return;
|
|
5499
|
+
// undo any temporary hiding when layer is selected
|
|
5500
|
+
target.layer.hidden = false;
|
|
5501
|
+
if (!map.isActiveLayer(target.layer)) {
|
|
5502
|
+
model.selectLayer(target.layer, target.dataset);
|
|
5503
|
+
}
|
|
5504
|
+
// close menu after a delay
|
|
5505
|
+
if (closeMenu === true) setTimeout(function() {
|
|
5506
|
+
gui.clearMode();
|
|
5507
|
+
}, 230);
|
|
5508
|
+
}
|
|
5509
|
+
|
|
5510
|
+
// init delete button
|
|
5511
|
+
// GUI.onClick(entry.findChild('img.close-btn'), function(e) {
|
|
5512
|
+
// e.stopPropagation();
|
|
5513
|
+
// deleteLayer();
|
|
5514
|
+
// });
|
|
5272
5515
|
|
|
5273
5516
|
if (pinnable) {
|
|
5274
5517
|
// init pin button
|
|
@@ -5289,7 +5532,7 @@
|
|
|
5289
5532
|
}
|
|
5290
5533
|
lyr.hidden = hidden;
|
|
5291
5534
|
lyr.unpinned = unpinned;
|
|
5292
|
-
|
|
5535
|
+
setLayerPinning(lyr, pinned);
|
|
5293
5536
|
entry.classed('pinned', pinned);
|
|
5294
5537
|
entry.classed('invisible', hidden);
|
|
5295
5538
|
updatePinAllButton();
|
|
@@ -5315,30 +5558,30 @@
|
|
|
5315
5558
|
|
|
5316
5559
|
// init click-to-select
|
|
5317
5560
|
GUI.onClick(entry, function() {
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
setTimeout(function() {
|
|
5328
|
-
gui.clearMode();
|
|
5329
|
-
}, 230);
|
|
5561
|
+
selectLayer(true);
|
|
5562
|
+
});
|
|
5563
|
+
|
|
5564
|
+
GUI.onContextClick(entry, function(e) {
|
|
5565
|
+
e.deleteLayer = deleteLayer;
|
|
5566
|
+
e.selectLayer = selectLayer;
|
|
5567
|
+
// contextMenu.open(e);
|
|
5568
|
+
// openContextMenu(e, null, entry.node())
|
|
5569
|
+
openContextMenu(e, null, null);
|
|
5330
5570
|
});
|
|
5331
5571
|
}
|
|
5332
5572
|
|
|
5333
|
-
function describeLyr(lyr) {
|
|
5573
|
+
function describeLyr(lyr, dataset) {
|
|
5334
5574
|
var n = internal.getFeatureCount(lyr),
|
|
5575
|
+
isFrame = internal.isFrameLayer(lyr, dataset.arcs),
|
|
5335
5576
|
str, type;
|
|
5336
5577
|
if (lyr.data && !lyr.shapes) {
|
|
5337
5578
|
type = 'data record';
|
|
5338
5579
|
} else if (lyr.geometry_type) {
|
|
5339
5580
|
type = lyr.geometry_type + ' feature';
|
|
5340
5581
|
}
|
|
5341
|
-
if (
|
|
5582
|
+
if (isFrame) {
|
|
5583
|
+
str = 'map frame';
|
|
5584
|
+
} else if (type) {
|
|
5342
5585
|
str = utils$1.format('%,d %s%s', n, type, utils$1.pluralSuffix(n));
|
|
5343
5586
|
} else {
|
|
5344
5587
|
str = "[empty]";
|
|
@@ -12477,10 +12720,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12477
12720
|
drawLayers();
|
|
12478
12721
|
};
|
|
12479
12722
|
|
|
12480
|
-
this.setLayerPinning = function(target, pinned) {
|
|
12481
|
-
target.layer.pinned = !!pinned;
|
|
12482
|
-
};
|
|
12483
|
-
|
|
12484
12723
|
this.pixelCoordsToLngLatCoords = function(x, y) {
|
|
12485
12724
|
var crsFrom = this.getDisplayCRS();
|
|
12486
12725
|
if (!crsFrom) return null; // e.g. table view
|
|
@@ -12904,11 +13143,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12904
13143
|
updateLayerStyles(contentLayers);
|
|
12905
13144
|
updateLayerStackOrder(model.getLayers());// update menu_order property of all layers
|
|
12906
13145
|
}
|
|
12907
|
-
adjustPointSymbolSizes(contentLayers, _overlayLyr, _ext);
|
|
12908
13146
|
sortMapLayers(contentLayers);
|
|
12909
13147
|
if (_intersectionLyr) {
|
|
12910
13148
|
contentLayers = contentLayers.concat(_intersectionLyr);
|
|
12911
13149
|
}
|
|
13150
|
+
// moved this below intersection layer addition, so intersection dots get scaled
|
|
13151
|
+
adjustPointSymbolSizes(contentLayers, _overlayLyr, _ext);
|
|
13152
|
+
|
|
12912
13153
|
// RENDERING
|
|
12913
13154
|
// draw main content layers
|
|
12914
13155
|
_renderer.drawMainLayers(contentLayers, action);
|
|
@@ -12954,139 +13195,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12954
13195
|
});
|
|
12955
13196
|
}
|
|
12956
13197
|
|
|
12957
|
-
function ContextMenu() {
|
|
12958
|
-
var body = document.querySelector('body');
|
|
12959
|
-
var menu = El('div').addClass('contextmenu rollover').appendTo(body);
|
|
12960
|
-
var _open = false;
|
|
12961
|
-
var _openCount = 0;
|
|
12962
|
-
document.addEventListener('mousedown', close);
|
|
12963
|
-
|
|
12964
|
-
this.isOpen = function() {
|
|
12965
|
-
return _open;
|
|
12966
|
-
};
|
|
12967
|
-
|
|
12968
|
-
function close() {
|
|
12969
|
-
var count = _openCount;
|
|
12970
|
-
if (!_open) return;
|
|
12971
|
-
setTimeout(function() {
|
|
12972
|
-
if (count == _openCount) {
|
|
12973
|
-
menu.hide();
|
|
12974
|
-
_open = false;
|
|
12975
|
-
}
|
|
12976
|
-
}, 200);
|
|
12977
|
-
}
|
|
12978
|
-
|
|
12979
|
-
function addMenuItem(label, func) {
|
|
12980
|
-
var prefix = '• ';
|
|
12981
|
-
|
|
12982
|
-
El('div')
|
|
12983
|
-
.appendTo(menu)
|
|
12984
|
-
.addClass('contextmenu-item')
|
|
12985
|
-
.html(prefix + label)
|
|
12986
|
-
.on('click', func)
|
|
12987
|
-
.show();
|
|
12988
|
-
}
|
|
12989
|
-
|
|
12990
|
-
function addMenuLabel(label) {
|
|
12991
|
-
El('div')
|
|
12992
|
-
.appendTo(menu)
|
|
12993
|
-
.addClass('contextmenu-label')
|
|
12994
|
-
.html(label);
|
|
12995
|
-
}
|
|
12996
|
-
|
|
12997
|
-
this.open = function(e, lyr) {
|
|
12998
|
-
var copyable = e.ids?.length;
|
|
12999
|
-
if (lyr && !lyr.gui.geographic) return; // no popup for tabular data
|
|
13000
|
-
menu.empty();
|
|
13001
|
-
|
|
13002
|
-
// menu contents
|
|
13003
|
-
//
|
|
13004
|
-
if (e.deleteVertex || e.deletePoint || copyable || e.deleteFeature) {
|
|
13005
|
-
|
|
13006
|
-
addMenuLabel('selection');
|
|
13007
|
-
if (e.deleteVertex) {
|
|
13008
|
-
addMenuItem('delete vertex', e.deleteVertex);
|
|
13009
|
-
}
|
|
13010
|
-
if (e.deletePoint) {
|
|
13011
|
-
addMenuItem('delete point', e.deletePoint);
|
|
13012
|
-
}
|
|
13013
|
-
if (e.ids?.length) {
|
|
13014
|
-
addMenuItem('copy as GeoJSON', copyGeoJSON);
|
|
13015
|
-
}
|
|
13016
|
-
if (e.deleteFeature) {
|
|
13017
|
-
addMenuItem(getDeleteLabel(), e.deleteFeature);
|
|
13018
|
-
}
|
|
13019
|
-
}
|
|
13020
|
-
|
|
13021
|
-
if (e.lonlat_coordinates) {
|
|
13022
|
-
addMenuLabel('longitude, latitude');
|
|
13023
|
-
addCoords(e.lonlat_coordinates);
|
|
13024
|
-
}
|
|
13025
|
-
if (e.projected_coordinates) {
|
|
13026
|
-
addMenuLabel('x, y');
|
|
13027
|
-
addCoords(e.projected_coordinates);
|
|
13028
|
-
}
|
|
13029
|
-
|
|
13030
|
-
if (menu.node().childNodes.length === 0) {
|
|
13031
|
-
return;
|
|
13032
|
-
}
|
|
13033
|
-
|
|
13034
|
-
_open = true;
|
|
13035
|
-
_openCount++;
|
|
13036
|
-
var rspace = body.clientWidth - e.pageX;
|
|
13037
|
-
var xoffs = 10;
|
|
13038
|
-
if (rspace > 150) {
|
|
13039
|
-
menu.css('left', e.pageX + xoffs + 'px');
|
|
13040
|
-
menu.css('right', null);
|
|
13041
|
-
} else {
|
|
13042
|
-
menu.css('right', (body.clientWidth - e.pageX + xoffs) + 'px');
|
|
13043
|
-
menu.css('left', null);
|
|
13044
|
-
}
|
|
13045
|
-
menu.css('top', (e.pageY - 15) + 'px');
|
|
13046
|
-
menu.show();
|
|
13047
|
-
|
|
13048
|
-
function getDeleteLabel() {
|
|
13049
|
-
return 'delete ' + (lyr.geometry_type == 'point' ? 'point' : 'shape');
|
|
13050
|
-
}
|
|
13051
|
-
|
|
13052
|
-
function addCoords(p) {
|
|
13053
|
-
var coordStr = p[0] + ',' + p[1];
|
|
13054
|
-
// var displayStr = '• ' + coordStr.replace(/-/g, '–').replace(',', ', ');
|
|
13055
|
-
var displayStr = coordStr.replace(/-/g, '–').replace(',', ', ');
|
|
13056
|
-
addMenuItem(displayStr, function() {
|
|
13057
|
-
saveFileContentToClipboard(coordStr);
|
|
13058
|
-
});
|
|
13059
|
-
}
|
|
13060
|
-
|
|
13061
|
-
function copyGeoJSON() {
|
|
13062
|
-
var opts = {
|
|
13063
|
-
no_replace: true,
|
|
13064
|
-
ids: e.ids,
|
|
13065
|
-
quiet: true
|
|
13066
|
-
};
|
|
13067
|
-
var dataset = lyr.gui.source.dataset;
|
|
13068
|
-
var layer = mapshaper.cmd.filterFeatures(lyr, dataset.arcs, opts);
|
|
13069
|
-
// the drawing tool can send open paths with 'polygon' geometry type,
|
|
13070
|
-
// should be changed to 'polyline'
|
|
13071
|
-
if (layer.geometry_type == 'polygon' && layerHasOpenPaths(layer, dataset.arcs)) {
|
|
13072
|
-
layer.geometry_type = 'polyline';
|
|
13073
|
-
}
|
|
13074
|
-
var features = internal.exportLayerAsGeoJSON(layer, dataset, {rfc7946: true, prettify: true}, true, 'string');
|
|
13075
|
-
var str = internal.geojson.formatCollection({"type": "FeatureCollection"}, features);
|
|
13076
|
-
saveFileContentToClipboard(str);
|
|
13077
|
-
}
|
|
13078
|
-
};
|
|
13079
|
-
}
|
|
13080
|
-
|
|
13081
|
-
|
|
13082
|
-
function layerHasOpenPaths(layer, arcs) {
|
|
13083
|
-
var retn = false;
|
|
13084
|
-
internal.editShapes(layer.shapes, function(part) {
|
|
13085
|
-
if (!geom.pathIsClosed(part, arcs)) retn = true;
|
|
13086
|
-
});
|
|
13087
|
-
return retn;
|
|
13088
|
-
}
|
|
13089
|
-
|
|
13090
13198
|
function loadScript(url, cb) {
|
|
13091
13199
|
var script = document.createElement('script');
|
|
13092
13200
|
script.onload = cb;
|
|
@@ -13558,14 +13666,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
13558
13666
|
dataLoaded = true;
|
|
13559
13667
|
gui.buttons.show();
|
|
13560
13668
|
gui.basemap.show();
|
|
13561
|
-
El('#mode-buttons').show();
|
|
13562
|
-
El('#splash-buttons').hide();
|
|
13669
|
+
El('#mode-buttons').show(); // show Simplify, Console, Export, etc.
|
|
13670
|
+
El('#splash-buttons').hide(); // hide Wiki, Github buttons
|
|
13563
13671
|
El('body').addClass('map-view');
|
|
13564
|
-
if (importOpts.display_all) {
|
|
13565
|
-
gui.model.getLayers().forEach(function(o) {
|
|
13566
|
-
gui.map.setLayerPinning(o, true);
|
|
13567
|
-
});
|
|
13568
|
-
}
|
|
13569
13672
|
gui.console.runInitialCommands(getInitialConsoleCommands());
|
|
13570
13673
|
});
|
|
13571
13674
|
};
|