mapshaper 0.6.76 → 0.6.77
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 +17 -9
- package/package.json +1 -1
- package/www/index.html +35 -48
- package/www/mapshaper-gui.js +1097 -987
- package/www/mapshaper.js +17 -9
- package/www/page.css +60 -108
package/www/mapshaper-gui.js
CHANGED
|
@@ -1475,6 +1475,7 @@
|
|
|
1475
1475
|
|
|
1476
1476
|
async function saveSnapshot(gui) {
|
|
1477
1477
|
var obj = await captureSnapshot(gui);
|
|
1478
|
+
if (!obj) return;
|
|
1478
1479
|
// storing an unpacked object is usually a bit faster (~20%)
|
|
1479
1480
|
// note: we don't know the size of unpacked snapshot objects
|
|
1480
1481
|
// obj = internal.pack(obj);
|
|
@@ -1554,12 +1555,13 @@
|
|
|
1554
1555
|
}
|
|
1555
1556
|
|
|
1556
1557
|
async function captureSnapshot(gui) {
|
|
1557
|
-
var
|
|
1558
|
-
|
|
1558
|
+
var lyr = gui.model.getActiveLayer()?.layer;
|
|
1559
|
+
if (!lyr) return null; // no data -- no snapshot
|
|
1560
|
+
lyr.active = true;
|
|
1559
1561
|
// compact: true applies compression to vector coordinates, for ~30% reduction
|
|
1560
1562
|
// in file size in a typical polygon or polyline file, but longer processing time
|
|
1561
1563
|
var opts = {compact: false};
|
|
1562
|
-
|
|
1564
|
+
var datasets = gui.model.getDatasets();
|
|
1563
1565
|
// console.time('msx');
|
|
1564
1566
|
var obj = await internal.exportDatasetsToPack(datasets, opts);
|
|
1565
1567
|
// console.timeEnd('msx')
|
|
@@ -1752,7 +1754,7 @@
|
|
|
1752
1754
|
}],
|
|
1753
1755
|
info: {}
|
|
1754
1756
|
};
|
|
1755
|
-
if (type == 'polygon' || type == '
|
|
1757
|
+
if (type == 'polygon' || type == 'polyline') {
|
|
1756
1758
|
dataset.arcs = new internal.ArcCollection();
|
|
1757
1759
|
}
|
|
1758
1760
|
if (crsInfo) {
|
|
@@ -1864,7 +1866,6 @@
|
|
|
1864
1866
|
var initialImport = true;
|
|
1865
1867
|
var importCount = 0;
|
|
1866
1868
|
var importTotal = 0;
|
|
1867
|
-
var overQuickView = false;
|
|
1868
1869
|
var useQuickView = false;
|
|
1869
1870
|
var queuedFiles = [];
|
|
1870
1871
|
var manifestFiles = opts.files || [];
|
|
@@ -1874,50 +1875,48 @@
|
|
|
1874
1875
|
catalog = new CatalogControl(gui, opts.catalog, downloadFiles);
|
|
1875
1876
|
}
|
|
1876
1877
|
|
|
1877
|
-
new SimpleButton('#import-
|
|
1878
|
-
new SimpleButton('#import-
|
|
1879
|
-
new DropControl(gui, 'body',
|
|
1880
|
-
new FileChooser('#
|
|
1881
|
-
new FileChooser('#import-buttons .add-btn', receiveFiles);
|
|
1878
|
+
var submitBtn = new SimpleButton('#import-options .submit-btn').on('click', importQueuedFiles);
|
|
1879
|
+
new SimpleButton('#import-options .cancel-btn').on('click', gui.clearMode);
|
|
1880
|
+
new DropControl(gui, 'body', receiveFilesWithOption);
|
|
1881
|
+
new FileChooser('#import-options .add-btn', receiveFilesWithOption);
|
|
1882
1882
|
new FileChooser('#add-file-btn', receiveFiles);
|
|
1883
1883
|
new SimpleButton('#add-empty-btn').on('click', function() {
|
|
1884
1884
|
gui.clearMode(); // close import dialog
|
|
1885
1885
|
openAddLayerPopup(gui);
|
|
1886
1886
|
});
|
|
1887
|
-
initDropArea('#import-quick-drop', true);
|
|
1888
|
-
initDropArea('#import-drop');
|
|
1887
|
+
// initDropArea('#import-quick-drop', true);
|
|
1888
|
+
// initDropArea('#import-drop');
|
|
1889
1889
|
gui.keyboard.onMenuSubmit(El('#import-options'), importQueuedFiles);
|
|
1890
1890
|
|
|
1891
1891
|
gui.addMode('import', turnOn, turnOff);
|
|
1892
1892
|
gui.enterMode('import');
|
|
1893
1893
|
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
}
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
function initDropArea(el, isQuick) {
|
|
1902
|
-
var area = El(el)
|
|
1903
|
-
.on('dragleave', onout)
|
|
1904
|
-
.on('dragover', function() {overQuickView = !!isQuick; onover();})
|
|
1905
|
-
.on('mouseover', onover)
|
|
1906
|
-
.on('mouseout', onout);
|
|
1907
|
-
|
|
1908
|
-
function onover() {
|
|
1909
|
-
area.addClass('dragover');
|
|
1894
|
+
function turnOn() {
|
|
1895
|
+
if (manifestFiles.length > 0) {
|
|
1896
|
+
downloadFiles(manifestFiles, true);
|
|
1897
|
+
manifestFiles = [];
|
|
1898
|
+
} else if (model.isEmpty()) {
|
|
1899
|
+
showImportMenu();
|
|
1910
1900
|
}
|
|
1901
|
+
}
|
|
1911
1902
|
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1903
|
+
function turnOff() {
|
|
1904
|
+
var target;
|
|
1905
|
+
if (catalog) catalog.reset(); // re-enable clickable catalog
|
|
1906
|
+
if (importCount > 0) {
|
|
1907
|
+
onImportComplete();
|
|
1908
|
+
importTotal += importCount;
|
|
1909
|
+
importCount = 0;
|
|
1915
1910
|
}
|
|
1911
|
+
gui.clearProgressMessage();
|
|
1912
|
+
initialImport = false; // unset 'quick view' mode, if on
|
|
1913
|
+
clearQueuedFiles();
|
|
1914
|
+
hideImportMenu();
|
|
1916
1915
|
}
|
|
1917
1916
|
|
|
1918
1917
|
async function importQueuedFiles() {
|
|
1919
|
-
gui.container.removeClass('queued-files');
|
|
1920
|
-
|
|
1918
|
+
// gui.container.removeClass('queued-files');
|
|
1919
|
+
hideImportMenu();
|
|
1921
1920
|
var files = queuedFiles;
|
|
1922
1921
|
try {
|
|
1923
1922
|
if (files.length > 0) {
|
|
@@ -1934,27 +1933,7 @@
|
|
|
1934
1933
|
}
|
|
1935
1934
|
}
|
|
1936
1935
|
|
|
1937
|
-
function turnOn() {
|
|
1938
|
-
if (manifestFiles.length > 0) {
|
|
1939
|
-
downloadFiles(manifestFiles, true);
|
|
1940
|
-
manifestFiles = [];
|
|
1941
|
-
} else if (model.isEmpty()) {
|
|
1942
|
-
gui.container.addClass('splash-screen');
|
|
1943
|
-
}
|
|
1944
|
-
}
|
|
1945
1936
|
|
|
1946
|
-
function turnOff() {
|
|
1947
|
-
var target;
|
|
1948
|
-
if (catalog) catalog.reset(); // re-enable clickable catalog
|
|
1949
|
-
if (importCount > 0) {
|
|
1950
|
-
onImportComplete();
|
|
1951
|
-
importTotal += importCount;
|
|
1952
|
-
importCount = 0;
|
|
1953
|
-
}
|
|
1954
|
-
gui.clearProgressMessage();
|
|
1955
|
-
initialImport = false; // unset 'quick view' mode, if on
|
|
1956
|
-
clearQueuedFiles();
|
|
1957
|
-
}
|
|
1958
1937
|
|
|
1959
1938
|
function onImportComplete() {
|
|
1960
1939
|
// display last layer of last imported dataset
|
|
@@ -1987,6 +1966,7 @@
|
|
|
1987
1966
|
}, []);
|
|
1988
1967
|
}
|
|
1989
1968
|
|
|
1969
|
+
|
|
1990
1970
|
function showQueuedFiles() {
|
|
1991
1971
|
var list = gui.container.findChild('.dropped-file-list').empty();
|
|
1992
1972
|
queuedFiles.forEach(function(f) {
|
|
@@ -2006,13 +1986,20 @@
|
|
|
2006
1986
|
}
|
|
2007
1987
|
});
|
|
2008
1988
|
});
|
|
1989
|
+
submitBtn.classed('disabled', queuedFiles.length === 0);
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
function receiveFilesWithOption(files) {
|
|
1993
|
+
var quickView = !El('.advanced-import-options').node().checked;
|
|
1994
|
+
receiveFiles(files, quickView);
|
|
2009
1995
|
}
|
|
2010
1996
|
|
|
2011
|
-
async function receiveFiles(files) {
|
|
1997
|
+
async function receiveFiles(files, quickView) {
|
|
2012
1998
|
var names = getFileNames(files);
|
|
2013
1999
|
var expanded = [];
|
|
2014
2000
|
if (files.length === 0) return;
|
|
2015
|
-
useQuickView = importTotal === 0 && (opts.quick_view ||
|
|
2001
|
+
useQuickView = importTotal === 0 && (opts.quick_view ||
|
|
2002
|
+
quickView);
|
|
2016
2003
|
try {
|
|
2017
2004
|
expanded = await expandFiles(files);
|
|
2018
2005
|
} catch(e) {
|
|
@@ -2030,12 +2017,23 @@
|
|
|
2030
2017
|
if (useQuickView) {
|
|
2031
2018
|
await importQueuedFiles();
|
|
2032
2019
|
} else {
|
|
2033
|
-
|
|
2034
|
-
El('#path-import-options').classed('hidden', !filesMayContainPaths(queuedFiles));
|
|
2035
|
-
showQueuedFiles();
|
|
2020
|
+
showImportMenu();
|
|
2036
2021
|
}
|
|
2037
2022
|
}
|
|
2038
2023
|
|
|
2024
|
+
function showImportMenu() {
|
|
2025
|
+
// gui.container.addClass('queued-files');
|
|
2026
|
+
El('#import-options').show();
|
|
2027
|
+
gui.container.classed('queued-files', queuedFiles.length > 0);
|
|
2028
|
+
El('#path-import-options').classed('hidden', !filesMayContainPaths(queuedFiles));
|
|
2029
|
+
showQueuedFiles();
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
function hideImportMenu() {
|
|
2033
|
+
// gui.container.removeClass('queued-files');
|
|
2034
|
+
El('#import-options').hide();
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2039
2037
|
function getFileNames(files) {
|
|
2040
2038
|
return Array.from(files).map(function(f) {return f.name;});
|
|
2041
2039
|
}
|
|
@@ -2531,7 +2529,11 @@
|
|
|
2531
2529
|
// prevent GUI message popup on error
|
|
2532
2530
|
internal.setLoggingForCLI();
|
|
2533
2531
|
try {
|
|
2534
|
-
|
|
2532
|
+
if (!dataset || internal.datasetIsEmpty(dataset)) {
|
|
2533
|
+
crs = internal.parseCrsString('wgs84');
|
|
2534
|
+
} else {
|
|
2535
|
+
crs = internal.getDatasetCRS(dataset);
|
|
2536
|
+
}
|
|
2535
2537
|
} catch(e) {
|
|
2536
2538
|
err = e.message;
|
|
2537
2539
|
}
|
|
@@ -2923,235 +2925,699 @@
|
|
|
2923
2925
|
return internal.findPropertiesBySymbolGeom(fields, lyr.geometry_type);
|
|
2924
2926
|
}
|
|
2925
2927
|
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
}
|
|
2928
|
+
// Create low-detail versions of large arc collections for faster rendering
|
|
2929
|
+
// at zoomed-out scales.
|
|
2930
|
+
function enhanceArcCollectionForDisplay(unfilteredArcs) {
|
|
2931
|
+
var size = unfilteredArcs.getPointCount(),
|
|
2932
|
+
filteredArcs, filteredSegLen;
|
|
2932
2933
|
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
lyr.gui.displayArcs.setRetainedInterval(z);
|
|
2934
|
+
// Only generate low-detail arcs for larger datasets
|
|
2935
|
+
if (size > 5e5) {
|
|
2936
|
+
update();
|
|
2937
2937
|
}
|
|
2938
|
-
}
|
|
2939
2938
|
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2939
|
+
function update() {
|
|
2940
|
+
if (unfilteredArcs.getVertexData().zz) {
|
|
2941
|
+
// Use precalculated simplification data for vertex filtering, if available
|
|
2942
|
+
filteredArcs = initFilteredArcs(unfilteredArcs);
|
|
2943
|
+
filteredSegLen = internal.getAvgSegment(filteredArcs);
|
|
2944
|
+
} else {
|
|
2945
|
+
// Use fast simplification as a fallback
|
|
2946
|
+
filteredSegLen = internal.getAvgSegment(unfilteredArcs) * 4;
|
|
2947
|
+
filteredArcs = internal.simplifyArcsFast(unfilteredArcs, filteredSegLen);
|
|
2948
|
+
}
|
|
2943
2949
|
}
|
|
2944
|
-
}
|
|
2945
2950
|
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
d.r = 3; // show a black circle if layer is styled
|
|
2955
|
-
}
|
|
2956
|
-
if (layer.geometry_type == 'polyline' || layer.geometry_type == 'polygon') {
|
|
2957
|
-
if (fields.includes('stroke')) d.stroke = 'black';
|
|
2958
|
-
if (fields.includes('stroke-width')) d['stroke-width'] = 1;
|
|
2951
|
+
function initFilteredArcs(arcs) {
|
|
2952
|
+
var filterPct = 0.08;
|
|
2953
|
+
var nth = Math.ceil(arcs.getPointCount() / 5e5);
|
|
2954
|
+
var currInterval = arcs.getRetainedInterval();
|
|
2955
|
+
var filterZ = arcs.getThresholdByPct(filterPct, nth);
|
|
2956
|
+
var filteredArcs = arcs.setRetainedInterval(filterZ).getFilteredCopy();
|
|
2957
|
+
arcs.setRetainedInterval(currInterval); // reset current simplification
|
|
2958
|
+
return filteredArcs;
|
|
2959
2959
|
}
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2960
|
+
|
|
2961
|
+
// TODO: better job of detecting arc change... e.g. revision number
|
|
2962
|
+
unfilteredArcs.getScaledArcs = function(ext) {
|
|
2963
|
+
// check for changes in the number of arcs (probably due to editing)
|
|
2964
|
+
if (filteredArcs && filteredArcs.size() != unfilteredArcs.size()) {
|
|
2965
|
+
// arc count has changed... probably due to editing
|
|
2966
|
+
update();
|
|
2967
|
+
if (filteredArcs.size() != unfilteredArcs.size()) {
|
|
2968
|
+
throw Error('Internal error');
|
|
2969
|
+
}
|
|
2963
2970
|
}
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2971
|
+
if (filteredArcs) {
|
|
2972
|
+
// match simplification of unfiltered arcs
|
|
2973
|
+
filteredArcs.setRetainedInterval(unfilteredArcs.getRetainedInterval());
|
|
2974
|
+
}
|
|
2975
|
+
// switch to filtered version of arcs at small scales
|
|
2976
|
+
var unitsPerPixel = 1/ext.getTransform().mx,
|
|
2977
|
+
useFiltering = filteredArcs && unitsPerPixel > filteredSegLen * 1.5;
|
|
2978
|
+
return useFiltering ? filteredArcs : unfilteredArcs;
|
|
2979
|
+
};
|
|
2968
2980
|
}
|
|
2969
2981
|
|
|
2970
|
-
function
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2982
|
+
function getDisplayLayerForTable(tableArg) {
|
|
2983
|
+
var table = tableArg || new internal.DataTable(0),
|
|
2984
|
+
n = table.size(),
|
|
2985
|
+
cellWidth = 12,
|
|
2986
|
+
cellHeight = 5,
|
|
2987
|
+
gutter = 6,
|
|
2988
|
+
arcs = [],
|
|
2989
|
+
shapes = [],
|
|
2990
|
+
aspectRatio = 1.1,
|
|
2991
|
+
x, y, col, row, blockSize;
|
|
2976
2992
|
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2993
|
+
if (n > 10000) {
|
|
2994
|
+
arcs = null;
|
|
2995
|
+
gutter = 0;
|
|
2996
|
+
cellWidth = 4;
|
|
2997
|
+
cellHeight = 4;
|
|
2998
|
+
aspectRatio = 1.45;
|
|
2999
|
+
} else if (n > 5000) {
|
|
3000
|
+
cellWidth = 5;
|
|
3001
|
+
gutter = 3;
|
|
3002
|
+
aspectRatio = 1.45;
|
|
3003
|
+
} else if (n > 1000) {
|
|
3004
|
+
gutter = 3;
|
|
3005
|
+
cellWidth = 8;
|
|
3006
|
+
aspectRatio = 1.3;
|
|
2981
3007
|
}
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
3008
|
+
|
|
3009
|
+
if (n < 25) {
|
|
3010
|
+
blockSize = n;
|
|
3011
|
+
} else {
|
|
3012
|
+
blockSize = Math.sqrt(n * (cellWidth + gutter) / cellHeight / aspectRatio) | 0;
|
|
2986
3013
|
}
|
|
2987
|
-
}
|
|
2988
3014
|
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
3015
|
+
for (var i=0; i<n; i++) {
|
|
3016
|
+
row = i % blockSize;
|
|
3017
|
+
col = Math.floor(i / blockSize);
|
|
3018
|
+
x = col * (cellWidth + gutter);
|
|
3019
|
+
y = cellHeight * (blockSize - row);
|
|
3020
|
+
if (arcs) {
|
|
3021
|
+
arcs.push(getArc(x, y, cellWidth, cellHeight));
|
|
3022
|
+
shapes.push([[i]]);
|
|
3023
|
+
} else {
|
|
3024
|
+
shapes.push([[x, y]]);
|
|
3025
|
+
}
|
|
2996
3026
|
}
|
|
2997
|
-
appendVertex$1(lyr, p1);
|
|
2998
|
-
appendVertex$1(lyr, p2);
|
|
2999
|
-
appendNewDataRecord(lyr);
|
|
3000
|
-
}
|
|
3001
3027
|
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
internal.insertVertex(lyr.gui.source.dataset.arcs, id, p);
|
|
3005
|
-
if (isProjectedLayer(lyr)) {
|
|
3006
|
-
internal.insertVertex(lyr.gui.displayArcs, id, lyr.gui.projectPoint(p[0], p[1]));
|
|
3028
|
+
function getArc(x, y, w, h) {
|
|
3029
|
+
return [[x, y], [x + w, y], [x + w, y - h], [x, y - h], [x, y]];
|
|
3007
3030
|
}
|
|
3008
|
-
}
|
|
3009
3031
|
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3032
|
+
return {
|
|
3033
|
+
layer: {
|
|
3034
|
+
geometry_type: arcs ? 'polygon' : 'point',
|
|
3035
|
+
shapes: shapes,
|
|
3036
|
+
data: table
|
|
3037
|
+
},
|
|
3038
|
+
arcs: arcs ? new internal.ArcCollection(arcs) : null
|
|
3039
|
+
};
|
|
3013
3040
|
}
|
|
3014
3041
|
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
}
|
|
3042
|
+
var R = 6378137;
|
|
3043
|
+
var D2R = Math.PI / 180;
|
|
3044
|
+
var R2D = 180 / Math.PI;
|
|
3019
3045
|
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3046
|
+
// Assumes projections are available
|
|
3047
|
+
|
|
3048
|
+
function needReprojectionForDisplay(sourceCRS, displayCRS) {
|
|
3049
|
+
if (!sourceCRS || !displayCRS) {
|
|
3050
|
+
return false;
|
|
3051
|
+
}
|
|
3052
|
+
if (internal.crsAreEqual(sourceCRS, displayCRS)) {
|
|
3053
|
+
return false;
|
|
3024
3054
|
}
|
|
3055
|
+
return true;
|
|
3025
3056
|
}
|
|
3026
3057
|
|
|
3027
|
-
|
|
3028
|
-
|
|
3029
|
-
|
|
3058
|
+
// bbox in wgs84 coords
|
|
3059
|
+
// dest: CRS, which may also be wgs84
|
|
3060
|
+
function projectLatLonBBox(bbox, dest) {
|
|
3061
|
+
if (!dest || internal.isWGS84(dest)) {
|
|
3062
|
+
return bbox.concat();
|
|
3063
|
+
}
|
|
3064
|
+
var proj = internal.getProjTransform2(internal.parseCrsString('wgs84'), dest);
|
|
3065
|
+
var bbox2 = proj(bbox[0], bbox[1]).concat(proj(bbox[2], bbox[3]));
|
|
3066
|
+
return bbox2;
|
|
3030
3067
|
}
|
|
3031
3068
|
|
|
3032
|
-
function
|
|
3033
|
-
var
|
|
3034
|
-
|
|
3035
|
-
|
|
3069
|
+
function projectArcsForDisplay(arcs, src, dest) {
|
|
3070
|
+
var copy = arcs.getCopy(); // need to flatten first?
|
|
3071
|
+
var destIsWebMerc = internal.isWebMercator(dest);
|
|
3072
|
+
if (destIsWebMerc && internal.isWebMercator(src)) {
|
|
3073
|
+
return copy;
|
|
3074
|
+
}
|
|
3036
3075
|
|
|
3037
|
-
|
|
3038
|
-
var
|
|
3039
|
-
|
|
3076
|
+
var wgs84 = internal.parseCrsString('wgs84');
|
|
3077
|
+
var toWGS84 = internal.getProjTransform2(src, wgs84);
|
|
3078
|
+
var fromWGS84 = internal.getProjTransform2(wgs84, dest);
|
|
3079
|
+
|
|
3080
|
+
try {
|
|
3081
|
+
// first try projectArcs() -- it's fast and preserves arc ids
|
|
3082
|
+
// (so vertex editing doesn't break)
|
|
3083
|
+
if (!internal.isWGS84(src)) {
|
|
3084
|
+
// use wgs84 as a pivot CRS, so we can handle polar coordinates
|
|
3085
|
+
// that can't be projected to Mercator
|
|
3086
|
+
internal.projectArcs(copy, toWGS84);
|
|
3087
|
+
}
|
|
3088
|
+
if (destIsWebMerc) {
|
|
3089
|
+
// handle polar points by clamping them to they will project
|
|
3090
|
+
// (downside: may cause unexpected behavior when editing vertices interactively)
|
|
3091
|
+
clampY(copy);
|
|
3092
|
+
}
|
|
3093
|
+
internal.projectArcs(copy, fromWGS84);
|
|
3094
|
+
} catch(e) {
|
|
3095
|
+
console.error(e);
|
|
3096
|
+
// use the more robust projectArcs2 if projectArcs throws an error
|
|
3097
|
+
// downside: projectArcs2 discards Z values and changes arc indexing,
|
|
3098
|
+
// which will break vertex editing.
|
|
3099
|
+
var reproject = internal.getProjTransform2(src, dest);
|
|
3100
|
+
copy = arcs.getCopy();
|
|
3101
|
+
internal.projectArcs2(copy, reproject);
|
|
3102
|
+
}
|
|
3103
|
+
return copy;
|
|
3040
3104
|
}
|
|
3041
3105
|
|
|
3042
|
-
function
|
|
3043
|
-
|
|
3106
|
+
function clampY(arcs) {
|
|
3107
|
+
var max = 89.9,
|
|
3108
|
+
min = -89.9,
|
|
3109
|
+
bbox = arcs.getBounds().toArray();
|
|
3110
|
+
if (bbox[1] >= min && bbox[3] <= max) return;
|
|
3111
|
+
arcs.transformPoints(function(x, y) {
|
|
3112
|
+
if (y > max) return [x, max];
|
|
3113
|
+
if (y < min) return [x, min];
|
|
3114
|
+
});
|
|
3044
3115
|
}
|
|
3045
3116
|
|
|
3046
|
-
function
|
|
3047
|
-
|
|
3117
|
+
function projectPointsForDisplay(lyr, src, dest) {
|
|
3118
|
+
var copy = utils$1.extend({}, lyr);
|
|
3119
|
+
var proj = internal.getProjTransform2(src, dest);
|
|
3120
|
+
copy.shapes = internal.cloneShapes(lyr.shapes);
|
|
3121
|
+
internal.projectPointLayer(copy, proj);
|
|
3122
|
+
return copy;
|
|
3048
3123
|
}
|
|
3049
3124
|
|
|
3050
|
-
|
|
3051
|
-
function
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
}
|
|
3125
|
+
|
|
3126
|
+
function toWebMercator(lng, lat) {
|
|
3127
|
+
var k = Math.cos(lat * D2R);
|
|
3128
|
+
var x = R * lng * D2R;
|
|
3129
|
+
var y = R * Math.log(Math.tan(Math.PI * 0.25 + lat * D2R * 0.5));
|
|
3130
|
+
return [x, y];
|
|
3057
3131
|
}
|
|
3058
3132
|
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
lyr.shapes[fid] = projectPointCoords(coords, lyr.gui.projectPoint);
|
|
3064
|
-
}
|
|
3133
|
+
function fromWebMercator(x, y) {
|
|
3134
|
+
var lon = x / R * R2D;
|
|
3135
|
+
var lat = R2D * (Math.PI * 0.5 - 2 * Math.atan(Math.exp(-y / R)));
|
|
3136
|
+
return [lon, lat];
|
|
3065
3137
|
}
|
|
3066
3138
|
|
|
3067
|
-
function
|
|
3068
|
-
|
|
3069
|
-
var p = lyr.gui.displayArcs.getVertex2(ids[0]);
|
|
3070
|
-
internal.snapVerticesToPoint(ids, lyr.gui.invertPoint(p[0], p[1]), lyr.gui.source.dataset.arcs);
|
|
3139
|
+
function scaleToZoom(metersPerPix) {
|
|
3140
|
+
return Math.log(40075017 / 512 / metersPerPix) / Math.log(2);
|
|
3071
3141
|
}
|
|
3072
3142
|
|
|
3073
|
-
function
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
if (isProjectedLayer(lyr)) {
|
|
3078
|
-
internal.snapVerticesToPoint([id], lyr.gui.projectPoint(p[0], p[1]), lyr.gui.displayArcs);
|
|
3079
|
-
}
|
|
3080
|
-
});
|
|
3143
|
+
function getMapboxBounds() {
|
|
3144
|
+
var ymax = toWebMercator(0, 84)[1];
|
|
3145
|
+
var ymin = toWebMercator(0, -84)[1];
|
|
3146
|
+
return [-Infinity, ymin, Infinity, ymax];
|
|
3081
3147
|
}
|
|
3082
3148
|
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
var
|
|
3087
|
-
|
|
3149
|
+
|
|
3150
|
+
// Update map extent and trigger redraw, after a new display CRS has been applied
|
|
3151
|
+
function projectMapExtent(ext, src, dest, newBounds) {
|
|
3152
|
+
var oldBounds = ext.getBounds();
|
|
3153
|
+
var oldScale = ext.scale();
|
|
3154
|
+
var newCP, proj, strictBounds;
|
|
3155
|
+
|
|
3156
|
+
if (dest && internal.isWebMercator(dest)) {
|
|
3157
|
+
// clampToMapboxBounds(newBounds);
|
|
3158
|
+
strictBounds = getMapboxBounds();
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
// if source or destination CRS is unknown, show full extent
|
|
3162
|
+
// if map is at full extent, show full extent
|
|
3163
|
+
// TODO: handle case that scale is 1 and map is panned away from center
|
|
3164
|
+
if (ext.scale() == 1 || !dest) {
|
|
3165
|
+
ext.setFullBounds(newBounds, strictBounds);
|
|
3166
|
+
ext.reset();
|
|
3167
|
+
} else {
|
|
3168
|
+
// if map is zoomed, stay centered on the same geographic location, at the same relative scale
|
|
3169
|
+
proj = internal.getProjTransform2(src, dest);
|
|
3170
|
+
newCP = proj(oldBounds.centerX(), oldBounds.centerY());
|
|
3171
|
+
ext.setFullBounds(newBounds, strictBounds);
|
|
3172
|
+
if (!newCP) {
|
|
3173
|
+
// projection of center point failed; use center of bounds
|
|
3174
|
+
// (also consider just resetting the view using ext.home())
|
|
3175
|
+
newCP = [newBounds.centerX(), newBounds.centerY()];
|
|
3176
|
+
}
|
|
3177
|
+
ext.recenter(newCP[0], newCP[1], oldScale);
|
|
3178
|
+
}
|
|
3179
|
+
// trigger full redraw, in case some SVG symbols are unprojectable
|
|
3180
|
+
ext.dispatchEvent('change', {redraw: true});
|
|
3088
3181
|
}
|
|
3089
3182
|
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3183
|
+
// Called from console; for testing dynamic crs
|
|
3184
|
+
function setDisplayProjection(gui, cmd) {
|
|
3185
|
+
var arg = cmd.replace(/^projd[ ]*/, '');
|
|
3186
|
+
if (arg) {
|
|
3187
|
+
gui.map.setDisplayCRS(internal.parseCrsString(arg));
|
|
3188
|
+
} else {
|
|
3189
|
+
gui.map.setDisplayCRS(null);
|
|
3095
3190
|
}
|
|
3096
|
-
return dest.length ? dest : null;
|
|
3097
3191
|
}
|
|
3098
3192
|
|
|
3099
|
-
|
|
3100
|
-
|
|
3193
|
+
function filterLayerByIds(lyr, ids) {
|
|
3194
|
+
var shapes;
|
|
3195
|
+
if (lyr.shapes) {
|
|
3196
|
+
shapes = ids.map(function(id) {
|
|
3197
|
+
return lyr.shapes[id];
|
|
3198
|
+
});
|
|
3199
|
+
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
3200
|
+
}
|
|
3201
|
+
return lyr;
|
|
3202
|
+
}
|
|
3101
3203
|
|
|
3102
|
-
|
|
3103
|
-
|
|
3204
|
+
function formatLayerNameForDisplay(name) {
|
|
3205
|
+
return name || '[unnamed]';
|
|
3206
|
+
}
|
|
3104
3207
|
|
|
3105
|
-
|
|
3106
|
-
|
|
3208
|
+
function cleanLayerName(raw) {
|
|
3209
|
+
return raw.replace(/[\n\t/\\]/g, '')
|
|
3210
|
+
.replace(/^[.\s]+/, '').replace(/[.\s]+$/, '');
|
|
3211
|
+
}
|
|
3107
3212
|
|
|
3108
|
-
|
|
3109
|
-
|
|
3213
|
+
function updateLayerStackOrder(layers) {
|
|
3214
|
+
// 1. assign ascending ids to unassigned layers above the range of other layers
|
|
3215
|
+
layers.forEach(function(o, i) {
|
|
3216
|
+
if (!o.layer.menu_order) o.layer.menu_order = 1e6 + i;
|
|
3217
|
+
});
|
|
3218
|
+
// 2. sort in ascending order
|
|
3219
|
+
layers.sort(function(a, b) {
|
|
3220
|
+
return a.layer.menu_order - b.layer.menu_order;
|
|
3221
|
+
});
|
|
3222
|
+
// 3. assign consecutve ids
|
|
3223
|
+
layers.forEach(function(o, i) {
|
|
3224
|
+
o.layer.menu_order = i + 1;
|
|
3225
|
+
});
|
|
3226
|
+
return layers;
|
|
3227
|
+
}
|
|
3110
3228
|
|
|
3111
|
-
|
|
3112
|
-
|
|
3229
|
+
function sortLayersForMenuDisplay(layers) {
|
|
3230
|
+
layers = updateLayerStackOrder(layers);
|
|
3231
|
+
return layers.reverse();
|
|
3232
|
+
}
|
|
3113
3233
|
|
|
3114
|
-
|
|
3115
|
-
|
|
3234
|
+
// lyr: a map layer with gui property
|
|
3235
|
+
// displayCRS: CRS to use for display, or null (which clears any current display CRS)
|
|
3236
|
+
function projectLayerForDisplay(lyr, displayCRS) {
|
|
3237
|
+
var crsInfo = getDatasetCrsInfo(lyr.gui.source.dataset);
|
|
3238
|
+
var sourceCRS = crsInfo.crs || null; // let enhanceLayerForDisplay() handle null case
|
|
3239
|
+
if (!lyr.gui.geographic) {
|
|
3240
|
+
return;
|
|
3241
|
+
}
|
|
3242
|
+
if (lyr.gui.dynamic_crs && internal.crsAreEqual(sourceCRS, lyr.gui.dynamic_crs)) {
|
|
3243
|
+
return;
|
|
3244
|
+
}
|
|
3245
|
+
var gui = lyr.gui;
|
|
3246
|
+
enhanceLayerForDisplay(lyr, lyr.gui.source.dataset, {crs: displayCRS});
|
|
3247
|
+
utils$1.defaults(lyr.gui, gui); // re-apply any properties that were lost (e.g. svg_id)
|
|
3248
|
+
if (lyr.gui.style?.ids) {
|
|
3249
|
+
// re-apply layer filter
|
|
3250
|
+
lyr.gui.displayLayer = filterLayerByIds(lyr.gui.displayLayer, lyr.gui.style.ids);
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3116
3253
|
|
|
3117
|
-
slider drag end
|
|
3118
|
-
-> [repair] intersection update
|
|
3119
3254
|
|
|
3120
|
-
|
|
3255
|
+
// Supplement a layer with information needed for rendering
|
|
3256
|
+
function enhanceLayerForDisplay(layer, dataset, opts) {
|
|
3257
|
+
var gui = {
|
|
3258
|
+
empty: internal.getFeatureCount(layer) === 0,
|
|
3259
|
+
geographic: false,
|
|
3260
|
+
displayArcs: null,
|
|
3261
|
+
displayLayer: null,
|
|
3262
|
+
source: {dataset},
|
|
3263
|
+
bounds: null,
|
|
3264
|
+
style: null,
|
|
3265
|
+
dynamic_crs: null,
|
|
3266
|
+
invertPoint: null,
|
|
3267
|
+
projectPoint: null
|
|
3268
|
+
};
|
|
3121
3269
|
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
var
|
|
3126
|
-
var
|
|
3127
|
-
var
|
|
3128
|
-
var
|
|
3270
|
+
var displayCRS = opts.crs || null;
|
|
3271
|
+
// display arcs may have been generated when another layer in the dataset
|
|
3272
|
+
// was converted for display... re-use if available
|
|
3273
|
+
var displayArcs = dataset.gui?.displayArcs;
|
|
3274
|
+
var unprojectable = false;
|
|
3275
|
+
var sourceCRS;
|
|
3276
|
+
var emptyArcs;
|
|
3129
3277
|
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
menu.hide();
|
|
3136
|
-
} else {
|
|
3137
|
-
gui.clearMode();
|
|
3138
|
-
}
|
|
3139
|
-
});
|
|
3140
|
-
new SimpleButton(el.findChild('.simplify-settings-btn')).on('click', function() {
|
|
3141
|
-
if (menu.visible()) {
|
|
3142
|
-
menu.hide();
|
|
3278
|
+
if (displayCRS && layer.geometry_type) {
|
|
3279
|
+
var crsInfo = getDatasetCrsInfo(dataset);
|
|
3280
|
+
if (crsInfo.error) {
|
|
3281
|
+
// unprojectable dataset -- return empty layer
|
|
3282
|
+
gui.unprojectable = true;
|
|
3143
3283
|
} else {
|
|
3144
|
-
|
|
3284
|
+
sourceCRS = crsInfo.crs;
|
|
3145
3285
|
}
|
|
3146
|
-
}
|
|
3147
|
-
gui.keyboard.onMenuSubmit(menu, onSubmit);
|
|
3286
|
+
}
|
|
3148
3287
|
|
|
3149
|
-
//
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3288
|
+
// Assume that dataset.displayArcs is in the display CRS
|
|
3289
|
+
// (it must be deleted upstream if reprojection is needed)
|
|
3290
|
+
// if (!obj.empty && dataset.arcs && !displayArcs) {
|
|
3291
|
+
if (dataset.arcs && !displayArcs && !gui.unprojectable) {
|
|
3292
|
+
// project arcs, if needed
|
|
3293
|
+
if (needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
3294
|
+
displayArcs = projectArcsForDisplay(dataset.arcs, sourceCRS, displayCRS);
|
|
3295
|
+
} else {
|
|
3296
|
+
// Use original arcs for display if there is no dynamic reprojection
|
|
3297
|
+
displayArcs = dataset.arcs;
|
|
3298
|
+
}
|
|
3299
|
+
|
|
3300
|
+
enhanceArcCollectionForDisplay(displayArcs);
|
|
3301
|
+
dataset.gui = {displayArcs}; // stash these in the dataset for other layers to use
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
if (internal.layerHasFurniture(layer)) {
|
|
3305
|
+
// TODO: consider how to render furniture in GUI
|
|
3306
|
+
// treating furniture layers (other than frame) as tabular for now,
|
|
3307
|
+
// so there is something to show if they are selected
|
|
3308
|
+
}
|
|
3309
|
+
|
|
3310
|
+
if (gui.unprojectable) {
|
|
3311
|
+
gui.displayLayer = {shapes: []}; // TODO: improve
|
|
3312
|
+
} else if (layer.geometry_type) {
|
|
3313
|
+
gui.geographic = true;
|
|
3314
|
+
gui.displayLayer = layer;
|
|
3315
|
+
gui.displayArcs = displayArcs;
|
|
3316
|
+
} else {
|
|
3317
|
+
var table = getDisplayLayerForTable(layer.data);
|
|
3318
|
+
gui.tabular = true;
|
|
3319
|
+
gui.displayLayer = table.layer;
|
|
3320
|
+
gui.displayArcs = table.arcs;
|
|
3321
|
+
}
|
|
3322
|
+
|
|
3323
|
+
// dynamic reprojection (arcs were already reprojected above)
|
|
3324
|
+
if (gui.geographic && needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
3325
|
+
gui.dynamic_crs = displayCRS;
|
|
3326
|
+
gui.invertPoint = internal.getProjTransform2(displayCRS, sourceCRS);
|
|
3327
|
+
gui.projectPoint = internal.getProjTransform2(sourceCRS, displayCRS);
|
|
3328
|
+
if (internal.layerHasPoints(layer)) {
|
|
3329
|
+
gui.displayLayer = projectPointsForDisplay(layer, sourceCRS, displayCRS);
|
|
3330
|
+
} else if (internal.layerHasPaths(layer)) {
|
|
3331
|
+
emptyArcs = findEmptyArcs(displayArcs);
|
|
3332
|
+
if (emptyArcs.length > 0) {
|
|
3333
|
+
// Don't try to draw paths containing coordinates that failed to project
|
|
3334
|
+
gui.displayLayer = internal.filterPathLayerByArcIds(gui.displayLayer, emptyArcs);
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
gui.bounds = getDisplayBounds(gui.displayLayer, gui.displayArcs);
|
|
3340
|
+
layer.gui = gui;
|
|
3341
|
+
}
|
|
3342
|
+
|
|
3343
|
+
function getDisplayBounds(lyr, arcs) {
|
|
3344
|
+
var bounds = internal.getLayerBounds(lyr, arcs) || new Bounds();
|
|
3345
|
+
if (lyr.geometry_type == 'point' && arcs && bounds.hasBounds() && bounds.area() > 0 === false) {
|
|
3346
|
+
// if a point layer has no extent (e.g. contains only a single point),
|
|
3347
|
+
// then merge with arc bounds, to place the point in context.
|
|
3348
|
+
bounds = bounds.mergeBounds(arcs.getBounds());
|
|
3349
|
+
}
|
|
3350
|
+
return bounds;
|
|
3351
|
+
}
|
|
3352
|
+
|
|
3353
|
+
// Returns an array of ids of empty arcs (arcs can be set to empty if errors occur while projecting them)
|
|
3354
|
+
function findEmptyArcs(arcs) {
|
|
3355
|
+
var nn = arcs.getVertexData().nn;
|
|
3356
|
+
var ids = [];
|
|
3357
|
+
for (var i=0, n=nn.length; i<n; i++) {
|
|
3358
|
+
if (nn[i] === 0) {
|
|
3359
|
+
ids.push(i);
|
|
3360
|
+
}
|
|
3361
|
+
}
|
|
3362
|
+
return ids;
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3365
|
+
function flattenArcs(lyr) {
|
|
3366
|
+
lyr.gui.source.dataset.arcs.flatten();
|
|
3367
|
+
if (isProjectedLayer(lyr)) {
|
|
3368
|
+
lyr.gui.displayArcs.flatten();
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
|
|
3372
|
+
function setZ(lyr, z) {
|
|
3373
|
+
lyr.gui.source.dataset.arcs.setRetainedInterval(z);
|
|
3374
|
+
if (isProjectedLayer(lyr)) {
|
|
3375
|
+
lyr.gui.displayArcs.setRetainedInterval(z);
|
|
3376
|
+
}
|
|
3377
|
+
}
|
|
3378
|
+
|
|
3379
|
+
function updateZ(lyr) {
|
|
3380
|
+
if (isProjectedLayer(lyr) && !lyr.gui.source.dataset.arcs.isFlat()) {
|
|
3381
|
+
lyr.gui.displayArcs.setThresholds(lyr.gui.source.dataset.arcs.getVertexData().zz);
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
|
|
3385
|
+
function appendNewDataRecord(layer) {
|
|
3386
|
+
if (!layer.data) return null;
|
|
3387
|
+
var fields = layer.data.getFields();
|
|
3388
|
+
var d = getEmptyDataRecord(layer.data);
|
|
3389
|
+
// TODO: handle SVG symbol layer
|
|
3390
|
+
if (internal.layerHasLabels(layer)) {
|
|
3391
|
+
d['label-text'] = 'TBD'; // without text, new labels will be invisible
|
|
3392
|
+
} else if (layer.geometry_type == 'point' && fields.includes('r')) {
|
|
3393
|
+
d.r = 3; // show a black circle if layer is styled
|
|
3394
|
+
}
|
|
3395
|
+
if (layer.geometry_type == 'polyline' || layer.geometry_type == 'polygon') {
|
|
3396
|
+
if (fields.includes('stroke')) d.stroke = 'black';
|
|
3397
|
+
if (fields.includes('stroke-width')) d['stroke-width'] = 1;
|
|
3398
|
+
}
|
|
3399
|
+
if (layer.geometry_type == 'polygon') {
|
|
3400
|
+
if (fields.includes('fill')) {
|
|
3401
|
+
d.fill = 'rgba(0,0,0,0.10)'; // 'rgba(249,120,249,0.20)';
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
// TODO: better styling
|
|
3405
|
+
layer.data.getRecords().push(d);
|
|
3406
|
+
return d;
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
function getEmptyDataRecord(table) {
|
|
3410
|
+
return table.getFields().reduce(function(memo, name) {
|
|
3411
|
+
memo[name] = null;
|
|
3412
|
+
return memo;
|
|
3413
|
+
}, {});
|
|
3414
|
+
}
|
|
3415
|
+
|
|
3416
|
+
// p1, p2: two points in source data CRS coords.
|
|
3417
|
+
function appendNewPath(lyr, p1, p2) {
|
|
3418
|
+
var arcId = lyr.gui.displayArcs.size();
|
|
3419
|
+
internal.appendEmptyArc(lyr.gui.displayArcs);
|
|
3420
|
+
lyr.shapes.push([[arcId]]);
|
|
3421
|
+
if (isProjectedLayer(lyr)) {
|
|
3422
|
+
internal.appendEmptyArc(lyr.gui.source.dataset.arcs);
|
|
3423
|
+
}
|
|
3424
|
+
appendVertex$1(lyr, p1);
|
|
3425
|
+
appendVertex$1(lyr, p2);
|
|
3426
|
+
appendNewDataRecord(lyr);
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
function deleteLastPath(lyr) {
|
|
3430
|
+
var arcId = lyr.gui.displayArcs.size() - 1;
|
|
3431
|
+
if (lyr.data) {
|
|
3432
|
+
lyr.data.getRecords().pop();
|
|
3433
|
+
}
|
|
3434
|
+
var shp = lyr.shapes.pop();
|
|
3435
|
+
internal.deleteLastArc(lyr.gui.displayArcs);
|
|
3436
|
+
if (isProjectedLayer(lyr)) {
|
|
3437
|
+
internal.deleteLastArc(lyr.gui.source.dataset.arcs);
|
|
3438
|
+
}
|
|
3439
|
+
}
|
|
3440
|
+
|
|
3441
|
+
// p: one point in source data coords
|
|
3442
|
+
function appendNewPoint(lyr, p) {
|
|
3443
|
+
lyr.shapes.push([p]);
|
|
3444
|
+
if (lyr.data) {
|
|
3445
|
+
appendNewDataRecord(lyr);
|
|
3446
|
+
}
|
|
3447
|
+
// this reprojects all the points... TODO: improve
|
|
3448
|
+
if (isProjectedLayer(lyr)) {
|
|
3449
|
+
projectLayerForDisplay(lyr, lyr.gui.dynamic_crs);
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
function deleteLastPoint(lyr) {
|
|
3454
|
+
if (lyr.data) {
|
|
3455
|
+
lyr.data.getRecords().pop();
|
|
3456
|
+
}
|
|
3457
|
+
lyr.shapes.pop();
|
|
3458
|
+
if (isProjectedLayer(lyr)) {
|
|
3459
|
+
lyr.gui.displayLayer.shapes.pop();
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
|
|
3463
|
+
// p: point in source data CRS coords.
|
|
3464
|
+
function insertVertex$1(lyr, id, p) {
|
|
3465
|
+
internal.insertVertex(lyr.gui.source.dataset.arcs, id, p);
|
|
3466
|
+
if (isProjectedLayer(lyr)) {
|
|
3467
|
+
internal.insertVertex(lyr.gui.displayArcs, id, lyr.gui.projectPoint(p[0], p[1]));
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3471
|
+
function appendVertex$1(lyr, p) {
|
|
3472
|
+
var n = lyr.gui.source.dataset.arcs.getPointCount();
|
|
3473
|
+
insertVertex$1(lyr, n, p);
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
// TODO: make sure we're not also removing an entire arc
|
|
3477
|
+
function deleteLastVertex(lyr) {
|
|
3478
|
+
deleteVertex$1(lyr, lyr.gui.displayArcs.getPointCount() - 1);
|
|
3479
|
+
}
|
|
3480
|
+
|
|
3481
|
+
|
|
3482
|
+
function deleteVertex$1(lyr, id) {
|
|
3483
|
+
internal.deleteVertex(lyr.gui.displayArcs, id);
|
|
3484
|
+
if (isProjectedLayer(lyr)) {
|
|
3485
|
+
internal.deleteVertex(lyr.gui.source.dataset.arcs, id);
|
|
3486
|
+
}
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3489
|
+
function getLastArcCoords(target) {
|
|
3490
|
+
var arcId = target.gui.source.dataset.arcs.size() - 1;
|
|
3491
|
+
return internal.getUnfilteredArcCoords(arcId, target.gui.source.dataset.arcs);
|
|
3492
|
+
}
|
|
3493
|
+
|
|
3494
|
+
function getLastVertexCoords(target) {
|
|
3495
|
+
var arcs = target.gui.source.dataset.arcs;
|
|
3496
|
+
return internal.getVertexCoords(arcs.getPointCount() - 1, arcs);
|
|
3497
|
+
}
|
|
3498
|
+
|
|
3499
|
+
function getLastArcLength(target) {
|
|
3500
|
+
var arcId = target.gui.source.dataset.arcs.size() - 1;
|
|
3501
|
+
return internal.getUnfilteredArcLength(arcId, target.gui.source.dataset.arcs);
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
function getPointCoords(lyr, fid) {
|
|
3505
|
+
return internal.cloneShape(lyr.shapes[fid]);
|
|
3506
|
+
}
|
|
3507
|
+
|
|
3508
|
+
function getVertexCoords(lyr, id) {
|
|
3509
|
+
return lyr.gui.source.dataset.arcs.getVertex2(id);
|
|
3510
|
+
}
|
|
3511
|
+
|
|
3512
|
+
// set data coords (not display coords) of one or more vertices.
|
|
3513
|
+
function setVertexCoords(lyr, ids, dataPoint) {
|
|
3514
|
+
internal.snapVerticesToPoint(ids, dataPoint, lyr.gui.source.dataset.arcs);
|
|
3515
|
+
if (isProjectedLayer(lyr)) {
|
|
3516
|
+
var p = lyr.gui.projectPoint(dataPoint[0], dataPoint[1]);
|
|
3517
|
+
internal.snapVerticesToPoint(ids, p, lyr.gui.displayArcs);
|
|
3518
|
+
}
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
// coords: [x, y] point in data CRS (not display CRS)
|
|
3522
|
+
function setPointCoords(lyr, fid, coords) {
|
|
3523
|
+
lyr.shapes[fid] = coords;
|
|
3524
|
+
if (isProjectedLayer(lyr)) {
|
|
3525
|
+
lyr.shapes[fid] = projectPointCoords(coords, lyr.gui.projectPoint);
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
function updateVertexCoords(lyr, ids) {
|
|
3530
|
+
if (!isProjectedLayer(lyr)) return;
|
|
3531
|
+
var p = lyr.gui.displayArcs.getVertex2(ids[0]);
|
|
3532
|
+
internal.snapVerticesToPoint(ids, lyr.gui.invertPoint(p[0], p[1]), lyr.gui.source.dataset.arcs);
|
|
3533
|
+
}
|
|
3534
|
+
|
|
3535
|
+
function setRectangleCoords(lyr, ids, coords) {
|
|
3536
|
+
ids.forEach(function(id, i) {
|
|
3537
|
+
var p = coords[i];
|
|
3538
|
+
internal.snapVerticesToPoint([id], p, lyr.gui.source.dataset.arcs);
|
|
3539
|
+
if (isProjectedLayer(lyr)) {
|
|
3540
|
+
internal.snapVerticesToPoint([id], lyr.gui.projectPoint(p[0], p[1]), lyr.gui.displayArcs);
|
|
3541
|
+
}
|
|
3542
|
+
});
|
|
3543
|
+
}
|
|
3544
|
+
|
|
3545
|
+
// Update source data coordinates by projecting display coordinates
|
|
3546
|
+
function updatePointCoords(lyr, fid) {
|
|
3547
|
+
if (!isProjectedLayer(lyr)) return;
|
|
3548
|
+
var displayShp = lyr.shapes[fid];
|
|
3549
|
+
lyr.shapes[fid] = projectPointCoords(displayShp, lyr.gui.invertPoint);
|
|
3550
|
+
}
|
|
3551
|
+
|
|
3552
|
+
function projectPointCoords(src, proj) {
|
|
3553
|
+
var dest = [], p;
|
|
3554
|
+
for (var i=0; i<src.length; i++) {
|
|
3555
|
+
p = proj(src[i][0], src[i][1]);
|
|
3556
|
+
if (p) dest.push(p);
|
|
3557
|
+
}
|
|
3558
|
+
return dest.length ? dest : null;
|
|
3559
|
+
}
|
|
3560
|
+
|
|
3561
|
+
/*
|
|
3562
|
+
How changes in the simplify control should affect other components
|
|
3563
|
+
|
|
3564
|
+
data calculated, 100% simplification
|
|
3565
|
+
-> [map] filtered arcs update
|
|
3566
|
+
|
|
3567
|
+
data calculated, <100% simplification
|
|
3568
|
+
-> [map] filtered arcs update, redraw; [repair] intersection update
|
|
3569
|
+
|
|
3570
|
+
change via text field
|
|
3571
|
+
-> [map] redraw; [repair] intersection update
|
|
3572
|
+
|
|
3573
|
+
slider drag start
|
|
3574
|
+
-> [repair] hide display
|
|
3575
|
+
|
|
3576
|
+
slider drag
|
|
3577
|
+
-> [map] redraw
|
|
3578
|
+
|
|
3579
|
+
slider drag end
|
|
3580
|
+
-> [repair] intersection update
|
|
3581
|
+
|
|
3582
|
+
*/
|
|
3583
|
+
|
|
3584
|
+
var SimplifyControl = function(gui) {
|
|
3585
|
+
var model = gui.model;
|
|
3586
|
+
var control = {};
|
|
3587
|
+
var _value = 1;
|
|
3588
|
+
var el = gui.container.findChild('.simplify-control-wrapper');
|
|
3589
|
+
var menu = gui.container.findChild('.simplify-options');
|
|
3590
|
+
var slider, text, fromPct;
|
|
3591
|
+
var menuBtn = gui.container.findChild('.simplify-btn').addClass('disabled');
|
|
3592
|
+
|
|
3593
|
+
// init settings menu
|
|
3594
|
+
new SimpleButton(menu.findChild('.submit-btn').addClass('default-btn')).on('click', onSubmit);
|
|
3595
|
+
new SimpleButton(menu.findChild('.close2-btn')).on('click', function() {
|
|
3596
|
+
if (el.visible()) {
|
|
3597
|
+
// cancel just hides menu if slider is visible
|
|
3598
|
+
menu.hide();
|
|
3599
|
+
} else {
|
|
3600
|
+
gui.clearMode();
|
|
3601
|
+
}
|
|
3602
|
+
});
|
|
3603
|
+
new SimpleButton(el.findChild('.simplify-settings-btn')).on('click', function() {
|
|
3604
|
+
if (menu.visible()) {
|
|
3605
|
+
menu.hide();
|
|
3606
|
+
} else {
|
|
3607
|
+
showMenu();
|
|
3608
|
+
}
|
|
3609
|
+
});
|
|
3610
|
+
gui.keyboard.onMenuSubmit(menu, onSubmit);
|
|
3611
|
+
|
|
3612
|
+
// init simplify button and mode
|
|
3613
|
+
gui.addMode('simplify', turnOn, turnOff, menuBtn);
|
|
3614
|
+
|
|
3615
|
+
model.on('update', function() {
|
|
3616
|
+
menuBtn.classed('disabled', !model.getActiveLayer());
|
|
3617
|
+
if (gui.getMode() == 'simplify') gui.clearMode();
|
|
3153
3618
|
});
|
|
3154
3619
|
|
|
3620
|
+
|
|
3155
3621
|
// exit simplify mode when user clicks off the visible part of the menu
|
|
3156
3622
|
menu.on('click', GUI.handleDirectEvent(gui.clearMode));
|
|
3157
3623
|
|
|
@@ -3331,144 +3797,6 @@
|
|
|
3331
3797
|
}
|
|
3332
3798
|
};
|
|
3333
3799
|
|
|
3334
|
-
var R = 6378137;
|
|
3335
|
-
var D2R = Math.PI / 180;
|
|
3336
|
-
var R2D = 180 / Math.PI;
|
|
3337
|
-
|
|
3338
|
-
// Assumes projections are available
|
|
3339
|
-
|
|
3340
|
-
function needReprojectionForDisplay(sourceCRS, displayCRS) {
|
|
3341
|
-
if (!sourceCRS || !displayCRS) {
|
|
3342
|
-
return false;
|
|
3343
|
-
}
|
|
3344
|
-
if (internal.crsAreEqual(sourceCRS, displayCRS)) {
|
|
3345
|
-
return false;
|
|
3346
|
-
}
|
|
3347
|
-
return true;
|
|
3348
|
-
}
|
|
3349
|
-
|
|
3350
|
-
function projectArcsForDisplay(arcs, src, dest) {
|
|
3351
|
-
var copy = arcs.getCopy(); // need to flatten first?
|
|
3352
|
-
var destIsWebMerc = internal.isWebMercator(dest);
|
|
3353
|
-
if (destIsWebMerc && internal.isWebMercator(src)) {
|
|
3354
|
-
return copy;
|
|
3355
|
-
}
|
|
3356
|
-
|
|
3357
|
-
var wgs84 = internal.parseCrsString('wgs84');
|
|
3358
|
-
var toWGS84 = internal.getProjTransform2(src, wgs84);
|
|
3359
|
-
var fromWGS84 = internal.getProjTransform2(wgs84, dest);
|
|
3360
|
-
|
|
3361
|
-
try {
|
|
3362
|
-
// first try projectArcs() -- it's fast and preserves arc ids
|
|
3363
|
-
// (so vertex editing doesn't break)
|
|
3364
|
-
if (!internal.isWGS84(src)) {
|
|
3365
|
-
// use wgs84 as a pivot CRS, so we can handle polar coordinates
|
|
3366
|
-
// that can't be projected to Mercator
|
|
3367
|
-
internal.projectArcs(copy, toWGS84);
|
|
3368
|
-
}
|
|
3369
|
-
if (destIsWebMerc) {
|
|
3370
|
-
// handle polar points by clamping them to they will project
|
|
3371
|
-
// (downside: may cause unexpected behavior when editing vertices interactively)
|
|
3372
|
-
clampY(copy);
|
|
3373
|
-
}
|
|
3374
|
-
internal.projectArcs(copy, fromWGS84);
|
|
3375
|
-
} catch(e) {
|
|
3376
|
-
console.error(e);
|
|
3377
|
-
// use the more robust projectArcs2 if projectArcs throws an error
|
|
3378
|
-
// downside: projectArcs2 discards Z values and changes arc indexing,
|
|
3379
|
-
// which will break vertex editing.
|
|
3380
|
-
var reproject = internal.getProjTransform2(src, dest);
|
|
3381
|
-
copy = arcs.getCopy();
|
|
3382
|
-
internal.projectArcs2(copy, reproject);
|
|
3383
|
-
}
|
|
3384
|
-
return copy;
|
|
3385
|
-
}
|
|
3386
|
-
|
|
3387
|
-
function clampY(arcs) {
|
|
3388
|
-
var max = 89.9,
|
|
3389
|
-
min = -89.9,
|
|
3390
|
-
bbox = arcs.getBounds().toArray();
|
|
3391
|
-
if (bbox[1] >= min && bbox[3] <= max) return;
|
|
3392
|
-
arcs.transformPoints(function(x, y) {
|
|
3393
|
-
if (y > max) return [x, max];
|
|
3394
|
-
if (y < min) return [x, min];
|
|
3395
|
-
});
|
|
3396
|
-
}
|
|
3397
|
-
|
|
3398
|
-
function projectPointsForDisplay(lyr, src, dest) {
|
|
3399
|
-
var copy = utils$1.extend({}, lyr);
|
|
3400
|
-
var proj = internal.getProjTransform2(src, dest);
|
|
3401
|
-
copy.shapes = internal.cloneShapes(lyr.shapes);
|
|
3402
|
-
internal.projectPointLayer(copy, proj);
|
|
3403
|
-
return copy;
|
|
3404
|
-
}
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
function toWebMercator(lng, lat) {
|
|
3408
|
-
var k = Math.cos(lat * D2R);
|
|
3409
|
-
var x = R * lng * D2R;
|
|
3410
|
-
var y = R * Math.log(Math.tan(Math.PI * 0.25 + lat * D2R * 0.5));
|
|
3411
|
-
return [x, y];
|
|
3412
|
-
}
|
|
3413
|
-
|
|
3414
|
-
function fromWebMercator(x, y) {
|
|
3415
|
-
var lon = x / R * R2D;
|
|
3416
|
-
var lat = R2D * (Math.PI * 0.5 - 2 * Math.atan(Math.exp(-y / R)));
|
|
3417
|
-
return [lon, lat];
|
|
3418
|
-
}
|
|
3419
|
-
|
|
3420
|
-
function scaleToZoom(metersPerPix) {
|
|
3421
|
-
return Math.log(40075017 / 512 / metersPerPix) / Math.log(2);
|
|
3422
|
-
}
|
|
3423
|
-
|
|
3424
|
-
function getMapboxBounds() {
|
|
3425
|
-
var ymax = toWebMercator(0, 84)[1];
|
|
3426
|
-
var ymin = toWebMercator(0, -84)[1];
|
|
3427
|
-
return [-Infinity, ymin, Infinity, ymax];
|
|
3428
|
-
}
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
// Update map extent and trigger redraw, after a new display CRS has been applied
|
|
3432
|
-
function projectMapExtent(ext, src, dest, newBounds) {
|
|
3433
|
-
var oldBounds = ext.getBounds();
|
|
3434
|
-
var oldScale = ext.scale();
|
|
3435
|
-
var newCP, proj, strictBounds;
|
|
3436
|
-
|
|
3437
|
-
if (dest && internal.isWebMercator(dest)) {
|
|
3438
|
-
// clampToMapboxBounds(newBounds);
|
|
3439
|
-
strictBounds = getMapboxBounds();
|
|
3440
|
-
}
|
|
3441
|
-
|
|
3442
|
-
// if source or destination CRS is unknown, show full extent
|
|
3443
|
-
// if map is at full extent, show full extent
|
|
3444
|
-
// TODO: handle case that scale is 1 and map is panned away from center
|
|
3445
|
-
if (ext.scale() == 1 || !dest) {
|
|
3446
|
-
ext.setFullBounds(newBounds, strictBounds);
|
|
3447
|
-
ext.home(); // sets full extent and triggers redraw
|
|
3448
|
-
} else {
|
|
3449
|
-
// if map is zoomed, stay centered on the same geographic location, at the same relative scale
|
|
3450
|
-
proj = internal.getProjTransform2(src, dest);
|
|
3451
|
-
newCP = proj(oldBounds.centerX(), oldBounds.centerY());
|
|
3452
|
-
ext.setFullBounds(newBounds, strictBounds);
|
|
3453
|
-
if (!newCP) {
|
|
3454
|
-
// projection of center point failed; use center of bounds
|
|
3455
|
-
// (also consider just resetting the view using ext.home())
|
|
3456
|
-
newCP = [newBounds.centerX(), newBounds.centerY()];
|
|
3457
|
-
}
|
|
3458
|
-
ext.recenter(newCP[0], newCP[1], oldScale);
|
|
3459
|
-
}
|
|
3460
|
-
}
|
|
3461
|
-
|
|
3462
|
-
// Called from console; for testing dynamic crs
|
|
3463
|
-
function setDisplayProjection(gui, cmd) {
|
|
3464
|
-
var arg = cmd.replace(/^projd[ ]*/, '');
|
|
3465
|
-
if (arg) {
|
|
3466
|
-
gui.map.setDisplayCRS(internal.parseCrsString(arg));
|
|
3467
|
-
} else {
|
|
3468
|
-
gui.map.setDisplayCRS(null);
|
|
3469
|
-
}
|
|
3470
|
-
}
|
|
3471
|
-
|
|
3472
3800
|
function Console(gui) {
|
|
3473
3801
|
var model = gui.model;
|
|
3474
3802
|
var CURSOR = '$ ';
|
|
@@ -3537,7 +3865,8 @@
|
|
|
3537
3865
|
}
|
|
3538
3866
|
|
|
3539
3867
|
function turnOn() {
|
|
3540
|
-
if (!_isOpen && !model.isEmpty()) {
|
|
3868
|
+
// if (!_isOpen && !model.isEmpty()) {
|
|
3869
|
+
if (!_isOpen) {
|
|
3541
3870
|
btn.addClass('active');
|
|
3542
3871
|
_isOpen = true;
|
|
3543
3872
|
// use console for messages while open
|
|
@@ -3876,8 +4205,8 @@
|
|
|
3876
4205
|
|
|
3877
4206
|
function applyParsedCommands(commands, done) {
|
|
3878
4207
|
var active = model.getActiveLayer(),
|
|
3879
|
-
prevArcs = active
|
|
3880
|
-
prevTable = active
|
|
4208
|
+
prevArcs = active?.dataset.arcs,
|
|
4209
|
+
prevTable = active?.layer.data,
|
|
3881
4210
|
prevTableSize = prevTable ? prevTable.size() : 0,
|
|
3882
4211
|
prevArcCount = prevArcs ? prevArcs.size() : 0,
|
|
3883
4212
|
job = new internal.Job(model);
|
|
@@ -3886,9 +4215,9 @@
|
|
|
3886
4215
|
internal.runParsedCommands(commands, job, function(err) {
|
|
3887
4216
|
var flags = getCommandFlags(commands),
|
|
3888
4217
|
active2 = model.getActiveLayer(),
|
|
3889
|
-
postArcs = active2
|
|
4218
|
+
postArcs = active2?.dataset.arcs,
|
|
3890
4219
|
postArcCount = postArcs ? postArcs.size() : 0,
|
|
3891
|
-
postTable = active2
|
|
4220
|
+
postTable = active2?.layer.data,
|
|
3892
4221
|
postTableSize = postTable ? postTable.size() : 0,
|
|
3893
4222
|
sameTable = prevTable == postTable && prevTableSize == postTableSize,
|
|
3894
4223
|
sameArcs = prevArcs == postArcs && postArcCount == prevArcCount;
|
|
@@ -3901,7 +4230,7 @@
|
|
|
3901
4230
|
if (sameTable) {
|
|
3902
4231
|
flags.same_table = true;
|
|
3903
4232
|
}
|
|
3904
|
-
if (active
|
|
4233
|
+
if (active && active?.layer == active2?.layer) {
|
|
3905
4234
|
// this can get set after some commands that don't set a new target
|
|
3906
4235
|
// (e.g. -dissolve)
|
|
3907
4236
|
flags.select = true;
|
|
@@ -3916,10 +4245,10 @@
|
|
|
3916
4245
|
function onError(err) {
|
|
3917
4246
|
if (utils$1.isString(err)) {
|
|
3918
4247
|
consoleStop(err);
|
|
3919
|
-
} else if (err.name == 'UserError') {
|
|
4248
|
+
} else if (err.name == 'UserError' ) {
|
|
3920
4249
|
// stop() has already been called, don't need to log
|
|
4250
|
+
console.error(err.stack);
|
|
3921
4251
|
} else if (err.name) {
|
|
3922
|
-
// log stack trace to browser console
|
|
3923
4252
|
console.error(err.stack);
|
|
3924
4253
|
// log to console window
|
|
3925
4254
|
consoleWarning(err.message);
|
|
@@ -4102,6 +4431,7 @@
|
|
|
4102
4431
|
return;
|
|
4103
4432
|
}
|
|
4104
4433
|
var e = model.getActiveLayer();
|
|
4434
|
+
if (!e) return;
|
|
4105
4435
|
if (internal.layerHasPaths(e.layer)) {
|
|
4106
4436
|
el.show();
|
|
4107
4437
|
checkBtn.show();
|
|
@@ -4180,47 +4510,6 @@
|
|
|
4180
4510
|
|
|
4181
4511
|
utils$1.inherit(RepairControl, EventDispatcher);
|
|
4182
4512
|
|
|
4183
|
-
function filterLayerByIds(lyr, ids) {
|
|
4184
|
-
var shapes;
|
|
4185
|
-
if (lyr.shapes) {
|
|
4186
|
-
shapes = ids.map(function(id) {
|
|
4187
|
-
return lyr.shapes[id];
|
|
4188
|
-
});
|
|
4189
|
-
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
4190
|
-
}
|
|
4191
|
-
return lyr;
|
|
4192
|
-
}
|
|
4193
|
-
|
|
4194
|
-
function formatLayerNameForDisplay(name) {
|
|
4195
|
-
return name || '[unnamed]';
|
|
4196
|
-
}
|
|
4197
|
-
|
|
4198
|
-
function cleanLayerName(raw) {
|
|
4199
|
-
return raw.replace(/[\n\t/\\]/g, '')
|
|
4200
|
-
.replace(/^[.\s]+/, '').replace(/[.\s]+$/, '');
|
|
4201
|
-
}
|
|
4202
|
-
|
|
4203
|
-
function updateLayerStackOrder(layers) {
|
|
4204
|
-
// 1. assign ascending ids to unassigned layers above the range of other layers
|
|
4205
|
-
layers.forEach(function(o, i) {
|
|
4206
|
-
if (!o.layer.menu_order) o.layer.menu_order = 1e6 + i;
|
|
4207
|
-
});
|
|
4208
|
-
// 2. sort in ascending order
|
|
4209
|
-
layers.sort(function(a, b) {
|
|
4210
|
-
return a.layer.menu_order - b.layer.menu_order;
|
|
4211
|
-
});
|
|
4212
|
-
// 3. assign consecutve ids
|
|
4213
|
-
layers.forEach(function(o, i) {
|
|
4214
|
-
o.layer.menu_order = i + 1;
|
|
4215
|
-
});
|
|
4216
|
-
return layers;
|
|
4217
|
-
}
|
|
4218
|
-
|
|
4219
|
-
function sortLayersForMenuDisplay(layers) {
|
|
4220
|
-
layers = updateLayerStackOrder(layers);
|
|
4221
|
-
return layers.reverse();
|
|
4222
|
-
}
|
|
4223
|
-
|
|
4224
4513
|
async function saveFileContentToClipboard(content) {
|
|
4225
4514
|
var str = utils$1.isString(content) ? content : content.toString();
|
|
4226
4515
|
await navigator.clipboard.writeText(str);
|
|
@@ -4233,7 +4522,7 @@
|
|
|
4233
4522
|
var menu = gui.container.findChild('.export-options').on('click', GUI.handleDirectEvent(gui.clearMode));
|
|
4234
4523
|
var layersArr = [];
|
|
4235
4524
|
var toggleBtn = null; // checkbox <input> for toggling layer selection
|
|
4236
|
-
var exportBtn = gui.container.findChild('.export-btn');
|
|
4525
|
+
var exportBtn = gui.container.findChild('.export-btn').addClass('disabled');
|
|
4237
4526
|
var ofileName = gui.container.findChild('#ofile-name');
|
|
4238
4527
|
new SimpleButton(menu.findChild('.close2-btn')).on('click', gui.clearMode);
|
|
4239
4528
|
|
|
@@ -4248,6 +4537,10 @@
|
|
|
4248
4537
|
return;
|
|
4249
4538
|
}
|
|
4250
4539
|
|
|
4540
|
+
model.on('update', function() {
|
|
4541
|
+
exportBtn.classed('disabled', !model.getActiveLayer());
|
|
4542
|
+
});
|
|
4543
|
+
|
|
4251
4544
|
new SimpleButton(menu.findChild('#export-btn').addClass('default-btn')).on('click', onExportClick);
|
|
4252
4545
|
gui.addMode('export', turnOn, turnOff, exportBtn);
|
|
4253
4546
|
gui.keyboard.onMenuSubmit(menu, onExportClick);
|
|
@@ -4578,6 +4871,14 @@
|
|
|
4578
4871
|
var layerOrderSlug;
|
|
4579
4872
|
|
|
4580
4873
|
gui.addMode('layer_menu', turnOn, turnOff, btn.findChild('.header-btn'));
|
|
4874
|
+
|
|
4875
|
+
// kludge to show menu button after initial import dialog is dismissed
|
|
4876
|
+
gui.on('mode', function(e) {
|
|
4877
|
+
if (!e.name) {
|
|
4878
|
+
updateMenuBtn();
|
|
4879
|
+
}
|
|
4880
|
+
});
|
|
4881
|
+
|
|
4581
4882
|
model.on('update', function(e) {
|
|
4582
4883
|
updateMenuBtn();
|
|
4583
4884
|
if (isOpen) render();
|
|
@@ -4668,8 +4969,9 @@
|
|
|
4668
4969
|
}
|
|
4669
4970
|
|
|
4670
4971
|
function updateMenuBtn() {
|
|
4671
|
-
var
|
|
4672
|
-
var
|
|
4972
|
+
var lyr = model.getActiveLayer()?.layer;
|
|
4973
|
+
var lyrName = lyr?.name || '';
|
|
4974
|
+
var menuTitle = lyrName || lyr && '[unnamed layer]' || '[no data]';
|
|
4673
4975
|
var pageTitle = lyrName || 'mapshaper';
|
|
4674
4976
|
btn.classed('active', 'true').findChild('.layer-name').html(menuTitle + " ▼");
|
|
4675
4977
|
window.document.title = pageTitle;
|
|
@@ -4681,6 +4983,8 @@
|
|
|
4681
4983
|
}
|
|
4682
4984
|
|
|
4683
4985
|
function renderSourceFileList() {
|
|
4986
|
+
el.findChild('.no-layer-note').classed('hidden', model.getActiveLayer());
|
|
4987
|
+
el.findChild('.source-file-section').classed('hidden', !model.getActiveLayer());
|
|
4684
4988
|
var list = el.findChild('.file-list');
|
|
4685
4989
|
var files = [];
|
|
4686
4990
|
list.empty();
|
|
@@ -5186,14 +5490,24 @@
|
|
|
5186
5490
|
addHistoryState(undo, redo);
|
|
5187
5491
|
});
|
|
5188
5492
|
|
|
5189
|
-
gui.on('vertex_delete', function(e) {
|
|
5190
|
-
// get vertex coords in data coordinates (not display coordinates);
|
|
5191
|
-
var p = getVertexCoords(e.data.target, e.vertex_id);
|
|
5493
|
+
gui.on('vertex_delete', function(e) {
|
|
5494
|
+
// get vertex coords in data coordinates (not display coordinates);
|
|
5495
|
+
var p = getVertexCoords(e.data.target, e.vertex_id);
|
|
5496
|
+
var redo = function() {
|
|
5497
|
+
deleteVertex$1(e.data.target, e.vertex_id);
|
|
5498
|
+
};
|
|
5499
|
+
var undo = function() {
|
|
5500
|
+
insertVertex$1(e.data.target, e.vertex_id, p);
|
|
5501
|
+
};
|
|
5502
|
+
addHistoryState(undo, redo);
|
|
5503
|
+
});
|
|
5504
|
+
|
|
5505
|
+
gui.on('point_add', function(e) {
|
|
5192
5506
|
var redo = function() {
|
|
5193
|
-
|
|
5507
|
+
appendNewPoint(e.data.target, e.p);
|
|
5194
5508
|
};
|
|
5195
5509
|
var undo = function() {
|
|
5196
|
-
|
|
5510
|
+
deleteLastPoint(e.data.target);
|
|
5197
5511
|
};
|
|
5198
5512
|
addHistoryState(undo, redo);
|
|
5199
5513
|
});
|
|
@@ -5266,6 +5580,7 @@
|
|
|
5266
5580
|
var _hidden = true;
|
|
5267
5581
|
gui.on('active', updateVisibility);
|
|
5268
5582
|
gui.on('inactive', updateVisibility);
|
|
5583
|
+
gui.model.on('update', updateVisibility);
|
|
5269
5584
|
|
|
5270
5585
|
// @iconRef: selector for an (svg) button icon
|
|
5271
5586
|
this.addButton = function(iconRef) {
|
|
@@ -5294,7 +5609,7 @@
|
|
|
5294
5609
|
};
|
|
5295
5610
|
|
|
5296
5611
|
function updateVisibility() {
|
|
5297
|
-
if (GUI.isActiveInstance(gui) && !_hidden) {
|
|
5612
|
+
if (GUI.isActiveInstance(gui) && !_hidden && !!gui.model.getActiveLayer()) {
|
|
5298
5613
|
buttons.show();
|
|
5299
5614
|
} else {
|
|
5300
5615
|
buttons.hide();
|
|
@@ -5315,6 +5630,7 @@
|
|
|
5315
5630
|
});
|
|
5316
5631
|
|
|
5317
5632
|
btn.on('click', function() {
|
|
5633
|
+
if (btn.hasClass('disabled')) return;
|
|
5318
5634
|
modes.enterMode(active ? null : name);
|
|
5319
5635
|
});
|
|
5320
5636
|
}
|
|
@@ -5389,14 +5705,16 @@
|
|
|
5389
5705
|
var ctrlDown = false;
|
|
5390
5706
|
document.addEventListener('keyup', function(e) {
|
|
5391
5707
|
if (!GUI.isActiveInstance(gui)) return;
|
|
5392
|
-
if
|
|
5708
|
+
// this can fail to fire if keyup occurs over a context menu
|
|
5709
|
+
// if (e.keyCode == 16) shiftDown = false;
|
|
5710
|
+
shiftDown = e.shiftKey;
|
|
5393
5711
|
if (e.keyCode == 17) ctrlDown = false;
|
|
5394
5712
|
self.dispatchEvent('keyup', getEventData(e));
|
|
5395
5713
|
});
|
|
5396
5714
|
|
|
5397
5715
|
document.addEventListener('keydown', function(e) {
|
|
5398
5716
|
if (!GUI.isActiveInstance(gui)) return;
|
|
5399
|
-
|
|
5717
|
+
shiftDown = e.shiftKey;
|
|
5400
5718
|
if (e.keyCode == 17) ctrlDown = true;
|
|
5401
5719
|
self.dispatchEvent('keydown', getEventData(e));
|
|
5402
5720
|
});
|
|
@@ -7621,9 +7939,12 @@
|
|
|
7621
7939
|
var priority = 2;
|
|
7622
7940
|
|
|
7623
7941
|
mouse.on('contextmenu', function(e) {
|
|
7624
|
-
|
|
7625
|
-
|
|
7942
|
+
// shift key enables default menu (for development)
|
|
7943
|
+
if (gui.keyboard.shiftIsPressed()) {
|
|
7944
|
+
return;
|
|
7626
7945
|
}
|
|
7946
|
+
e.originalEvent.preventDefault();
|
|
7947
|
+
if (!targetLayer) return; // TODO: enable menu on empty map
|
|
7627
7948
|
triggerHitEvent('contextmenu', e);
|
|
7628
7949
|
}, false);
|
|
7629
7950
|
|
|
@@ -7667,7 +7988,6 @@
|
|
|
7667
7988
|
};
|
|
7668
7989
|
|
|
7669
7990
|
function updateHitTest(featureFilter) {
|
|
7670
|
-
if (!hoverable()) return;
|
|
7671
7991
|
hitTest = getPointerHitTest(targetLayer, ext, interactionMode, featureFilter);
|
|
7672
7992
|
}
|
|
7673
7993
|
|
|
@@ -7688,7 +8008,7 @@
|
|
|
7688
8008
|
}
|
|
7689
8009
|
|
|
7690
8010
|
function hoverable() {
|
|
7691
|
-
return
|
|
8011
|
+
return !!interactionMode;
|
|
7692
8012
|
}
|
|
7693
8013
|
|
|
7694
8014
|
function selectable() {
|
|
@@ -7864,6 +8184,7 @@
|
|
|
7864
8184
|
|
|
7865
8185
|
// Hits are re-detected on 'hover' (if hit detection is active)
|
|
7866
8186
|
mouse.on('hover', function(e) {
|
|
8187
|
+
if (gui.contextMenu.isOpen()) return;
|
|
7867
8188
|
handlePointerEvent(e);
|
|
7868
8189
|
if (storedData.pinned || !hitTest || !active) return;
|
|
7869
8190
|
if (e.hover && isOverMap(e)) {
|
|
@@ -7979,10 +8300,6 @@
|
|
|
7979
8300
|
// check if an event is used in the current interaction mode
|
|
7980
8301
|
function eventIsEnabled(type) {
|
|
7981
8302
|
if (!active) return false;
|
|
7982
|
-
if (interactionMode == 'drawing' && (type == 'hover' || type == 'dblclick')) {
|
|
7983
|
-
return true; // special case -- using hover for line drawing animation
|
|
7984
|
-
}
|
|
7985
|
-
|
|
7986
8303
|
if (type == 'click' && gui.keyboard.ctrlIsPressed()) {
|
|
7987
8304
|
return false; // don't fire if context menu might open
|
|
7988
8305
|
}
|
|
@@ -7993,6 +8310,10 @@
|
|
|
7993
8310
|
return true; // click events are triggered even if no shape is hit
|
|
7994
8311
|
}
|
|
7995
8312
|
|
|
8313
|
+
if (interactionMode == 'drawing' && (type == 'hover' || type == 'dblclick')) {
|
|
8314
|
+
return true; // special case -- using hover for line drawing animation
|
|
8315
|
+
}
|
|
8316
|
+
|
|
7996
8317
|
// ignore pointer events when no features are being hit
|
|
7997
8318
|
// (don't block pan and other navigation when events aren't being used for editing)
|
|
7998
8319
|
var hitId = self.getHitId();
|
|
@@ -8848,7 +9169,7 @@
|
|
|
8848
9169
|
}
|
|
8849
9170
|
|
|
8850
9171
|
gui.on('map_reset', function() {
|
|
8851
|
-
ext.
|
|
9172
|
+
ext.reset(true);
|
|
8852
9173
|
});
|
|
8853
9174
|
|
|
8854
9175
|
zoomTween.on('change', function(e) {
|
|
@@ -8866,8 +9187,9 @@
|
|
|
8866
9187
|
|
|
8867
9188
|
mouse.on('dragstart', function(e) {
|
|
8868
9189
|
if (disabled()) return;
|
|
8869
|
-
if
|
|
8870
|
-
//
|
|
9190
|
+
// allow drawing rectangles if active layer is empty
|
|
9191
|
+
// var lyr = gui.model.getActiveLayer()?.layer;
|
|
9192
|
+
// if (lyr && !internal.layerHasGeometry(lyr)) return;
|
|
8871
9193
|
shiftDrag = !!e.shiftKey;
|
|
8872
9194
|
if (shiftDrag) {
|
|
8873
9195
|
if (useBoxZoom()) zoomBox.turnOn();
|
|
@@ -10355,25 +10677,18 @@
|
|
|
10355
10677
|
|
|
10356
10678
|
mouse.on('click', function(e) {
|
|
10357
10679
|
if (!active()) return;
|
|
10358
|
-
|
|
10680
|
+
var p = pixToDataCoords(e.x, e.y);
|
|
10681
|
+
var target = hit.getHitTarget();
|
|
10682
|
+
appendNewPoint(target, p);
|
|
10683
|
+
gui.dispatchEvent('point_add', {p, target});
|
|
10359
10684
|
gui.dispatchEvent('map-needs-refresh');
|
|
10360
10685
|
});
|
|
10361
10686
|
|
|
10362
|
-
// x, y: pixel coordinates
|
|
10363
|
-
function addPoint(x, y) {
|
|
10364
|
-
var p = ext.translatePixelCoords(x, y);
|
|
10365
|
-
var lyr = hit.getHitTarget();
|
|
10366
|
-
var fid = lyr.shapes.length;
|
|
10367
|
-
var d = appendNewDataRecord(lyr);
|
|
10368
|
-
if (d) {
|
|
10369
|
-
// this seems to work even for projected layers -- the data tables
|
|
10370
|
-
// of projected and original data seem to be shared.
|
|
10371
|
-
lyr.data.getRecords()[fid] = d;
|
|
10372
|
-
}
|
|
10373
|
-
lyr.shapes[fid] = [p];
|
|
10374
|
-
updatePointCoords(lyr, fid);
|
|
10375
|
-
}
|
|
10376
10687
|
|
|
10688
|
+
function pixToDataCoords(x, y) {
|
|
10689
|
+
var target = hit.getHitTarget();
|
|
10690
|
+
return translateDisplayPoint(target, ext.translatePixelCoords(x, y));
|
|
10691
|
+
}
|
|
10377
10692
|
|
|
10378
10693
|
}
|
|
10379
10694
|
|
|
@@ -10394,26 +10709,32 @@
|
|
|
10394
10709
|
|
|
10395
10710
|
_position.on('resize', function(e) {
|
|
10396
10711
|
if (ready()) {
|
|
10397
|
-
triggerChangeEvent({resize: true});
|
|
10712
|
+
// triggerChangeEvent({resize: true});
|
|
10713
|
+
triggerChangeEvent();
|
|
10398
10714
|
}
|
|
10399
10715
|
});
|
|
10400
10716
|
|
|
10401
10717
|
function ready() { return !!_fullBounds; }
|
|
10402
10718
|
|
|
10403
|
-
this.reset = function() {
|
|
10719
|
+
this.reset = function(fire) {
|
|
10404
10720
|
if (!ready()) return;
|
|
10405
|
-
recenter(_fullBounds.centerX(), _fullBounds.centerY(), 1
|
|
10721
|
+
recenter(_fullBounds.centerX(), _fullBounds.centerY(), 1);
|
|
10722
|
+
if (fire) {
|
|
10723
|
+
triggerChangeEvent();
|
|
10724
|
+
}
|
|
10406
10725
|
};
|
|
10407
10726
|
|
|
10408
10727
|
this.home = function() {
|
|
10409
10728
|
if (!ready()) return;
|
|
10410
10729
|
recenter(_fullBounds.centerX(), _fullBounds.centerY(), 1);
|
|
10730
|
+
triggerChangeEvent();
|
|
10411
10731
|
};
|
|
10412
10732
|
|
|
10413
10733
|
this.pan = function(xpix, ypix) {
|
|
10414
10734
|
if (!ready()) return;
|
|
10415
10735
|
var t = this.getTransform();
|
|
10416
10736
|
recenter(_cx - xpix / t.mx, _cy - ypix / t.my);
|
|
10737
|
+
triggerChangeEvent();
|
|
10417
10738
|
};
|
|
10418
10739
|
|
|
10419
10740
|
// Zoom to @w (width of the map viewport in coordinates)
|
|
@@ -10436,6 +10757,7 @@
|
|
|
10436
10757
|
cx = fx + dx2,
|
|
10437
10758
|
cy = fy + dy2;
|
|
10438
10759
|
recenter(cx, cy, scale);
|
|
10760
|
+
triggerChangeEvent();
|
|
10439
10761
|
};
|
|
10440
10762
|
|
|
10441
10763
|
this.zoomByPct = function(pct, xpct, ypct) {
|
|
@@ -10527,11 +10849,10 @@
|
|
|
10527
10849
|
return this.getTransform().invert().transform(x, y);
|
|
10528
10850
|
};
|
|
10529
10851
|
|
|
10530
|
-
function recenter(cx, cy, scale
|
|
10852
|
+
function recenter(cx, cy, scale) {
|
|
10531
10853
|
scale = scale ? limitScale(scale) : _scale;
|
|
10532
10854
|
if (cx == _cx && cy == _cy && scale == _scale) return;
|
|
10533
10855
|
navigate(cx, cy, scale);
|
|
10534
|
-
triggerChangeEvent(data);
|
|
10535
10856
|
}
|
|
10536
10857
|
|
|
10537
10858
|
function navigate(cx, cy, scale) {
|
|
@@ -10558,9 +10879,8 @@
|
|
|
10558
10879
|
_scale = scale;
|
|
10559
10880
|
}
|
|
10560
10881
|
|
|
10561
|
-
function triggerChangeEvent(
|
|
10562
|
-
|
|
10563
|
-
_self.dispatchEvent('change', data);
|
|
10882
|
+
function triggerChangeEvent() {
|
|
10883
|
+
_self.dispatchEvent('change');
|
|
10564
10884
|
}
|
|
10565
10885
|
|
|
10566
10886
|
// stop zooming before rounding errors become too obvious
|
|
@@ -11453,8 +11773,10 @@
|
|
|
11453
11773
|
return el;
|
|
11454
11774
|
}
|
|
11455
11775
|
|
|
11456
|
-
function LayerRenderer(gui, container
|
|
11776
|
+
function LayerRenderer(gui, container) {
|
|
11457
11777
|
var el = El(container),
|
|
11778
|
+
ext = gui.map.getExtent(),
|
|
11779
|
+
mouse = gui.map.getMouse(),
|
|
11458
11780
|
_mainCanv = new DisplayCanvas().appendTo(el),
|
|
11459
11781
|
_overlayCanv = new DisplayCanvas().appendTo(el),
|
|
11460
11782
|
_svg = new SvgDisplayLayer(gui, ext, mouse).appendTo(el),
|
|
@@ -11507,499 +11829,254 @@
|
|
|
11507
11829
|
layers.forEach(function(lyr) {
|
|
11508
11830
|
if (noRedraw) {
|
|
11509
11831
|
_furniture.reposition(lyr, 'furniture');
|
|
11510
|
-
} else {
|
|
11511
|
-
_furniture.drawLayer(lyr, 'furniture');
|
|
11512
|
-
}
|
|
11513
|
-
});
|
|
11514
|
-
};
|
|
11515
|
-
|
|
11516
|
-
// kludge: skip rendering base layers if hovering, except on first hover
|
|
11517
|
-
// (because highlight shapes may be rendered to the main canvas)
|
|
11518
|
-
function skipMainLayerRedraw(action) {
|
|
11519
|
-
return action == 'hover' && _overlayCanv.visible();
|
|
11520
|
-
}
|
|
11521
|
-
|
|
11522
|
-
function drawCanvasLayer(lyr, canv) {
|
|
11523
|
-
if (!lyr) return;
|
|
11524
|
-
if (lyr.gui.style.type == 'outline') {
|
|
11525
|
-
drawOutlineLayerToCanvas(lyr, canv, ext);
|
|
11526
|
-
} else {
|
|
11527
|
-
drawStyledLayerToCanvas(lyr, canv, ext);
|
|
11528
|
-
}
|
|
11529
|
-
}
|
|
11530
|
-
|
|
11531
|
-
function getSvgLayerType(layer) {
|
|
11532
|
-
var type = null;
|
|
11533
|
-
if (internal.layerHasSvgSymbols(layer)) {
|
|
11534
|
-
type = 'symbol'; // also label + symbol
|
|
11535
|
-
} else if (internal.layerHasLabels(layer)) {
|
|
11536
|
-
type = 'symbol';
|
|
11537
|
-
}
|
|
11538
|
-
return type;
|
|
11539
|
-
}
|
|
11540
|
-
}
|
|
11541
|
-
|
|
11542
|
-
// Controls the shift-drag box editing tool
|
|
11543
|
-
//
|
|
11544
|
-
function BoxTool(gui, ext, nav) {
|
|
11545
|
-
var self = new EventDispatcher();
|
|
11546
|
-
var box = new HighlightBox(gui, {name: 'box-tool', persistent: true, handles: true, draggable: true});
|
|
11547
|
-
var popup = gui.container.findChild('.box-tool-options');
|
|
11548
|
-
var coords = popup.findChild('.box-coords');
|
|
11549
|
-
var _on = false;
|
|
11550
|
-
|
|
11551
|
-
var infoBtn = new SimpleButton(popup.findChild('.info-btn')).on('click', function() {
|
|
11552
|
-
if (coords.visible()) hideCoords(); else showCoords();
|
|
11553
|
-
});
|
|
11554
|
-
|
|
11555
|
-
new SimpleButton(popup.findChild('.cancel-btn')).on('click', function() {
|
|
11556
|
-
reset();
|
|
11557
|
-
});
|
|
11558
|
-
|
|
11559
|
-
new SimpleButton(popup.findChild('.select-btn')).on('click', function() {
|
|
11560
|
-
var coords = box.getDataCoords();
|
|
11561
|
-
if (!coords) return;
|
|
11562
|
-
gui.enterMode('selection_tool');
|
|
11563
|
-
gui.interaction.setMode('selection');
|
|
11564
|
-
// kludge to pass bbox to the selection tool
|
|
11565
|
-
gui.dispatchEvent('selection_bridge', {
|
|
11566
|
-
map_data_bbox: coords
|
|
11567
|
-
});
|
|
11568
|
-
});
|
|
11569
|
-
|
|
11570
|
-
new SimpleButton(popup.findChild('.clip-btn')).on('click', function() {
|
|
11571
|
-
runCommand('-clip bbox=' + box.getDataCoords().join(','));
|
|
11572
|
-
});
|
|
11573
|
-
|
|
11574
|
-
new SimpleButton(popup.findChild('.erase-btn')).on('click', function() {
|
|
11575
|
-
runCommand('-erase bbox=' + box.getDataCoords().join(','));
|
|
11576
|
-
});
|
|
11577
|
-
|
|
11578
|
-
new SimpleButton(popup.findChild('.rect-btn')).on('click', function() {
|
|
11579
|
-
var cmd = '-rectangle + bbox=' + box.getDataCoords().join(',');
|
|
11580
|
-
runCommand(cmd);
|
|
11581
|
-
});
|
|
11582
|
-
|
|
11583
|
-
new SimpleButton(popup.findChild('.frame-btn')).on('click', function() {
|
|
11584
|
-
openAddFramePopup(gui, box.getDataCoords());
|
|
11585
|
-
});
|
|
11586
|
-
|
|
11587
|
-
gui.addMode('box_tool', turnOn, turnOff);
|
|
11588
|
-
|
|
11589
|
-
gui.on('interaction_mode_change', function(e) {
|
|
11590
|
-
if (e.mode === 'box') {
|
|
11591
|
-
gui.enterMode('box_tool');
|
|
11592
|
-
} else if (_on) {
|
|
11593
|
-
turnOff();
|
|
11594
|
-
}
|
|
11595
|
-
});
|
|
11596
|
-
|
|
11597
|
-
gui.on('shift_drag_start', function() {
|
|
11598
|
-
// box.classed('zooming', inZoomMode());
|
|
11599
|
-
hideCoords();
|
|
11600
|
-
});
|
|
11601
|
-
|
|
11602
|
-
box.on('dragend', function(e) {
|
|
11603
|
-
if (_on) popup.show();
|
|
11604
|
-
});
|
|
11605
|
-
|
|
11606
|
-
box.on('handle_drag', function() {
|
|
11607
|
-
if (coords.visible()) {
|
|
11608
|
-
showCoords();
|
|
11609
|
-
}
|
|
11610
|
-
});
|
|
11611
|
-
|
|
11612
|
-
function inZoomMode() {
|
|
11613
|
-
return !_on && gui.getMode() != 'selection_tool';
|
|
11614
|
-
}
|
|
11615
|
-
|
|
11616
|
-
function runCommand(cmd) {
|
|
11617
|
-
if (gui.console) {
|
|
11618
|
-
gui.console.runMapshaperCommands(cmd, function(err) {
|
|
11619
|
-
reset();
|
|
11620
|
-
gui.clearMode();
|
|
11621
|
-
});
|
|
11622
|
-
}
|
|
11623
|
-
// reset(); // TODO: exit interactive mode
|
|
11624
|
-
}
|
|
11625
|
-
|
|
11626
|
-
function showCoords() {
|
|
11627
|
-
El(infoBtn.node()).addClass('selected-btn');
|
|
11628
|
-
coords.text(box.getDataCoords().join(','));
|
|
11629
|
-
coords.show();
|
|
11630
|
-
GUI.selectElement(coords.node());
|
|
11631
|
-
}
|
|
11632
|
-
|
|
11633
|
-
function hideCoords() {
|
|
11634
|
-
El(infoBtn.node()).removeClass('selected-btn');
|
|
11635
|
-
coords.hide();
|
|
11636
|
-
}
|
|
11637
|
-
|
|
11638
|
-
function turnOn() {
|
|
11639
|
-
box.turnOn();
|
|
11640
|
-
_on = true;
|
|
11641
|
-
}
|
|
11642
|
-
|
|
11643
|
-
function turnOff() {
|
|
11644
|
-
box.turnOff();
|
|
11645
|
-
if (gui.interaction.getMode() == 'box') {
|
|
11646
|
-
// mode change was not initiated by interactive menu -- turn off interactivity
|
|
11647
|
-
gui.interaction.turnOff();
|
|
11648
|
-
}
|
|
11649
|
-
_on = false;
|
|
11650
|
-
reset();
|
|
11651
|
-
}
|
|
11652
|
-
|
|
11653
|
-
function reset() {
|
|
11654
|
-
box.hide();
|
|
11655
|
-
popup.hide();
|
|
11656
|
-
hideCoords();
|
|
11657
|
-
}
|
|
11658
|
-
|
|
11659
|
-
function openAddFramePopup(gui, bbox) {
|
|
11660
|
-
var popup = showPopupAlert('', 'Add a map frame');
|
|
11661
|
-
var el = popup.container();
|
|
11662
|
-
el.addClass('option-menu');
|
|
11663
|
-
var html = `<p>Enter a width in px, cm or inches to create a frame layer
|
|
11664
|
-
for setting the size of the map for symbol scaling in the
|
|
11665
|
-
GUI and setting the size and crop of SVG output.</p><div><input type="text" class="frame-width text-input" placeholder="examples: 600px 5in"></div>
|
|
11666
|
-
<div tabindex="0" class="btn dialog-btn">Create</div></span>`;
|
|
11667
|
-
el.html(html);
|
|
11668
|
-
var input = el.findChild('.frame-width');
|
|
11669
|
-
input.node().focus();
|
|
11670
|
-
var btn = el.findChild('.btn').on('click', function() {
|
|
11671
|
-
var widthStr = input.node().value.trim();
|
|
11672
|
-
if (parseFloat(widthStr) > 0 === false) {
|
|
11673
|
-
// invalid input
|
|
11674
|
-
input.node().value = '';
|
|
11675
|
-
return;
|
|
11676
|
-
}
|
|
11677
|
-
var cmd = `-rectangle + name=frame bbox='${bbox.join(',')}' width='${widthStr}'`;
|
|
11678
|
-
runCommand(cmd);
|
|
11679
|
-
popup.close();
|
|
11680
|
-
});
|
|
11681
|
-
}
|
|
11682
|
-
|
|
11683
|
-
return self;
|
|
11684
|
-
}
|
|
11685
|
-
|
|
11686
|
-
function RectangleControl(gui, hit) {
|
|
11687
|
-
var box = new HighlightBox(gui, {name: 'rectangle-tool', persistent: true, handles: true, classname: 'rectangles', draggable: false});
|
|
11688
|
-
var _on = false;
|
|
11689
|
-
var dragInfo;
|
|
11690
|
-
|
|
11691
|
-
gui.addMode('rectangle_tool', turnOn, turnOff);
|
|
11692
|
-
|
|
11693
|
-
gui.on('interaction_mode_change', function(e) {
|
|
11694
|
-
if (e.mode === 'rectangles') {
|
|
11695
|
-
gui.enterMode('rectangle_tool');
|
|
11696
|
-
} else if (_on) {
|
|
11697
|
-
turnOff();
|
|
11698
|
-
}
|
|
11699
|
-
});
|
|
11700
|
-
|
|
11701
|
-
hit.on('change', function(e) {
|
|
11702
|
-
if (!_on) return;
|
|
11703
|
-
// TODO: handle multiple hits (see gui-inspection-control)
|
|
11704
|
-
var id = e.id;
|
|
11705
|
-
if (e.id > -1 && e.pinned) {
|
|
11706
|
-
var target = hit.getHitTarget();
|
|
11707
|
-
var path = target.shapes[e.id][0];
|
|
11708
|
-
var bbox = target.gui.displayArcs.getSimpleShapeBounds(path).toArray();
|
|
11709
|
-
box.setDataCoords(bbox);
|
|
11710
|
-
dragInfo = {
|
|
11711
|
-
id: e.id,
|
|
11712
|
-
target: target,
|
|
11713
|
-
ids: [],
|
|
11714
|
-
points: []
|
|
11715
|
-
};
|
|
11716
|
-
var iter = target.gui.displayArcs.getShapeIter(path);
|
|
11717
|
-
while (iter.hasNext()) {
|
|
11718
|
-
dragInfo.points.push([iter.x, iter.y]);
|
|
11719
|
-
dragInfo.ids.push(iter._arc.i);
|
|
11720
|
-
}
|
|
11721
|
-
gui.container.findChild('.map-layers').classed('dragging', true);
|
|
11722
|
-
|
|
11723
|
-
} else if (dragInfo) {
|
|
11724
|
-
gui.dispatchEvent('rectangle_dragend', dragInfo); // save undo state
|
|
11725
|
-
gui.container.findChild('.map-layers').classed('dragging', false);
|
|
11726
|
-
reset();
|
|
11727
|
-
} else {
|
|
11728
|
-
box.hide();
|
|
11729
|
-
}
|
|
11730
|
-
|
|
11731
|
-
});
|
|
11732
|
-
|
|
11733
|
-
box.on('handle_drag', function(e) {
|
|
11734
|
-
if (!_on || !dragInfo) return;
|
|
11735
|
-
var coords = internal.bboxToCoords(box.getDataCoords());
|
|
11736
|
-
setRectangleCoords(dragInfo.target, dragInfo.ids, coords);
|
|
11737
|
-
gui.dispatchEvent('map-needs-refresh');
|
|
11738
|
-
});
|
|
11832
|
+
} else {
|
|
11833
|
+
_furniture.drawLayer(lyr, 'furniture');
|
|
11834
|
+
}
|
|
11835
|
+
});
|
|
11836
|
+
};
|
|
11739
11837
|
|
|
11740
|
-
|
|
11741
|
-
|
|
11742
|
-
|
|
11838
|
+
// kludge: skip rendering base layers if hovering, except on first hover
|
|
11839
|
+
// (because highlight shapes may be rendered to the main canvas)
|
|
11840
|
+
function skipMainLayerRedraw(action) {
|
|
11841
|
+
return action == 'hover' && _overlayCanv.visible();
|
|
11743
11842
|
}
|
|
11744
11843
|
|
|
11745
|
-
function
|
|
11746
|
-
|
|
11747
|
-
if (gui.
|
|
11748
|
-
|
|
11749
|
-
|
|
11844
|
+
function drawCanvasLayer(lyr, canv) {
|
|
11845
|
+
if (!lyr) return;
|
|
11846
|
+
if (lyr.gui.style.type == 'outline') {
|
|
11847
|
+
drawOutlineLayerToCanvas(lyr, canv, ext);
|
|
11848
|
+
} else {
|
|
11849
|
+
drawStyledLayerToCanvas(lyr, canv, ext);
|
|
11750
11850
|
}
|
|
11751
|
-
_on = false;
|
|
11752
|
-
reset();
|
|
11753
11851
|
}
|
|
11754
11852
|
|
|
11755
|
-
function
|
|
11756
|
-
|
|
11757
|
-
|
|
11853
|
+
function getSvgLayerType(layer) {
|
|
11854
|
+
var type = null;
|
|
11855
|
+
if (internal.layerHasSvgSymbols(layer)) {
|
|
11856
|
+
type = 'symbol'; // also label + symbol
|
|
11857
|
+
} else if (internal.layerHasLabels(layer)) {
|
|
11858
|
+
type = 'symbol';
|
|
11859
|
+
}
|
|
11860
|
+
return type;
|
|
11758
11861
|
}
|
|
11759
11862
|
}
|
|
11760
11863
|
|
|
11761
|
-
//
|
|
11762
|
-
//
|
|
11763
|
-
function
|
|
11764
|
-
var
|
|
11765
|
-
|
|
11766
|
-
|
|
11767
|
-
|
|
11768
|
-
|
|
11769
|
-
update();
|
|
11770
|
-
}
|
|
11864
|
+
// Controls the shift-drag box editing tool
|
|
11865
|
+
//
|
|
11866
|
+
function BoxTool(gui, ext, nav) {
|
|
11867
|
+
var self = new EventDispatcher();
|
|
11868
|
+
var box = new HighlightBox(gui, {name: 'box-tool', persistent: true, handles: true, draggable: true});
|
|
11869
|
+
var popup = gui.container.findChild('.box-tool-options');
|
|
11870
|
+
var coords = popup.findChild('.box-coords');
|
|
11871
|
+
var _on = false;
|
|
11771
11872
|
|
|
11772
|
-
|
|
11773
|
-
if (
|
|
11774
|
-
|
|
11775
|
-
filteredArcs = initFilteredArcs(unfilteredArcs);
|
|
11776
|
-
filteredSegLen = internal.getAvgSegment(filteredArcs);
|
|
11777
|
-
} else {
|
|
11778
|
-
// Use fast simplification as a fallback
|
|
11779
|
-
filteredSegLen = internal.getAvgSegment(unfilteredArcs) * 4;
|
|
11780
|
-
filteredArcs = internal.simplifyArcsFast(unfilteredArcs, filteredSegLen);
|
|
11781
|
-
}
|
|
11782
|
-
}
|
|
11873
|
+
var infoBtn = new SimpleButton(popup.findChild('.info-btn')).on('click', function() {
|
|
11874
|
+
if (coords.visible()) hideCoords(); else showCoords();
|
|
11875
|
+
});
|
|
11783
11876
|
|
|
11784
|
-
|
|
11785
|
-
|
|
11786
|
-
|
|
11787
|
-
var currInterval = arcs.getRetainedInterval();
|
|
11788
|
-
var filterZ = arcs.getThresholdByPct(filterPct, nth);
|
|
11789
|
-
var filteredArcs = arcs.setRetainedInterval(filterZ).getFilteredCopy();
|
|
11790
|
-
arcs.setRetainedInterval(currInterval); // reset current simplification
|
|
11791
|
-
return filteredArcs;
|
|
11792
|
-
}
|
|
11877
|
+
new SimpleButton(popup.findChild('.cancel-btn')).on('click', function() {
|
|
11878
|
+
reset();
|
|
11879
|
+
});
|
|
11793
11880
|
|
|
11794
|
-
|
|
11795
|
-
|
|
11796
|
-
|
|
11797
|
-
|
|
11798
|
-
|
|
11799
|
-
|
|
11800
|
-
|
|
11801
|
-
|
|
11802
|
-
|
|
11803
|
-
|
|
11804
|
-
if (filteredArcs) {
|
|
11805
|
-
// match simplification of unfiltered arcs
|
|
11806
|
-
filteredArcs.setRetainedInterval(unfilteredArcs.getRetainedInterval());
|
|
11807
|
-
}
|
|
11808
|
-
// switch to filtered version of arcs at small scales
|
|
11809
|
-
var unitsPerPixel = 1/ext.getTransform().mx,
|
|
11810
|
-
useFiltering = filteredArcs && unitsPerPixel > filteredSegLen * 1.5;
|
|
11811
|
-
return useFiltering ? filteredArcs : unfilteredArcs;
|
|
11812
|
-
};
|
|
11813
|
-
}
|
|
11881
|
+
new SimpleButton(popup.findChild('.select-btn')).on('click', function() {
|
|
11882
|
+
var coords = box.getDataCoords();
|
|
11883
|
+
if (!coords) return;
|
|
11884
|
+
gui.enterMode('selection_tool');
|
|
11885
|
+
gui.interaction.setMode('selection');
|
|
11886
|
+
// kludge to pass bbox to the selection tool
|
|
11887
|
+
gui.dispatchEvent('selection_bridge', {
|
|
11888
|
+
map_data_bbox: coords
|
|
11889
|
+
});
|
|
11890
|
+
});
|
|
11814
11891
|
|
|
11815
|
-
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
cellWidth = 12,
|
|
11819
|
-
cellHeight = 5,
|
|
11820
|
-
gutter = 6,
|
|
11821
|
-
arcs = [],
|
|
11822
|
-
shapes = [],
|
|
11823
|
-
aspectRatio = 1.1,
|
|
11824
|
-
x, y, col, row, blockSize;
|
|
11892
|
+
new SimpleButton(popup.findChild('.clip-btn')).on('click', function() {
|
|
11893
|
+
runCommand('-clip bbox=' + box.getDataCoords().join(','));
|
|
11894
|
+
});
|
|
11825
11895
|
|
|
11826
|
-
|
|
11827
|
-
|
|
11828
|
-
|
|
11829
|
-
cellWidth = 4;
|
|
11830
|
-
cellHeight = 4;
|
|
11831
|
-
aspectRatio = 1.45;
|
|
11832
|
-
} else if (n > 5000) {
|
|
11833
|
-
cellWidth = 5;
|
|
11834
|
-
gutter = 3;
|
|
11835
|
-
aspectRatio = 1.45;
|
|
11836
|
-
} else if (n > 1000) {
|
|
11837
|
-
gutter = 3;
|
|
11838
|
-
cellWidth = 8;
|
|
11839
|
-
aspectRatio = 1.3;
|
|
11840
|
-
}
|
|
11896
|
+
new SimpleButton(popup.findChild('.erase-btn')).on('click', function() {
|
|
11897
|
+
runCommand('-erase bbox=' + box.getDataCoords().join(','));
|
|
11898
|
+
});
|
|
11841
11899
|
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
11846
|
-
}
|
|
11900
|
+
new SimpleButton(popup.findChild('.rect-btn')).on('click', function() {
|
|
11901
|
+
var cmd = '-rectangle + bbox=' + box.getDataCoords().join(',');
|
|
11902
|
+
runCommand(cmd);
|
|
11903
|
+
});
|
|
11847
11904
|
|
|
11848
|
-
|
|
11849
|
-
|
|
11850
|
-
|
|
11851
|
-
x = col * (cellWidth + gutter);
|
|
11852
|
-
y = cellHeight * (blockSize - row);
|
|
11853
|
-
if (arcs) {
|
|
11854
|
-
arcs.push(getArc(x, y, cellWidth, cellHeight));
|
|
11855
|
-
shapes.push([[i]]);
|
|
11856
|
-
} else {
|
|
11857
|
-
shapes.push([[x, y]]);
|
|
11858
|
-
}
|
|
11859
|
-
}
|
|
11905
|
+
new SimpleButton(popup.findChild('.frame-btn')).on('click', function() {
|
|
11906
|
+
openAddFramePopup(gui, box.getDataCoords());
|
|
11907
|
+
});
|
|
11860
11908
|
|
|
11861
|
-
|
|
11862
|
-
return [[x, y], [x + w, y], [x + w, y - h], [x, y - h], [x, y]];
|
|
11863
|
-
}
|
|
11909
|
+
gui.addMode('box_tool', turnOn, turnOff);
|
|
11864
11910
|
|
|
11865
|
-
|
|
11866
|
-
|
|
11867
|
-
|
|
11868
|
-
|
|
11869
|
-
|
|
11870
|
-
}
|
|
11871
|
-
|
|
11872
|
-
};
|
|
11873
|
-
}
|
|
11911
|
+
gui.on('interaction_mode_change', function(e) {
|
|
11912
|
+
if (e.mode === 'box') {
|
|
11913
|
+
gui.enterMode('box_tool');
|
|
11914
|
+
} else if (_on) {
|
|
11915
|
+
turnOff();
|
|
11916
|
+
}
|
|
11917
|
+
});
|
|
11874
11918
|
|
|
11875
|
-
|
|
11876
|
-
|
|
11877
|
-
|
|
11878
|
-
var crsInfo = getDatasetCrsInfo(lyr.gui.source.dataset);
|
|
11879
|
-
var sourceCRS = crsInfo.crs || null; // let enhanceLayerForDisplay() handle null case
|
|
11880
|
-
if (!lyr.gui.geographic) {
|
|
11881
|
-
return;
|
|
11882
|
-
}
|
|
11883
|
-
if (lyr.gui.dynamic_crs && internal.crsAreEqual(sourceCRS, lyr.gui.dynamic_crs)) {
|
|
11884
|
-
return;
|
|
11885
|
-
}
|
|
11886
|
-
enhanceLayerForDisplay(lyr, lyr.gui.source.dataset, {crs: displayCRS});
|
|
11887
|
-
if (lyr.gui.style?.ids) {
|
|
11888
|
-
// re-apply layer filter
|
|
11889
|
-
lyr.gui.displayLayer = filterLayerByIds(lyr.gui.displayLayer, lyr.gui.style.ids);
|
|
11890
|
-
}
|
|
11891
|
-
}
|
|
11919
|
+
gui.on('shift_drag_start', function() {
|
|
11920
|
+
hideCoords();
|
|
11921
|
+
});
|
|
11892
11922
|
|
|
11923
|
+
box.on('dragend', function(e) {
|
|
11924
|
+
if (_on) popup.show();
|
|
11925
|
+
});
|
|
11893
11926
|
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11899
|
-
displayArcs: null,
|
|
11900
|
-
displayLayer: null,
|
|
11901
|
-
source: {dataset},
|
|
11902
|
-
bounds: null,
|
|
11903
|
-
style: null,
|
|
11904
|
-
dynamic_crs: null,
|
|
11905
|
-
invertPoint: null,
|
|
11906
|
-
projectPoint: null
|
|
11907
|
-
};
|
|
11927
|
+
box.on('handle_drag', function() {
|
|
11928
|
+
if (coords.visible()) {
|
|
11929
|
+
showCoords();
|
|
11930
|
+
}
|
|
11931
|
+
});
|
|
11908
11932
|
|
|
11909
|
-
|
|
11910
|
-
|
|
11911
|
-
|
|
11912
|
-
var displayArcs = dataset.gui?.displayArcs;
|
|
11913
|
-
var unprojectable = false;
|
|
11914
|
-
var sourceCRS;
|
|
11915
|
-
var emptyArcs;
|
|
11933
|
+
function inZoomMode() {
|
|
11934
|
+
return !_on && gui.getMode() != 'selection_tool';
|
|
11935
|
+
}
|
|
11916
11936
|
|
|
11917
|
-
|
|
11918
|
-
|
|
11919
|
-
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
sourceCRS = crsInfo.crs;
|
|
11937
|
+
function runCommand(cmd) {
|
|
11938
|
+
if (gui.console) {
|
|
11939
|
+
gui.console.runMapshaperCommands(cmd, function(err) {
|
|
11940
|
+
reset();
|
|
11941
|
+
gui.clearMode();
|
|
11942
|
+
});
|
|
11924
11943
|
}
|
|
11944
|
+
// reset(); // TODO: exit interactive mode
|
|
11945
|
+
}
|
|
11946
|
+
|
|
11947
|
+
function showCoords() {
|
|
11948
|
+
El(infoBtn.node()).addClass('selected-btn');
|
|
11949
|
+
coords.text(box.getDataCoords().join(','));
|
|
11950
|
+
coords.show();
|
|
11951
|
+
GUI.selectElement(coords.node());
|
|
11925
11952
|
}
|
|
11926
11953
|
|
|
11927
|
-
|
|
11928
|
-
|
|
11929
|
-
|
|
11930
|
-
|
|
11931
|
-
// project arcs, if needed
|
|
11932
|
-
if (needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
11933
|
-
displayArcs = projectArcsForDisplay(dataset.arcs, sourceCRS, displayCRS);
|
|
11934
|
-
} else {
|
|
11935
|
-
// Use original arcs for display if there is no dynamic reprojection
|
|
11936
|
-
displayArcs = dataset.arcs;
|
|
11937
|
-
}
|
|
11954
|
+
function hideCoords() {
|
|
11955
|
+
El(infoBtn.node()).removeClass('selected-btn');
|
|
11956
|
+
coords.hide();
|
|
11957
|
+
}
|
|
11938
11958
|
|
|
11939
|
-
|
|
11940
|
-
|
|
11959
|
+
function turnOn() {
|
|
11960
|
+
box.turnOn();
|
|
11961
|
+
_on = true;
|
|
11941
11962
|
}
|
|
11942
11963
|
|
|
11943
|
-
|
|
11944
|
-
|
|
11945
|
-
|
|
11946
|
-
|
|
11964
|
+
function turnOff() {
|
|
11965
|
+
box.turnOff();
|
|
11966
|
+
if (gui.interaction.getMode() == 'box') {
|
|
11967
|
+
// mode change was not initiated by interactive menu -- turn off interactivity
|
|
11968
|
+
gui.interaction.turnOff();
|
|
11969
|
+
}
|
|
11970
|
+
_on = false;
|
|
11971
|
+
reset();
|
|
11947
11972
|
}
|
|
11948
11973
|
|
|
11949
|
-
|
|
11950
|
-
|
|
11951
|
-
|
|
11952
|
-
|
|
11953
|
-
gui.displayLayer = layer;
|
|
11954
|
-
gui.displayArcs = displayArcs;
|
|
11955
|
-
} else {
|
|
11956
|
-
var table = getDisplayLayerForTable(layer.data);
|
|
11957
|
-
gui.tabular = true;
|
|
11958
|
-
gui.displayLayer = table.layer;
|
|
11959
|
-
gui.displayArcs = table.arcs;
|
|
11974
|
+
function reset() {
|
|
11975
|
+
box.hide();
|
|
11976
|
+
popup.hide();
|
|
11977
|
+
hideCoords();
|
|
11960
11978
|
}
|
|
11961
11979
|
|
|
11962
|
-
|
|
11963
|
-
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
11970
|
-
|
|
11971
|
-
|
|
11972
|
-
|
|
11973
|
-
|
|
11980
|
+
function openAddFramePopup(gui, bbox) {
|
|
11981
|
+
var popup = showPopupAlert('', 'Add a map frame');
|
|
11982
|
+
var el = popup.container();
|
|
11983
|
+
el.addClass('option-menu');
|
|
11984
|
+
var html = `<p>Enter a width in px, cm or inches to create a frame layer
|
|
11985
|
+
for setting the size of the map for symbol scaling in the
|
|
11986
|
+
GUI and setting the size and crop of SVG output.</p><div><input type="text" class="frame-width text-input" placeholder="examples: 600px 5in"></div>
|
|
11987
|
+
<div tabindex="0" class="btn dialog-btn">Create</div></span>`;
|
|
11988
|
+
el.html(html);
|
|
11989
|
+
var input = el.findChild('.frame-width');
|
|
11990
|
+
input.node().focus();
|
|
11991
|
+
var btn = el.findChild('.btn').on('click', function() {
|
|
11992
|
+
var widthStr = input.node().value.trim();
|
|
11993
|
+
if (parseFloat(widthStr) > 0 === false) {
|
|
11994
|
+
// invalid input
|
|
11995
|
+
input.node().value = '';
|
|
11996
|
+
return;
|
|
11974
11997
|
}
|
|
11975
|
-
|
|
11998
|
+
var cmd = `-rectangle + name=frame bbox='${bbox.join(',')}' width='${widthStr}'`;
|
|
11999
|
+
runCommand(cmd);
|
|
12000
|
+
popup.close();
|
|
12001
|
+
});
|
|
11976
12002
|
}
|
|
11977
12003
|
|
|
11978
|
-
|
|
11979
|
-
layer.gui = gui;
|
|
12004
|
+
return self;
|
|
11980
12005
|
}
|
|
11981
12006
|
|
|
12007
|
+
function RectangleControl(gui, hit) {
|
|
12008
|
+
var box = new HighlightBox(gui, {name: 'rectangle-tool', persistent: true, handles: true, classname: 'rectangles', draggable: false});
|
|
12009
|
+
var _on = false;
|
|
12010
|
+
var dragInfo;
|
|
11982
12011
|
|
|
11983
|
-
|
|
11984
|
-
|
|
11985
|
-
|
|
11986
|
-
|
|
11987
|
-
|
|
11988
|
-
|
|
12012
|
+
gui.addMode('rectangle_tool', turnOn, turnOff);
|
|
12013
|
+
|
|
12014
|
+
gui.on('interaction_mode_change', function(e) {
|
|
12015
|
+
if (e.mode === 'rectangles') {
|
|
12016
|
+
gui.enterMode('rectangle_tool');
|
|
12017
|
+
} else if (_on) {
|
|
12018
|
+
turnOff();
|
|
12019
|
+
}
|
|
12020
|
+
});
|
|
12021
|
+
|
|
12022
|
+
hit.on('change', function(e) {
|
|
12023
|
+
if (!_on) return;
|
|
12024
|
+
// TODO: handle multiple hits (see gui-inspection-control)
|
|
12025
|
+
var id = e.id;
|
|
12026
|
+
if (e.id > -1 && e.pinned) {
|
|
12027
|
+
var target = hit.getHitTarget();
|
|
12028
|
+
var path = target.shapes[e.id][0];
|
|
12029
|
+
var bbox = target.gui.displayArcs.getSimpleShapeBounds(path).toArray();
|
|
12030
|
+
box.setDataCoords(bbox);
|
|
12031
|
+
dragInfo = {
|
|
12032
|
+
id: e.id,
|
|
12033
|
+
target: target,
|
|
12034
|
+
ids: [],
|
|
12035
|
+
points: []
|
|
12036
|
+
};
|
|
12037
|
+
var iter = target.gui.displayArcs.getShapeIter(path);
|
|
12038
|
+
while (iter.hasNext()) {
|
|
12039
|
+
dragInfo.points.push([iter.x, iter.y]);
|
|
12040
|
+
dragInfo.ids.push(iter._arc.i);
|
|
12041
|
+
}
|
|
12042
|
+
gui.container.findChild('.map-layers').classed('dragging', true);
|
|
12043
|
+
|
|
12044
|
+
} else if (dragInfo) {
|
|
12045
|
+
gui.dispatchEvent('rectangle_dragend', dragInfo); // save undo state
|
|
12046
|
+
gui.container.findChild('.map-layers').classed('dragging', false);
|
|
12047
|
+
reset();
|
|
12048
|
+
} else {
|
|
12049
|
+
box.hide();
|
|
12050
|
+
}
|
|
12051
|
+
|
|
12052
|
+
});
|
|
12053
|
+
|
|
12054
|
+
box.on('handle_drag', function(e) {
|
|
12055
|
+
if (!_on || !dragInfo) return;
|
|
12056
|
+
var coords = internal.bboxToCoords(box.getDataCoords());
|
|
12057
|
+
setRectangleCoords(dragInfo.target, dragInfo.ids, coords);
|
|
12058
|
+
gui.dispatchEvent('map-needs-refresh');
|
|
12059
|
+
});
|
|
12060
|
+
|
|
12061
|
+
function turnOn() {
|
|
12062
|
+
box.turnOn();
|
|
12063
|
+
_on = true;
|
|
11989
12064
|
}
|
|
11990
|
-
return bounds;
|
|
11991
|
-
}
|
|
11992
12065
|
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
|
|
11996
|
-
|
|
11997
|
-
|
|
11998
|
-
if (nn[i] === 0) {
|
|
11999
|
-
ids.push(i);
|
|
12066
|
+
function turnOff() {
|
|
12067
|
+
box.turnOff();
|
|
12068
|
+
if (gui.interaction.getMode() == 'rectangles') {
|
|
12069
|
+
// mode change was not initiated by interactive menu -- turn off interactivity
|
|
12070
|
+
gui.interaction.turnOff();
|
|
12000
12071
|
}
|
|
12072
|
+
_on = false;
|
|
12073
|
+
reset();
|
|
12074
|
+
}
|
|
12075
|
+
|
|
12076
|
+
function reset() {
|
|
12077
|
+
box.hide();
|
|
12078
|
+
dragInfo = null;
|
|
12001
12079
|
}
|
|
12002
|
-
return ids;
|
|
12003
12080
|
}
|
|
12004
12081
|
|
|
12005
12082
|
function loadScript(url, cb) {
|
|
@@ -12052,15 +12129,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12052
12129
|
turnOff();
|
|
12053
12130
|
});
|
|
12054
12131
|
|
|
12055
|
-
// hideBtn.on('mousedown', function() {
|
|
12056
|
-
// if (activeStyle) {
|
|
12057
|
-
// mapEl.css('visibility', 'hidden');
|
|
12058
|
-
// hidden = true;
|
|
12059
|
-
// }
|
|
12060
|
-
// })
|
|
12061
12132
|
clearBtn.on('click', function() {
|
|
12062
12133
|
if (activeStyle) {
|
|
12063
|
-
|
|
12134
|
+
turnOffBasemap();
|
|
12064
12135
|
updateButtons();
|
|
12065
12136
|
}
|
|
12066
12137
|
});
|
|
@@ -12084,28 +12155,34 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12084
12155
|
params.styles.forEach(function(style) {
|
|
12085
12156
|
var btn = El('div').html(`<div class="basemap-style-btn"><img src="${style.icon}"></img></div><div class="basemap-style-label">${style.name}</div>`);
|
|
12086
12157
|
btn.findChild('.basemap-style-btn').on('click', function() {
|
|
12087
|
-
|
|
12158
|
+
if (style == activeStyle) {
|
|
12159
|
+
turnOffBasemap();
|
|
12160
|
+
} else {
|
|
12161
|
+
showBasemap(style);
|
|
12162
|
+
}
|
|
12088
12163
|
updateButtons();
|
|
12089
12164
|
});
|
|
12090
12165
|
btn.appendTo(list);
|
|
12091
12166
|
});
|
|
12092
12167
|
}
|
|
12093
12168
|
|
|
12094
|
-
function
|
|
12095
|
-
activeStyle =
|
|
12096
|
-
|
|
12169
|
+
function turnOffBasemap() {
|
|
12170
|
+
activeStyle = null;
|
|
12171
|
+
gui.map.setDisplayCRS(null);
|
|
12172
|
+
refresh();
|
|
12173
|
+
}
|
|
12174
|
+
|
|
12175
|
+
function showBasemap(style) {
|
|
12176
|
+
activeStyle = style;
|
|
12177
|
+
// TODO: consider enabling dark basemap mode
|
|
12097
12178
|
// Make sure that the selected layer style gets updated in gui-map.js
|
|
12098
12179
|
// gui.state.dark_basemap = style && style.dark || false;
|
|
12099
|
-
if (
|
|
12100
|
-
gui.map.setDisplayCRS(null);
|
|
12101
|
-
refresh();
|
|
12102
|
-
} else if (map) {
|
|
12180
|
+
if (map) {
|
|
12103
12181
|
map.setStyle(style.url);
|
|
12104
12182
|
refresh();
|
|
12105
|
-
} else {
|
|
12183
|
+
} else if (prepareMapView()) {
|
|
12106
12184
|
initMap();
|
|
12107
12185
|
}
|
|
12108
|
-
|
|
12109
12186
|
}
|
|
12110
12187
|
|
|
12111
12188
|
function updateButtons() {
|
|
@@ -12115,8 +12192,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12115
12192
|
}
|
|
12116
12193
|
|
|
12117
12194
|
function turnOn() {
|
|
12118
|
-
|
|
12119
|
-
var
|
|
12195
|
+
// TODO: show basemap even if there is no data
|
|
12196
|
+
var activeLyr = gui.model.getActiveLayer(); // may be null
|
|
12197
|
+
var info = getDatasetCrsInfo(activeLyr?.dataset); // defaults to wgs84
|
|
12120
12198
|
var dataCRS = info.crs || null;
|
|
12121
12199
|
var displayCRS = gui.map.getDisplayCRS();
|
|
12122
12200
|
var warning;
|
|
@@ -12159,9 +12237,9 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12159
12237
|
|
|
12160
12238
|
function getLonLatBounds() {
|
|
12161
12239
|
var bbox = ext.getBounds().toArray();
|
|
12162
|
-
var
|
|
12163
|
-
|
|
12164
|
-
return
|
|
12240
|
+
var bbox2 = fromWebMercator(bbox[0], bbox[1])
|
|
12241
|
+
.concat(fromWebMercator(bbox[2], bbox[3]));
|
|
12242
|
+
return bbox2;
|
|
12165
12243
|
}
|
|
12166
12244
|
|
|
12167
12245
|
function initMap() {
|
|
@@ -12219,6 +12297,15 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12219
12297
|
return true;
|
|
12220
12298
|
}
|
|
12221
12299
|
|
|
12300
|
+
function prepareMapView() {
|
|
12301
|
+
var crs = gui.map.getDisplayCRS();
|
|
12302
|
+
if (!crs) return false;
|
|
12303
|
+
if (!internal.isWebMercator(crs)) {
|
|
12304
|
+
gui.map.setDisplayCRS(internal.parseCrsString('webmercator'));
|
|
12305
|
+
}
|
|
12306
|
+
return true;
|
|
12307
|
+
}
|
|
12308
|
+
|
|
12222
12309
|
function refresh() {
|
|
12223
12310
|
var crs = gui.map.getDisplayCRS();
|
|
12224
12311
|
var off = !crs || !enabled() || !map || loading || !activeStyle;
|
|
@@ -12230,9 +12317,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12230
12317
|
return;
|
|
12231
12318
|
}
|
|
12232
12319
|
|
|
12233
|
-
|
|
12234
|
-
gui.map.setDisplayCRS(internal.parseCrsString('webmercator'));
|
|
12235
|
-
}
|
|
12320
|
+
prepareMapView();
|
|
12236
12321
|
var bbox = getLonLatBounds();
|
|
12237
12322
|
if (!checkBounds(bbox)) {
|
|
12238
12323
|
// map does not display outside these bounds
|
|
@@ -12331,8 +12416,15 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12331
12416
|
};
|
|
12332
12417
|
|
|
12333
12418
|
this.getDisplayCRS = function() {
|
|
12334
|
-
if (!_activeLyr
|
|
12335
|
-
|
|
12419
|
+
if (!_activeLyr) {
|
|
12420
|
+
return _dynamicCRS || internal.parseCrsString('wgs84');
|
|
12421
|
+
}
|
|
12422
|
+
if (!_activeLyr.gui.geographic) {
|
|
12423
|
+
return null;
|
|
12424
|
+
}
|
|
12425
|
+
if (_activeLyr.gui.dynamic_crs) {
|
|
12426
|
+
return _activeLyr.gui.dynamic_crs;
|
|
12427
|
+
}
|
|
12336
12428
|
var info = getDatasetCrsInfo(_activeLyr.gui.source.dataset);
|
|
12337
12429
|
return info.crs || null;
|
|
12338
12430
|
};
|
|
@@ -12365,7 +12457,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12365
12457
|
var newCRS = utils$1.isString(crs) ? internal.parseCrsString(crs) : crs;
|
|
12366
12458
|
// TODO: handle case that old and new CRS are the same
|
|
12367
12459
|
_dynamicCRS = newCRS;
|
|
12368
|
-
if (!_activeLyr) return; // stop here if no layers have been selected
|
|
12460
|
+
// if (!_activeLyr) return; // stop here if no layers have been selected
|
|
12369
12461
|
|
|
12370
12462
|
// clear any stored FilteredArcs objects (so they will be recreated with the desired projection)
|
|
12371
12463
|
clearAllDisplayArcs();
|
|
@@ -12383,6 +12475,34 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12383
12475
|
updateFullBounds();
|
|
12384
12476
|
};
|
|
12385
12477
|
|
|
12478
|
+
// Initialization just before displaying the map for the first time
|
|
12479
|
+
this.init = function() {
|
|
12480
|
+
if (_renderer) return;
|
|
12481
|
+
_ext.setFullBounds(calcFullBounds());
|
|
12482
|
+
_ext.resize();
|
|
12483
|
+
_renderer = new LayerRenderer(gui, el);
|
|
12484
|
+
gui.buttons.show();
|
|
12485
|
+
|
|
12486
|
+
if (opts.inspectorControl) {
|
|
12487
|
+
_hit = new HitControl(gui, _ext, _mouse),
|
|
12488
|
+
new InspectionControl2(gui, _hit);
|
|
12489
|
+
new SelectionTool(gui, _ext, _hit),
|
|
12490
|
+
new BoxTool(gui, _ext, _nav),
|
|
12491
|
+
new RectangleControl(gui, _hit),
|
|
12492
|
+
initInteractiveEditing(gui, _ext, _hit);
|
|
12493
|
+
_hit.on('change', updateOverlayLayer);
|
|
12494
|
+
}
|
|
12495
|
+
|
|
12496
|
+
_ext.on('change', function(e) {
|
|
12497
|
+
if (_basemap) _basemap.refresh(); // keep basemap synced up (if enabled)
|
|
12498
|
+
drawLayers(e.redraw ? '' : 'nav');
|
|
12499
|
+
});
|
|
12500
|
+
|
|
12501
|
+
gui.on('resize', function() {
|
|
12502
|
+
position.update(); // kludge to detect new map size after console toggle
|
|
12503
|
+
});
|
|
12504
|
+
};
|
|
12505
|
+
|
|
12386
12506
|
function getGlobalStyleOptions(opts) {
|
|
12387
12507
|
var mode = gui.state.interaction_mode;
|
|
12388
12508
|
return Object.assign({
|
|
@@ -12398,7 +12518,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12398
12518
|
var fullBounds;
|
|
12399
12519
|
var needReset;
|
|
12400
12520
|
if (!prevLyr) {
|
|
12401
|
-
initMap(); // first call
|
|
12521
|
+
// initMap(); // first call
|
|
12402
12522
|
}
|
|
12403
12523
|
|
|
12404
12524
|
if (arcsMayHaveChanged(e.flags)) {
|
|
@@ -12422,10 +12542,14 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12422
12542
|
return;
|
|
12423
12543
|
}
|
|
12424
12544
|
|
|
12425
|
-
|
|
12426
|
-
|
|
12427
|
-
|
|
12428
|
-
|
|
12545
|
+
if (e.layer) {
|
|
12546
|
+
enhanceLayerForDisplay(e.layer, e.dataset, getDisplayOptions());
|
|
12547
|
+
_activeLyr = e.layer;
|
|
12548
|
+
_activeLyr.gui.style = getActiveLayerStyle(_activeLyr.gui.displayLayer, getGlobalStyleOptions());
|
|
12549
|
+
_activeLyr.active = true;
|
|
12550
|
+
} else {
|
|
12551
|
+
_activeLyr = null;
|
|
12552
|
+
}
|
|
12429
12553
|
|
|
12430
12554
|
if (popupCanStayOpen(e.flags)) {
|
|
12431
12555
|
// data may have changed; if popup is open, it needs to be refreshed
|
|
@@ -12438,7 +12562,11 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12438
12562
|
updateVisibleMapLayers();
|
|
12439
12563
|
fullBounds = calcFullBounds();
|
|
12440
12564
|
|
|
12441
|
-
if (
|
|
12565
|
+
if (prevLyr?.gui.tabular || _activeLyr?.gui.tabular) {
|
|
12566
|
+
needReset = true;
|
|
12567
|
+
} else if (_activeLyr && internal.layerIsEmpty(_activeLyr)) {
|
|
12568
|
+
needReset = false;
|
|
12569
|
+
} else if (!prevLyr) {
|
|
12442
12570
|
needReset = true;
|
|
12443
12571
|
} else {
|
|
12444
12572
|
needReset = mapNeedsReset(fullBounds, _ext.getFullBounds(), _ext.getBounds(), e.flags);
|
|
@@ -12448,37 +12576,12 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12448
12576
|
|
|
12449
12577
|
if (needReset) {
|
|
12450
12578
|
_ext.reset();
|
|
12579
|
+
if (_basemap) _basemap.refresh();
|
|
12451
12580
|
}
|
|
12452
12581
|
drawLayers();
|
|
12453
12582
|
map.dispatchEvent('updated');
|
|
12454
12583
|
}
|
|
12455
12584
|
|
|
12456
|
-
// Initialization just before displaying the map for the first time
|
|
12457
|
-
function initMap() {
|
|
12458
|
-
_ext.resize();
|
|
12459
|
-
_renderer = new LayerRenderer(gui, el, _ext, _mouse);
|
|
12460
|
-
gui.buttons.show();
|
|
12461
|
-
|
|
12462
|
-
if (opts.inspectorControl) {
|
|
12463
|
-
_hit = new HitControl(gui, _ext, _mouse),
|
|
12464
|
-
new InspectionControl2(gui, _hit);
|
|
12465
|
-
new SelectionTool(gui, _ext, _hit),
|
|
12466
|
-
new BoxTool(gui, _ext, _nav),
|
|
12467
|
-
new RectangleControl(gui, _hit),
|
|
12468
|
-
initInteractiveEditing(gui, _ext, _hit);
|
|
12469
|
-
_hit.on('change', updateOverlayLayer);
|
|
12470
|
-
}
|
|
12471
|
-
|
|
12472
|
-
_ext.on('change', function(e) {
|
|
12473
|
-
if (_basemap) _basemap.refresh(); // keep basemap synced up (if enabled)
|
|
12474
|
-
if (e.reset) return; // don't need to redraw map here if extent has been reset
|
|
12475
|
-
drawLayers('nav');
|
|
12476
|
-
});
|
|
12477
|
-
|
|
12478
|
-
gui.on('resize', function() {
|
|
12479
|
-
position.update(); // kludge to detect new map size after console toggle
|
|
12480
|
-
});
|
|
12481
|
-
}
|
|
12482
12585
|
|
|
12483
12586
|
function updateOverlayLayer(e) {
|
|
12484
12587
|
var style = getOverlayStyle(_activeLyr.gui.displayLayer, e, getGlobalStyleOptions());
|
|
@@ -12521,7 +12624,8 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12521
12624
|
|
|
12522
12625
|
if (!b.hasBounds()) {
|
|
12523
12626
|
// assign bounds to empty layers, to prevent rendering errors downstream
|
|
12524
|
-
b.setBounds(0,0,0,0);
|
|
12627
|
+
// b.setBounds(0,0,0,0);
|
|
12628
|
+
b.setBounds(projectLatLonBBox([11.28,33.43,32.26,46.04], _dynamicCRS));
|
|
12525
12629
|
}
|
|
12526
12630
|
return b;
|
|
12527
12631
|
}
|
|
@@ -12546,7 +12650,6 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12546
12650
|
|
|
12547
12651
|
// Inflate display bounding box by a tiny amount (gives extent to single-point layers and collapsed shapes)
|
|
12548
12652
|
b.padBounds(1e-4, 1e-4, 1e-4, 1e-4);
|
|
12549
|
-
|
|
12550
12653
|
return b;
|
|
12551
12654
|
}
|
|
12552
12655
|
|
|
@@ -12559,7 +12662,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12559
12662
|
}
|
|
12560
12663
|
|
|
12561
12664
|
function isTableView() {
|
|
12562
|
-
return !!_activeLyr
|
|
12665
|
+
return !!_activeLyr?.gui.tabular;
|
|
12563
12666
|
}
|
|
12564
12667
|
|
|
12565
12668
|
function findFrameLayer() {
|
|
@@ -12769,12 +12872,13 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12769
12872
|
El('div')
|
|
12770
12873
|
.appendTo(menu)
|
|
12771
12874
|
.addClass('contextmenu-item')
|
|
12772
|
-
.
|
|
12875
|
+
.html(label)
|
|
12773
12876
|
.on('click', func)
|
|
12774
12877
|
.show();
|
|
12775
12878
|
}
|
|
12776
12879
|
|
|
12777
12880
|
this.open = function(e, lyr) {
|
|
12881
|
+
if (!lyr || !lyr.gui.geographic) return;
|
|
12778
12882
|
_open = true;
|
|
12779
12883
|
_openCount++;
|
|
12780
12884
|
var rspace = body.clientWidth - e.pageX;
|
|
@@ -12782,27 +12886,29 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12782
12886
|
menu.empty().show();
|
|
12783
12887
|
if (rspace > 150) {
|
|
12784
12888
|
menu.css('left', e.pageX + xoffs + 'px');
|
|
12889
|
+
menu.css('right', null);
|
|
12785
12890
|
} else {
|
|
12786
12891
|
menu.css('right', (body.clientWidth - e.pageX + xoffs) + 'px');
|
|
12892
|
+
menu.css('left', null);
|
|
12787
12893
|
}
|
|
12788
12894
|
menu.css('top', (e.pageY - 15) + 'px');
|
|
12789
12895
|
|
|
12790
12896
|
// menu contents
|
|
12791
|
-
if (e.deleteVertex) {
|
|
12792
|
-
addMenuItem('Delete vertex', e.deleteVertex);
|
|
12793
|
-
}
|
|
12794
12897
|
if (e.coordinates) {
|
|
12795
12898
|
addCopyCoords();
|
|
12796
12899
|
}
|
|
12900
|
+
if (e.deleteVertex) {
|
|
12901
|
+
addMenuItem('Delete vertex', e.deleteVertex);
|
|
12902
|
+
}
|
|
12797
12903
|
if (e.ids?.length) {
|
|
12798
12904
|
addMenuItem('Copy as GeoJSON', copyGeoJSON);
|
|
12799
12905
|
}
|
|
12800
12906
|
|
|
12801
12907
|
function addCopyCoords() {
|
|
12802
12908
|
var bbox = internal.getLayerBounds(lyr, lyr.gui.source.dataset.arcs).toArray();
|
|
12803
|
-
var
|
|
12804
|
-
var
|
|
12805
|
-
addMenuItem(
|
|
12909
|
+
var coordStr = internal.getRoundedCoordString(e.coordinates, internal.getBoundsPrecisionForDisplay(bbox));
|
|
12910
|
+
var displayStr = '• ' + coordStr.replace(/-/g, '–').replace(',', ', ');
|
|
12911
|
+
addMenuItem(displayStr, function() {
|
|
12806
12912
|
saveFileContentToClipboard(coordStr);
|
|
12807
12913
|
});
|
|
12808
12914
|
}
|
|
@@ -12868,6 +12974,7 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12868
12974
|
var clearMsg;
|
|
12869
12975
|
|
|
12870
12976
|
initModeRules(gui);
|
|
12977
|
+
gui.map.init();
|
|
12871
12978
|
|
|
12872
12979
|
gui.showProgressMessage = function(msg) {
|
|
12873
12980
|
if (!gui.progressMessage) {
|
|
@@ -12980,9 +13087,10 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
12980
13087
|
importOpts = getImportOpts(manifest),
|
|
12981
13088
|
gui = new GuiInstance('body');
|
|
12982
13089
|
|
|
12983
|
-
|
|
12984
|
-
|
|
12985
|
-
|
|
13090
|
+
// TODO: re-enable the "blurb"
|
|
13091
|
+
// if (manifest.blurb) {
|
|
13092
|
+
// El('#splash-screen-blurb').text(manifest.blurb);
|
|
13093
|
+
// }
|
|
12986
13094
|
|
|
12987
13095
|
new AlertControl(gui);
|
|
12988
13096
|
new RepairControl(gui);
|
|
@@ -13013,17 +13121,19 @@ GUI and setting the size and crop of SVG output.</p><div><input type="text" clas
|
|
|
13013
13121
|
});
|
|
13014
13122
|
|
|
13015
13123
|
// Initial display configuration
|
|
13016
|
-
gui.
|
|
13124
|
+
gui.on('mode', function(e) {
|
|
13017
13125
|
if (dataLoaded) return;
|
|
13018
13126
|
dataLoaded = true;
|
|
13127
|
+
gui.buttons.show();
|
|
13019
13128
|
El('#mode-buttons').show();
|
|
13129
|
+
El('#splash-buttons').hide();
|
|
13130
|
+
El('body').addClass('map-view');
|
|
13020
13131
|
if (importOpts.display_all) {
|
|
13021
13132
|
gui.model.getLayers().forEach(function(o) {
|
|
13022
13133
|
gui.map.setLayerPinning(o, true);
|
|
13023
13134
|
});
|
|
13024
13135
|
}
|
|
13025
13136
|
gui.console.runInitialCommands(getInitialConsoleCommands());
|
|
13026
|
-
|
|
13027
13137
|
});
|
|
13028
13138
|
};
|
|
13029
13139
|
|