mapshaper 0.5.96 → 0.5.99
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/CHANGELOG.md +9 -0
- package/mapshaper.js +180 -71
- package/package.json +2 -1
- package/www/images/thumb-map.jpg +0 -0
- package/www/images/thumb-satellite.jpg +0 -0
- package/www/index.html +15 -1
- package/www/mapshaper-gui.js +707 -388
- package/www/mapshaper.js +180 -71
- package/www/page.css +89 -4
package/www/mapshaper-gui.js
CHANGED
|
@@ -1736,6 +1736,451 @@
|
|
|
1736
1736
|
|
|
1737
1737
|
utils$1.inherit(Slider, EventDispatcher);
|
|
1738
1738
|
|
|
1739
|
+
// Create low-detail versions of large arc collections for faster rendering
|
|
1740
|
+
// at zoomed-out scales.
|
|
1741
|
+
function enhanceArcCollectionForDisplay(unfilteredArcs) {
|
|
1742
|
+
var size = unfilteredArcs.getPointCount(),
|
|
1743
|
+
filteredArcs, filteredSegLen;
|
|
1744
|
+
|
|
1745
|
+
// Only generate low-detail arcs for larger datasets
|
|
1746
|
+
if (size > 5e5) {
|
|
1747
|
+
if (!!unfilteredArcs.getVertexData().zz) {
|
|
1748
|
+
// Use precalculated simplification data for vertex filtering, if available
|
|
1749
|
+
filteredArcs = initFilteredArcs(unfilteredArcs);
|
|
1750
|
+
filteredSegLen = internal.getAvgSegment(filteredArcs);
|
|
1751
|
+
} else {
|
|
1752
|
+
// Use fast simplification as a fallback
|
|
1753
|
+
filteredSegLen = internal.getAvgSegment(unfilteredArcs) * 4;
|
|
1754
|
+
filteredArcs = internal.simplifyArcsFast(unfilteredArcs, filteredSegLen);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
|
|
1758
|
+
function initFilteredArcs(arcs) {
|
|
1759
|
+
var filterPct = 0.08;
|
|
1760
|
+
var nth = Math.ceil(arcs.getPointCount() / 5e5);
|
|
1761
|
+
var currInterval = arcs.getRetainedInterval();
|
|
1762
|
+
var filterZ = arcs.getThresholdByPct(filterPct, nth);
|
|
1763
|
+
var filteredArcs = arcs.setRetainedInterval(filterZ).getFilteredCopy();
|
|
1764
|
+
arcs.setRetainedInterval(currInterval); // reset current simplification
|
|
1765
|
+
return filteredArcs;
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
unfilteredArcs.getScaledArcs = function(ext) {
|
|
1769
|
+
if (filteredArcs) {
|
|
1770
|
+
// match simplification of unfiltered arcs
|
|
1771
|
+
filteredArcs.setRetainedInterval(unfilteredArcs.getRetainedInterval());
|
|
1772
|
+
}
|
|
1773
|
+
// switch to filtered version of arcs at small scales
|
|
1774
|
+
var unitsPerPixel = 1/ext.getTransform().mx,
|
|
1775
|
+
useFiltering = filteredArcs && unitsPerPixel > filteredSegLen * 1.5;
|
|
1776
|
+
return useFiltering ? filteredArcs : unfilteredArcs;
|
|
1777
|
+
};
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
function getDisplayLayerForTable(table) {
|
|
1781
|
+
var n = table.size(),
|
|
1782
|
+
cellWidth = 12,
|
|
1783
|
+
cellHeight = 5,
|
|
1784
|
+
gutter = 6,
|
|
1785
|
+
arcs = [],
|
|
1786
|
+
shapes = [],
|
|
1787
|
+
aspectRatio = 1.1,
|
|
1788
|
+
x, y, col, row, blockSize;
|
|
1789
|
+
|
|
1790
|
+
if (n > 10000) {
|
|
1791
|
+
arcs = null;
|
|
1792
|
+
gutter = 0;
|
|
1793
|
+
cellWidth = 4;
|
|
1794
|
+
cellHeight = 4;
|
|
1795
|
+
aspectRatio = 1.45;
|
|
1796
|
+
} else if (n > 5000) {
|
|
1797
|
+
cellWidth = 5;
|
|
1798
|
+
gutter = 3;
|
|
1799
|
+
aspectRatio = 1.45;
|
|
1800
|
+
} else if (n > 1000) {
|
|
1801
|
+
gutter = 3;
|
|
1802
|
+
cellWidth = 8;
|
|
1803
|
+
aspectRatio = 1.3;
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
if (n < 25) {
|
|
1807
|
+
blockSize = n;
|
|
1808
|
+
} else {
|
|
1809
|
+
blockSize = Math.sqrt(n * (cellWidth + gutter) / cellHeight / aspectRatio) | 0;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
for (var i=0; i<n; i++) {
|
|
1813
|
+
row = i % blockSize;
|
|
1814
|
+
col = Math.floor(i / blockSize);
|
|
1815
|
+
x = col * (cellWidth + gutter);
|
|
1816
|
+
y = cellHeight * (blockSize - row);
|
|
1817
|
+
if (arcs) {
|
|
1818
|
+
arcs.push(getArc(x, y, cellWidth, cellHeight));
|
|
1819
|
+
shapes.push([[i]]);
|
|
1820
|
+
} else {
|
|
1821
|
+
shapes.push([[x, y]]);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
function getArc(x, y, w, h) {
|
|
1826
|
+
return [[x, y], [x + w, y], [x + w, y - h], [x, y - h], [x, y]];
|
|
1827
|
+
}
|
|
1828
|
+
|
|
1829
|
+
return {
|
|
1830
|
+
layer: {
|
|
1831
|
+
geometry_type: arcs ? 'polygon' : 'point',
|
|
1832
|
+
shapes: shapes,
|
|
1833
|
+
data: table
|
|
1834
|
+
},
|
|
1835
|
+
arcs: arcs ? new internal.ArcCollection(arcs) : null
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
|
|
1839
|
+
// Assumes projections are available
|
|
1840
|
+
|
|
1841
|
+
function needReprojectionForDisplay(sourceCRS, displayCRS) {
|
|
1842
|
+
if (!sourceCRS || !displayCRS) {
|
|
1843
|
+
return false;
|
|
1844
|
+
}
|
|
1845
|
+
if (internal.crsAreEqual(sourceCRS, displayCRS)) {
|
|
1846
|
+
return false;
|
|
1847
|
+
}
|
|
1848
|
+
return true;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
function projectArcsForDisplay(arcs, src, dest) {
|
|
1852
|
+
var copy = arcs.getCopy(); // need to flatten first?
|
|
1853
|
+
var proj = internal.getProjTransform2(src, dest);
|
|
1854
|
+
// TODO: think about densification
|
|
1855
|
+
try {
|
|
1856
|
+
// fast and preserves Z values, but throws on first unprojectable point
|
|
1857
|
+
internal.projectArcs(copy, proj);
|
|
1858
|
+
} catch(e) {
|
|
1859
|
+
console.error(e);
|
|
1860
|
+
internal.projectArcs2(copy, proj);
|
|
1861
|
+
}
|
|
1862
|
+
return copy;
|
|
1863
|
+
}
|
|
1864
|
+
|
|
1865
|
+
function projectPointsForDisplay(lyr, src, dest) {
|
|
1866
|
+
var copy = utils$1.extend({}, lyr);
|
|
1867
|
+
var proj = internal.getProjTransform2(src, dest);
|
|
1868
|
+
copy.shapes = internal.cloneShapes(lyr.shapes);
|
|
1869
|
+
internal.projectPointLayer(copy, proj);
|
|
1870
|
+
return copy;
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
|
|
1874
|
+
// Update map extent and trigger redraw, after a new display CRS has been applied
|
|
1875
|
+
function projectMapExtent(ext, src, dest, newBounds) {
|
|
1876
|
+
var oldBounds = ext.getBounds();
|
|
1877
|
+
var oldScale = ext.scale();
|
|
1878
|
+
var newCP, proj;
|
|
1879
|
+
|
|
1880
|
+
// if source or destination CRS is unknown, show full extent
|
|
1881
|
+
// if map is at full extent, show full extent
|
|
1882
|
+
// TODO: handle case that scale is 1 and map is panned away from center
|
|
1883
|
+
if (ext.scale() == 1 || !dest) {
|
|
1884
|
+
ext.setBounds(newBounds);
|
|
1885
|
+
ext.home(); // sets full extent and triggers redraw
|
|
1886
|
+
} else {
|
|
1887
|
+
// if map is zoomed, stay centered on the same geographic location, at the same relative scale
|
|
1888
|
+
proj = internal.getProjTransform2(src, dest);
|
|
1889
|
+
newCP = proj(oldBounds.centerX(), oldBounds.centerY());
|
|
1890
|
+
ext.setBounds(newBounds);
|
|
1891
|
+
if (!newCP) {
|
|
1892
|
+
// projection of center point failed; use center of bounds
|
|
1893
|
+
// (also consider just resetting the view using ext.home())
|
|
1894
|
+
newCP = [newBounds.centerX(), newBounds.centerY()];
|
|
1895
|
+
}
|
|
1896
|
+
ext.recenter(newCP[0], newCP[1], oldScale);
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
// Called from console; for testing dynamic crs
|
|
1901
|
+
function setDisplayProjection(gui, cmd) {
|
|
1902
|
+
var arg = cmd.replace(/^projd[ ]*/, '');
|
|
1903
|
+
if (arg) {
|
|
1904
|
+
gui.map.setDisplayCRS(internal.getCRS(arg));
|
|
1905
|
+
} else {
|
|
1906
|
+
gui.map.setDisplayCRS(null);
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
function filterLayerByIds(lyr, ids) {
|
|
1911
|
+
var shapes;
|
|
1912
|
+
if (lyr.shapes) {
|
|
1913
|
+
shapes = ids.map(function(id) {
|
|
1914
|
+
return lyr.shapes[id];
|
|
1915
|
+
});
|
|
1916
|
+
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
1917
|
+
}
|
|
1918
|
+
return lyr;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
function formatLayerNameForDisplay(name) {
|
|
1922
|
+
return name || '[unnamed]';
|
|
1923
|
+
}
|
|
1924
|
+
|
|
1925
|
+
function cleanLayerName(raw) {
|
|
1926
|
+
return raw.replace(/[\n\t/\\]/g, '')
|
|
1927
|
+
.replace(/^[\.\s]+/, '').replace(/[\.\s]+$/, '');
|
|
1928
|
+
}
|
|
1929
|
+
|
|
1930
|
+
function updateLayerStackOrder(layers) {
|
|
1931
|
+
// 1. assign ascending ids to unassigned layers above the range of other layers
|
|
1932
|
+
layers.forEach(function(o, i) {
|
|
1933
|
+
if (!o.layer.stack_id) o.layer.stack_id = 1e6 + i;
|
|
1934
|
+
});
|
|
1935
|
+
// 2. sort in ascending order
|
|
1936
|
+
layers.sort(function(a, b) {
|
|
1937
|
+
return a.layer.stack_id - b.layer.stack_id;
|
|
1938
|
+
});
|
|
1939
|
+
// 3. assign consecutve ids
|
|
1940
|
+
layers.forEach(function(o, i) {
|
|
1941
|
+
o.layer.stack_id = i + 1;
|
|
1942
|
+
});
|
|
1943
|
+
return layers;
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
function sortLayersForMenuDisplay(layers) {
|
|
1947
|
+
layers = updateLayerStackOrder(layers);
|
|
1948
|
+
return layers.reverse();
|
|
1949
|
+
}
|
|
1950
|
+
|
|
1951
|
+
function setZ(lyr, z) {
|
|
1952
|
+
lyr.source.dataset.arcs.setRetainedInterval(z);
|
|
1953
|
+
if (isProjectedLayer(lyr)) {
|
|
1954
|
+
lyr.arcs.setRetainedInterval(z);
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
function updateZ(lyr) {
|
|
1959
|
+
if (isProjectedLayer(lyr) && !lyr.source.dataset.arcs.isFlat()) {
|
|
1960
|
+
lyr.arcs.setThresholds(lyr.source.dataset.arcs.getVertexData().zz);
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
|
|
1964
|
+
function insertVertex$1(lyr, id, dataPoint) {
|
|
1965
|
+
internal.insertVertex(lyr.source.dataset.arcs, id, dataPoint);
|
|
1966
|
+
if (isProjectedLayer(lyr)) {
|
|
1967
|
+
internal.insertVertex(lyr.arcs, id, lyr.projectPoint(dataPoint[0], dataPoint[1]));
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
function deleteVertex$1(lyr, id) {
|
|
1972
|
+
internal.deleteVertex(lyr.arcs, id);
|
|
1973
|
+
if (isProjectedLayer(lyr)) {
|
|
1974
|
+
internal.deleteVertex(lyr.source.dataset.arcs, id);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
function translateDisplayPoint(lyr, p) {
|
|
1979
|
+
return isProjectedLayer(lyr) ? lyr.invertPoint(p[0], p[1]) : p;
|
|
1980
|
+
}
|
|
1981
|
+
|
|
1982
|
+
function getPointCoords(lyr, fid) {
|
|
1983
|
+
return internal.cloneShape(lyr.source.layer.shapes[fid]);
|
|
1984
|
+
}
|
|
1985
|
+
|
|
1986
|
+
// bbox: display coords
|
|
1987
|
+
// intended to work with rectangular projections like Mercator
|
|
1988
|
+
function getBBoxCoords(lyr, bbox) {
|
|
1989
|
+
if (!isProjectedLayer(lyr)) return bbox;
|
|
1990
|
+
var a = translateDisplayPoint(lyr, [bbox[0], bbox[1]]);
|
|
1991
|
+
var b = translateDisplayPoint(lyr, [bbox[2], bbox[3]]);
|
|
1992
|
+
var bounds = new internal.Bounds();
|
|
1993
|
+
bounds.mergePoint(a[0], a[1]);
|
|
1994
|
+
bounds.mergePoint(b[0], b[1]);
|
|
1995
|
+
return bounds.toArray();
|
|
1996
|
+
}
|
|
1997
|
+
|
|
1998
|
+
function getVertexCoords(lyr, id) {
|
|
1999
|
+
return lyr.source.dataset.arcs.getVertex2(id);
|
|
2000
|
+
}
|
|
2001
|
+
|
|
2002
|
+
function setVertexCoords(lyr, ids, dataPoint) {
|
|
2003
|
+
internal.snapVerticesToPoint(ids, dataPoint, lyr.source.dataset.arcs, true);
|
|
2004
|
+
if (isProjectedLayer(lyr)) {
|
|
2005
|
+
var p = lyr.projectPoint(dataPoint[0], dataPoint[1]);
|
|
2006
|
+
internal.snapVerticesToPoint(ids, p, lyr.arcs, true);
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
function setPointCoords(lyr, fid, coords) {
|
|
2011
|
+
lyr.source.layer.shapes[fid] = coords;
|
|
2012
|
+
if (isProjectedLayer(lyr)) {
|
|
2013
|
+
lyr.layer.shapes[fid] = projectPointCoords(coords, lyr.projectPoint);
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
function updateVertexCoords(lyr, ids) {
|
|
2018
|
+
if (!isProjectedLayer(lyr)) return;
|
|
2019
|
+
var p = lyr.arcs.getVertex2(ids[0]);
|
|
2020
|
+
internal.snapVerticesToPoint(ids, lyr.invertPoint(p[0], p[1]), lyr.source.dataset.arcs, true);
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
function isProjectedLayer(lyr) {
|
|
2024
|
+
// TODO: could do some validation on the layer's contents
|
|
2025
|
+
return !!(lyr.source && lyr.invertPoint);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
// Update data coordinates by projecting display coordinates
|
|
2029
|
+
function updatePointCoords(lyr, fid) {
|
|
2030
|
+
if (!isProjectedLayer(lyr)) return;
|
|
2031
|
+
var displayShp = lyr.layer.shapes[fid];
|
|
2032
|
+
lyr.source.layer.shapes[fid] = projectPointCoords(displayShp, lyr.invertPoint);
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
function projectPointCoords(src, proj) {
|
|
2036
|
+
var dest = [], p;
|
|
2037
|
+
for (var i=0; i<src.length; i++) {
|
|
2038
|
+
p = proj(src[i][0], src[i][1]);
|
|
2039
|
+
if (p) dest.push(p);
|
|
2040
|
+
}
|
|
2041
|
+
return dest.length ? dest : null;
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
// displayCRS: CRS to use for display, or null (which clears any current display CRS)
|
|
2045
|
+
function projectDisplayLayer(lyr, displayCRS) {
|
|
2046
|
+
var sourceCRS = internal.getDatasetCRS(lyr.source.dataset);
|
|
2047
|
+
var lyr2;
|
|
2048
|
+
if (!lyr.geographic || !sourceCRS) {
|
|
2049
|
+
return lyr;
|
|
2050
|
+
}
|
|
2051
|
+
if (lyr.dynamic_crs && internal.crsAreEqual(sourceCRS, lyr.dynamic_crs)) {
|
|
2052
|
+
return lyr;
|
|
2053
|
+
}
|
|
2054
|
+
lyr2 = getDisplayLayer(lyr.source.layer, lyr.source.dataset, {crs: displayCRS});
|
|
2055
|
+
// kludge: copy projection-related properties to original layer
|
|
2056
|
+
lyr.dynamic_crs = lyr2.dynamic_crs;
|
|
2057
|
+
lyr.layer = lyr2.layer;
|
|
2058
|
+
if (lyr.style && lyr.style.ids) {
|
|
2059
|
+
// re-apply layer filter
|
|
2060
|
+
lyr.layer = filterLayerByIds(lyr.layer, lyr.style.ids);
|
|
2061
|
+
}
|
|
2062
|
+
lyr.invertPoint = lyr2.invertPoint;
|
|
2063
|
+
lyr.projectPoint = lyr2.projectPoint;
|
|
2064
|
+
lyr.bounds = lyr2.bounds;
|
|
2065
|
+
lyr.arcs = lyr2.arcs;
|
|
2066
|
+
}
|
|
2067
|
+
|
|
2068
|
+
|
|
2069
|
+
// Wrap a layer in an object along with information needed for rendering
|
|
2070
|
+
function getDisplayLayer(layer, dataset, opts) {
|
|
2071
|
+
var obj = {
|
|
2072
|
+
layer: null,
|
|
2073
|
+
arcs: null,
|
|
2074
|
+
// display_arcs: null,
|
|
2075
|
+
style: null,
|
|
2076
|
+
invertPoint: null,
|
|
2077
|
+
projectPoint: null,
|
|
2078
|
+
source: {
|
|
2079
|
+
layer: layer,
|
|
2080
|
+
dataset: dataset
|
|
2081
|
+
},
|
|
2082
|
+
empty: internal.getFeatureCount(layer) === 0
|
|
2083
|
+
};
|
|
2084
|
+
|
|
2085
|
+
var sourceCRS = opts.crs && internal.getDatasetCRS(dataset); // get src iff display CRS is given
|
|
2086
|
+
var displayCRS = opts.crs || null;
|
|
2087
|
+
// display arcs may have been generated when another layer in the dataset was converted for display... re-use if available
|
|
2088
|
+
var displayArcs = dataset.displayArcs || null;
|
|
2089
|
+
var emptyArcs;
|
|
2090
|
+
|
|
2091
|
+
// Assume that dataset.displayArcs is in the display CRS
|
|
2092
|
+
// (it must be deleted upstream if reprojection is needed)
|
|
2093
|
+
if (dataset.arcs && !displayArcs) {
|
|
2094
|
+
// project arcs, if needed
|
|
2095
|
+
if (needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
2096
|
+
displayArcs = projectArcsForDisplay(dataset.arcs, sourceCRS, displayCRS);
|
|
2097
|
+
} else {
|
|
2098
|
+
// Use original arcs for display if there is no dynamic reprojection
|
|
2099
|
+
displayArcs = dataset.arcs;
|
|
2100
|
+
}
|
|
2101
|
+
|
|
2102
|
+
enhanceArcCollectionForDisplay(displayArcs);
|
|
2103
|
+
dataset.displayArcs = displayArcs; // stash these in the dataset for other layers to use
|
|
2104
|
+
}
|
|
2105
|
+
|
|
2106
|
+
if (internal.layerHasFurniture(layer)) {
|
|
2107
|
+
obj.furniture = true;
|
|
2108
|
+
obj.furniture_type = internal.getFurnitureLayerType(layer);
|
|
2109
|
+
obj.layer = layer;
|
|
2110
|
+
// treating furniture layers (other than frame) as tabular for now,
|
|
2111
|
+
// so there is something to show if they are selected
|
|
2112
|
+
obj.tabular = obj.furniture_type != 'frame';
|
|
2113
|
+
} else if (obj.empty) {
|
|
2114
|
+
obj.layer = {shapes: []}; // ideally we should avoid empty layers
|
|
2115
|
+
} else if (!layer.geometry_type) {
|
|
2116
|
+
obj.tabular = true;
|
|
2117
|
+
} else {
|
|
2118
|
+
obj.geographic = true;
|
|
2119
|
+
obj.layer = layer;
|
|
2120
|
+
obj.arcs = displayArcs;
|
|
2121
|
+
}
|
|
2122
|
+
|
|
2123
|
+
if (obj.tabular) {
|
|
2124
|
+
utils$1.extend(obj, getDisplayLayerForTable(layer.data));
|
|
2125
|
+
}
|
|
2126
|
+
|
|
2127
|
+
// dynamic reprojection (arcs were already reprojected above)
|
|
2128
|
+
if (obj.geographic && needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
2129
|
+
obj.dynamic_crs = displayCRS;
|
|
2130
|
+
obj.invertPoint = internal.getProjTransform2(displayCRS, sourceCRS);
|
|
2131
|
+
obj.projectPoint = internal.getProjTransform2(sourceCRS, displayCRS);
|
|
2132
|
+
if (internal.layerHasPoints(layer)) {
|
|
2133
|
+
obj.layer = projectPointsForDisplay(layer, sourceCRS, displayCRS);
|
|
2134
|
+
} else if (internal.layerHasPaths(layer)) {
|
|
2135
|
+
emptyArcs = findEmptyArcs(displayArcs);
|
|
2136
|
+
if (emptyArcs.length > 0) {
|
|
2137
|
+
// Don't try to draw paths containing coordinates that failed to project
|
|
2138
|
+
obj.layer = internal.filterPathLayerByArcIds(obj.layer, emptyArcs);
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
|
|
2143
|
+
obj.bounds = getDisplayBounds(obj.layer, obj.arcs);
|
|
2144
|
+
return obj;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
|
|
2148
|
+
function getDisplayBounds(lyr, arcs) {
|
|
2149
|
+
var arcBounds = arcs ? arcs.getBounds() : new Bounds(),
|
|
2150
|
+
bounds = arcBounds, // default display extent: all arcs in the dataset
|
|
2151
|
+
lyrBounds;
|
|
2152
|
+
|
|
2153
|
+
if (lyr.geometry_type == 'point') {
|
|
2154
|
+
lyrBounds = internal.getLayerBounds(lyr);
|
|
2155
|
+
if (lyrBounds && lyrBounds.hasBounds()) {
|
|
2156
|
+
if (lyrBounds.area() > 0 || !arcBounds.hasBounds()) {
|
|
2157
|
+
bounds = lyrBounds;
|
|
2158
|
+
} else {
|
|
2159
|
+
// if a point layer has no extent (e.g. contains only a single point),
|
|
2160
|
+
// then merge with arc bounds, to place the point in context.
|
|
2161
|
+
bounds = arcBounds.mergeBounds(lyrBounds);
|
|
2162
|
+
}
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
|
|
2166
|
+
if (!bounds || !bounds.hasBounds()) { // empty layer
|
|
2167
|
+
bounds = new Bounds();
|
|
2168
|
+
}
|
|
2169
|
+
return bounds;
|
|
2170
|
+
}
|
|
2171
|
+
|
|
2172
|
+
// Returns an array of ids of empty arcs (arcs can be set to empty if errors occur while projecting them)
|
|
2173
|
+
function findEmptyArcs(arcs) {
|
|
2174
|
+
var nn = arcs.getVertexData().nn;
|
|
2175
|
+
var ids = [];
|
|
2176
|
+
for (var i=0, n=nn.length; i<n; i++) {
|
|
2177
|
+
if (nn[i] === 0) {
|
|
2178
|
+
ids.push(i);
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return ids;
|
|
2182
|
+
}
|
|
2183
|
+
|
|
1739
2184
|
/*
|
|
1740
2185
|
How changes in the simplify control should affect other components
|
|
1741
2186
|
|
|
@@ -1904,6 +2349,7 @@
|
|
|
1904
2349
|
var opts = getSimplifyOptions();
|
|
1905
2350
|
mapshaper.simplify(dataset, opts);
|
|
1906
2351
|
gui.session.simplificationApplied(getSimplifyOptionsAsString());
|
|
2352
|
+
updateZ(gui.map.getActiveLayer()); // question: does this update all display layers?
|
|
1907
2353
|
model.updated({
|
|
1908
2354
|
// trigger filtered arc rebuild without redraw if pct is 1
|
|
1909
2355
|
simplify_method: opts.percentage == 1,
|
|
@@ -1955,7 +2401,8 @@
|
|
|
1955
2401
|
function onChange(pct) {
|
|
1956
2402
|
if (_value != pct) {
|
|
1957
2403
|
_value = pct;
|
|
1958
|
-
model.getActiveLayer().dataset.arcs.setRetainedInterval(fromPct(pct));
|
|
2404
|
+
// model.getActiveLayer().dataset.arcs.setRetainedInterval(fromPct(pct));
|
|
2405
|
+
setZ(gui.map.getActiveLayer(), fromPct(pct));
|
|
1959
2406
|
gui.session.updateSimplificationPct(pct);
|
|
1960
2407
|
model.updated({'simplify_amount': true});
|
|
1961
2408
|
updateSliderDisplay();
|
|
@@ -2191,77 +2638,6 @@
|
|
|
2191
2638
|
}
|
|
2192
2639
|
}
|
|
2193
2640
|
|
|
2194
|
-
// Assumes projections are available
|
|
2195
|
-
|
|
2196
|
-
function needReprojectionForDisplay(sourceCRS, displayCRS) {
|
|
2197
|
-
if (!sourceCRS || !displayCRS) {
|
|
2198
|
-
return false;
|
|
2199
|
-
}
|
|
2200
|
-
if (internal.crsAreEqual(sourceCRS, displayCRS)) {
|
|
2201
|
-
return false;
|
|
2202
|
-
}
|
|
2203
|
-
return true;
|
|
2204
|
-
}
|
|
2205
|
-
|
|
2206
|
-
function projectArcsForDisplay_v1(arcs, src, dest) {
|
|
2207
|
-
var copy = arcs.getCopy(); // need to flatten first?
|
|
2208
|
-
var proj = internal.getProjTransform(src, dest);
|
|
2209
|
-
internal.projectArcs(copy, proj); // need to densify arcs?
|
|
2210
|
-
return copy;
|
|
2211
|
-
}
|
|
2212
|
-
|
|
2213
|
-
function projectArcsForDisplay(arcs, src, dest) {
|
|
2214
|
-
var copy = arcs.getCopy(); // need to flatten first?
|
|
2215
|
-
var proj = internal.getProjTransform2(src, dest);
|
|
2216
|
-
internal.projectArcs2(copy, proj); // need to densify arcs?
|
|
2217
|
-
return copy;
|
|
2218
|
-
}
|
|
2219
|
-
|
|
2220
|
-
function projectPointsForDisplay(lyr, src, dest) {
|
|
2221
|
-
var copy = utils$1.extend({}, lyr);
|
|
2222
|
-
var proj = internal.getProjTransform2(src, dest);
|
|
2223
|
-
copy.shapes = internal.cloneShapes(lyr.shapes);
|
|
2224
|
-
internal.projectPointLayer(copy, proj);
|
|
2225
|
-
return copy;
|
|
2226
|
-
}
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
// Update map extent and trigger redraw, after a new display CRS has been applied
|
|
2230
|
-
function projectMapExtent(ext, src, dest, newBounds) {
|
|
2231
|
-
var oldBounds = ext.getBounds();
|
|
2232
|
-
var oldScale = ext.scale();
|
|
2233
|
-
var newCP, proj;
|
|
2234
|
-
|
|
2235
|
-
// if source or destination CRS is unknown, show full extent
|
|
2236
|
-
// if map is at full extent, show full extent
|
|
2237
|
-
// TODO: handle case that scale is 1 and map is panned away from center
|
|
2238
|
-
if (ext.scale() == 1 || !dest) {
|
|
2239
|
-
ext.setBounds(newBounds);
|
|
2240
|
-
ext.home(); // sets full extent and triggers redraw
|
|
2241
|
-
} else {
|
|
2242
|
-
// if map is zoomed, stay centered on the same geographic location, at the same relative scale
|
|
2243
|
-
proj = internal.getProjTransform2(src, dest);
|
|
2244
|
-
newCP = proj(oldBounds.centerX(), oldBounds.centerY());
|
|
2245
|
-
ext.setBounds(newBounds);
|
|
2246
|
-
if (!newCP) {
|
|
2247
|
-
// projection of center point failed; use center of bounds
|
|
2248
|
-
// (also consider just resetting the view using ext.home())
|
|
2249
|
-
newCP = [newBounds.centerX(), newBounds.centerY()];
|
|
2250
|
-
}
|
|
2251
|
-
ext.recenter(newCP[0], newCP[1], oldScale);
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2254
|
-
|
|
2255
|
-
// Called from console; for testing dynamic crs
|
|
2256
|
-
function setDisplayProjection(gui, cmd) {
|
|
2257
|
-
var arg = cmd.replace(/^projd[ ]*/, '');
|
|
2258
|
-
if (arg) {
|
|
2259
|
-
gui.map.setDisplayCRS(internal.getCRS(arg));
|
|
2260
|
-
} else {
|
|
2261
|
-
gui.map.setDisplayCRS(null);
|
|
2262
|
-
}
|
|
2263
|
-
}
|
|
2264
|
-
|
|
2265
2641
|
function Console(gui) {
|
|
2266
2642
|
var model = gui.model;
|
|
2267
2643
|
var CURSOR = '$ ';
|
|
@@ -2346,8 +2722,8 @@
|
|
|
2346
2722
|
// when an instance loses focus.
|
|
2347
2723
|
internal.setLoggingFunctions(consoleMessage, consoleError, consoleStop);
|
|
2348
2724
|
gui.container.addClass('console-open');
|
|
2349
|
-
gui.dispatchEvent('resize');
|
|
2350
2725
|
el.show();
|
|
2726
|
+
gui.dispatchEvent('resize');
|
|
2351
2727
|
input.node().focus();
|
|
2352
2728
|
history = getHistory();
|
|
2353
2729
|
}
|
|
@@ -2902,47 +3278,6 @@
|
|
|
2902
3278
|
|
|
2903
3279
|
utils$1.inherit(RepairControl, EventDispatcher);
|
|
2904
3280
|
|
|
2905
|
-
function filterLayerByIds(lyr, ids) {
|
|
2906
|
-
var shapes;
|
|
2907
|
-
if (lyr.shapes) {
|
|
2908
|
-
shapes = ids.map(function(id) {
|
|
2909
|
-
return lyr.shapes[id];
|
|
2910
|
-
});
|
|
2911
|
-
return utils$1.defaults({shapes: shapes, data: null}, lyr);
|
|
2912
|
-
}
|
|
2913
|
-
return lyr;
|
|
2914
|
-
}
|
|
2915
|
-
|
|
2916
|
-
function formatLayerNameForDisplay(name) {
|
|
2917
|
-
return name || '[unnamed]';
|
|
2918
|
-
}
|
|
2919
|
-
|
|
2920
|
-
function cleanLayerName(raw) {
|
|
2921
|
-
return raw.replace(/[\n\t/\\]/g, '')
|
|
2922
|
-
.replace(/^[\.\s]+/, '').replace(/[\.\s]+$/, '');
|
|
2923
|
-
}
|
|
2924
|
-
|
|
2925
|
-
function updateLayerStackOrder(layers) {
|
|
2926
|
-
// 1. assign ascending ids to unassigned layers above the range of other layers
|
|
2927
|
-
layers.forEach(function(o, i) {
|
|
2928
|
-
if (!o.layer.stack_id) o.layer.stack_id = 1e6 + i;
|
|
2929
|
-
});
|
|
2930
|
-
// 2. sort in ascending order
|
|
2931
|
-
layers.sort(function(a, b) {
|
|
2932
|
-
return a.layer.stack_id - b.layer.stack_id;
|
|
2933
|
-
});
|
|
2934
|
-
// 3. assign consecutve ids
|
|
2935
|
-
layers.forEach(function(o, i) {
|
|
2936
|
-
o.layer.stack_id = i + 1;
|
|
2937
|
-
});
|
|
2938
|
-
return layers;
|
|
2939
|
-
}
|
|
2940
|
-
|
|
2941
|
-
function sortLayersForMenuDisplay(layers) {
|
|
2942
|
-
layers = updateLayerStackOrder(layers);
|
|
2943
|
-
return layers.reverse();
|
|
2944
|
-
}
|
|
2945
|
-
|
|
2946
3281
|
// import { groupLayersByDataset } from '../dataset/mapshaper-target-utils';
|
|
2947
3282
|
|
|
2948
3283
|
// Export buttons and their behavior
|
|
@@ -3669,7 +4004,6 @@
|
|
|
3669
4004
|
offset = 0;
|
|
3670
4005
|
}
|
|
3671
4006
|
|
|
3672
|
-
|
|
3673
4007
|
function isUndoEvt(e) {
|
|
3674
4008
|
return (e.ctrlKey || e.metaKey) && !e.shiftKey && e.key == 'z';
|
|
3675
4009
|
}
|
|
@@ -3691,18 +4025,17 @@
|
|
|
3691
4025
|
e.stopPropagation();
|
|
3692
4026
|
e.preventDefault();
|
|
3693
4027
|
}
|
|
3694
|
-
|
|
3695
4028
|
}, this, 10);
|
|
3696
4029
|
|
|
3697
|
-
// undo/redo point/symbol dragging
|
|
3698
|
-
//
|
|
3699
|
-
gui.on('symbol_dragstart', function(e) {
|
|
3700
|
-
stashedUndo = this.makePointSetter(e.FID);
|
|
3701
|
-
}, this);
|
|
3702
|
-
|
|
3703
4030
|
gui.on('symbol_dragend', function(e) {
|
|
3704
|
-
var
|
|
3705
|
-
|
|
4031
|
+
var target = e.data.target;
|
|
4032
|
+
var undo = function() {
|
|
4033
|
+
setPointCoords(target, e.FID, e.startCoords);
|
|
4034
|
+
};
|
|
4035
|
+
var redo = function() {
|
|
4036
|
+
setPointCoords(target, e.FID, e.endCoords);
|
|
4037
|
+
};
|
|
4038
|
+
this.addHistoryState(undo, redo);
|
|
3706
4039
|
}, this);
|
|
3707
4040
|
|
|
3708
4041
|
// undo/redo label dragging
|
|
@@ -3729,35 +4062,33 @@
|
|
|
3729
4062
|
}, this);
|
|
3730
4063
|
|
|
3731
4064
|
gui.on('vertex_dragend', function(e) {
|
|
3732
|
-
var target =
|
|
3733
|
-
var
|
|
3734
|
-
var
|
|
3735
|
-
var endPoint = internal.getVertexCoords(e.ids[0], arcs);
|
|
4065
|
+
var target = e.data.target;
|
|
4066
|
+
var startPoint = e.points[0]; // in data coords
|
|
4067
|
+
var endPoint = getVertexCoords(target, e.ids[0]);
|
|
3736
4068
|
var undo = function() {
|
|
3737
4069
|
if (e.insertion) {
|
|
3738
|
-
|
|
4070
|
+
deleteVertex$1(target, e.ids[0]);
|
|
3739
4071
|
} else {
|
|
3740
|
-
|
|
4072
|
+
setVertexCoords(target, e.ids, startPoint);
|
|
3741
4073
|
}
|
|
3742
4074
|
};
|
|
3743
4075
|
var redo = function() {
|
|
3744
4076
|
if (e.insertion) {
|
|
3745
|
-
|
|
4077
|
+
insertVertex$1(target, e.ids[0], endPoint);
|
|
3746
4078
|
}
|
|
3747
|
-
|
|
4079
|
+
setVertexCoords(target, e.ids, endPoint);
|
|
3748
4080
|
};
|
|
3749
4081
|
this.addHistoryState(undo, redo);
|
|
3750
4082
|
}, this);
|
|
3751
4083
|
|
|
3752
4084
|
gui.on('vertex_delete', function(e) {
|
|
3753
|
-
|
|
3754
|
-
var
|
|
3755
|
-
var p = arcs.getVertex2(e.vertex_id);
|
|
4085
|
+
// get vertex coords in data coordinates (not display coordinates);
|
|
4086
|
+
var p = getVertexCoords(e.data.target, e.vertex_id);
|
|
3756
4087
|
var redo = function() {
|
|
3757
|
-
|
|
4088
|
+
deleteVertex$1(e.data.target, e.vertex_id);
|
|
3758
4089
|
};
|
|
3759
4090
|
var undo = function() {
|
|
3760
|
-
|
|
4091
|
+
insertVertex$1(e.data.target, e.vertex_id, p);
|
|
3761
4092
|
};
|
|
3762
4093
|
this.addHistoryState(undo, redo);
|
|
3763
4094
|
}, this);
|
|
@@ -3766,14 +4097,6 @@
|
|
|
3766
4097
|
reset();
|
|
3767
4098
|
};
|
|
3768
4099
|
|
|
3769
|
-
this.makePointSetter = function(i) {
|
|
3770
|
-
var target = gui.model.getActiveLayer();
|
|
3771
|
-
var shp = cloneShape(target.layer.shapes[i]);
|
|
3772
|
-
return function() {
|
|
3773
|
-
target.layer.shapes[i] = shp;
|
|
3774
|
-
};
|
|
3775
|
-
};
|
|
3776
|
-
|
|
3777
4100
|
this.makeDataSetter = function(id) {
|
|
3778
4101
|
var target = gui.model.getActiveLayer();
|
|
3779
4102
|
var rec = copyRecord(target.layer.data.getRecordAt(id));
|
|
@@ -3783,15 +4106,6 @@
|
|
|
3783
4106
|
};
|
|
3784
4107
|
};
|
|
3785
4108
|
|
|
3786
|
-
this.makeVertexSetter = function(ids) {
|
|
3787
|
-
var target = gui.model.getActiveLayer();
|
|
3788
|
-
var arcs = target.dataset.arcs;
|
|
3789
|
-
var p = internal.getVertexCoords(ids[0], arcs);
|
|
3790
|
-
return function() {
|
|
3791
|
-
snapVerticesToPoint(ids, p, arcs, true);
|
|
3792
|
-
};
|
|
3793
|
-
};
|
|
3794
|
-
|
|
3795
4109
|
this.addHistoryState = function(undo, redo) {
|
|
3796
4110
|
if (offset > 0) {
|
|
3797
4111
|
history.splice(-offset);
|
|
@@ -5503,6 +5817,8 @@
|
|
|
5503
5817
|
// avoid re-allocating memory
|
|
5504
5818
|
var xx2 = new Float64Array(data.xx.buffer, 0, n-1);
|
|
5505
5819
|
var yy2 = new Float64Array(data.yy.buffer, 0, n-1);
|
|
5820
|
+
var zz2 = arcs.isFlat() ? null : new Float64Array(data.zz.buffer, 0, n-1);
|
|
5821
|
+
var z = arcs.getRetainedInterval();
|
|
5506
5822
|
var count = 0;
|
|
5507
5823
|
var found = false;
|
|
5508
5824
|
for (var j=0; j<nn.length; j++) {
|
|
@@ -5516,24 +5832,31 @@
|
|
|
5516
5832
|
utils.copyElements(data.yy, 0, yy2, 0, i);
|
|
5517
5833
|
utils.copyElements(data.xx, i+1, xx2, i, n-i-1);
|
|
5518
5834
|
utils.copyElements(data.yy, i+1, yy2, i, n-i-1);
|
|
5519
|
-
|
|
5835
|
+
if (zz2) {
|
|
5836
|
+
utils.copyElements(data.zz, 0, zz2, 0, i);
|
|
5837
|
+
utils.copyElements(data.zz, i+1, zz2, i, n-i-1);
|
|
5838
|
+
}
|
|
5839
|
+
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
5840
|
+
arcs.setRetainedInterval(z);
|
|
5520
5841
|
}
|
|
5521
5842
|
|
|
5522
5843
|
function insertVertex(arcs, i, p) {
|
|
5523
|
-
// TODO: add extra bytes to the buffers, to reduce new memory allocation
|
|
5524
5844
|
var data = arcs.getVertexData();
|
|
5525
5845
|
var nn = data.nn;
|
|
5526
5846
|
var n = data.xx.length;
|
|
5527
5847
|
var count = 0;
|
|
5528
5848
|
var found = false;
|
|
5529
|
-
var xx2, yy2;
|
|
5849
|
+
var xx2, yy2, zz2;
|
|
5530
5850
|
// avoid re-allocating memory on each insertion
|
|
5531
5851
|
if (data.xx.buffer.byteLength >= data.xx.length * 8 + 8) {
|
|
5532
5852
|
xx2 = new Float64Array(data.xx.buffer, 0, n+1);
|
|
5533
5853
|
yy2 = new Float64Array(data.yy.buffer, 0, n+1);
|
|
5534
5854
|
} else {
|
|
5535
|
-
xx2 = new Float64Array(new ArrayBuffer((n +
|
|
5536
|
-
yy2 = new Float64Array(new ArrayBuffer((n +
|
|
5855
|
+
xx2 = new Float64Array(new ArrayBuffer((n + 50) * 8), 0, n+1);
|
|
5856
|
+
yy2 = new Float64Array(new ArrayBuffer((n + 50) * 8), 0, n+1);
|
|
5857
|
+
}
|
|
5858
|
+
if (!arcs.isFlat()) {
|
|
5859
|
+
zz2 = new Float64Array(new ArrayBuffer((n + 1) * 8), 0, n+1);
|
|
5537
5860
|
}
|
|
5538
5861
|
for (var j=0; j<nn.length; j++) {
|
|
5539
5862
|
count += nn[j];
|
|
@@ -5548,7 +5871,12 @@
|
|
|
5548
5871
|
utils.copyElements(data.yy, i, yy2, i+1, n-i);
|
|
5549
5872
|
xx2[i] = p[0];
|
|
5550
5873
|
yy2[i] = p[1];
|
|
5551
|
-
|
|
5874
|
+
if (zz2) {
|
|
5875
|
+
zz2[i] = Infinity;
|
|
5876
|
+
utils.copyElements(data.zz, 0, zz2, 0, i);
|
|
5877
|
+
utils.copyElements(data.zz, i, zz2, i+1, n-i);
|
|
5878
|
+
}
|
|
5879
|
+
arcs.updateVertexData(nn, xx2, yy2, zz2);
|
|
5552
5880
|
}
|
|
5553
5881
|
|
|
5554
5882
|
function getShapeHitTest(displayLayer, ext, interactionMode) {
|
|
@@ -5675,7 +6003,7 @@
|
|
|
5675
6003
|
hits.push(id);
|
|
5676
6004
|
}
|
|
5677
6005
|
});
|
|
5678
|
-
//
|
|
6006
|
+
// TODO: add info on what part of a shape gets hit
|
|
5679
6007
|
return {
|
|
5680
6008
|
ids: utils$1.uniq(hits) // multipoint features can register multiple hits
|
|
5681
6009
|
};
|
|
@@ -6283,15 +6611,18 @@
|
|
|
6283
6611
|
function onMouseChange(e) {
|
|
6284
6612
|
if (!enabled) return;
|
|
6285
6613
|
if (isOverMap(e)) {
|
|
6286
|
-
displayCoords(
|
|
6614
|
+
displayCoords(gui.map.translatePixelCoords(e.x, e.y));
|
|
6287
6615
|
} else {
|
|
6288
6616
|
clearCoords();
|
|
6289
6617
|
}
|
|
6290
6618
|
}
|
|
6291
6619
|
|
|
6292
6620
|
function displayCoords(p) {
|
|
6293
|
-
var
|
|
6294
|
-
var
|
|
6621
|
+
var p1 = gui.map.translatePixelCoords(0, ext.height());
|
|
6622
|
+
var p2 = gui.map.translatePixelCoords(ext.width(), 0);
|
|
6623
|
+
var bbox = p1.concat(p2);
|
|
6624
|
+
var decimals = internal.getBoundsPrecisionForDisplay(bbox);
|
|
6625
|
+
var str = internal.getRoundedCoordString(p, decimals);
|
|
6295
6626
|
readout.text(str).show();
|
|
6296
6627
|
}
|
|
6297
6628
|
|
|
@@ -6756,6 +7087,10 @@
|
|
|
6756
7087
|
ext.zoomToExtent(e.value, _fx, _fy);
|
|
6757
7088
|
});
|
|
6758
7089
|
|
|
7090
|
+
mouse.on('click', function(e) {
|
|
7091
|
+
gui.dispatchEvent('map_click', e);
|
|
7092
|
+
});
|
|
7093
|
+
|
|
6759
7094
|
mouse.on('dblclick', function(e) {
|
|
6760
7095
|
if (disabled()) return;
|
|
6761
7096
|
zoomByPct(getZoomInPct(), e.x / ext.width(), e.y / ext.height());
|
|
@@ -7491,31 +7826,38 @@
|
|
|
7491
7826
|
}
|
|
7492
7827
|
|
|
7493
7828
|
function initPointDragging(gui, ext, hit) {
|
|
7494
|
-
|
|
7829
|
+
var symbolInfo;
|
|
7495
7830
|
function active(e) {
|
|
7496
7831
|
return e.id > -1 && gui.interaction.getMode() == 'location';
|
|
7497
7832
|
}
|
|
7498
7833
|
|
|
7499
7834
|
hit.on('dragstart', function(e) {
|
|
7500
7835
|
if (!active(e)) return;
|
|
7501
|
-
|
|
7836
|
+
var target = hit.getHitTarget();
|
|
7837
|
+
symbolInfo = {
|
|
7838
|
+
FID: e.id,
|
|
7839
|
+
startCoords: getPointCoords(target, e.id),
|
|
7840
|
+
target: target
|
|
7841
|
+
};
|
|
7502
7842
|
});
|
|
7503
7843
|
|
|
7504
7844
|
hit.on('drag', function(e) {
|
|
7505
7845
|
if (!active(e)) return;
|
|
7506
|
-
|
|
7507
|
-
var p = getPointCoordsById(e.id,
|
|
7846
|
+
// TODO: support multi points... get id of closest part to the pointer
|
|
7847
|
+
var p = getPointCoordsById(e.id, symbolInfo.target.layer);
|
|
7508
7848
|
if (!p) return;
|
|
7509
7849
|
var diff = translateDeltaDisplayCoords(e.dx, e.dy, ext);
|
|
7510
7850
|
p[0] += diff[0];
|
|
7511
7851
|
p[1] += diff[1];
|
|
7512
7852
|
gui.dispatchEvent('map-needs-refresh');
|
|
7513
|
-
gui.dispatchEvent('symbol_drag', {FID: e.id});
|
|
7514
7853
|
});
|
|
7515
7854
|
|
|
7516
7855
|
hit.on('dragend', function(e) {
|
|
7517
|
-
if (!active(e)) return;
|
|
7518
|
-
|
|
7856
|
+
if (!active(e) || !symbolInfo ) return;
|
|
7857
|
+
updatePointCoords(symbolInfo.target, e.id);
|
|
7858
|
+
symbolInfo.endCoords = getPointCoords(symbolInfo.target, e.id);
|
|
7859
|
+
gui.dispatchEvent('symbol_dragend', symbolInfo);
|
|
7860
|
+
symbolInfo = null;
|
|
7519
7861
|
});
|
|
7520
7862
|
|
|
7521
7863
|
function translateDeltaDisplayCoords(dx, dy, ext) {
|
|
@@ -7569,8 +7911,11 @@
|
|
|
7569
7911
|
if (pixelDist > HOVER_THRESHOLD) {
|
|
7570
7912
|
return null;
|
|
7571
7913
|
}
|
|
7572
|
-
var points = nearestIds.map(function(i) {
|
|
7914
|
+
var points = nearestIds.map(function(i) {
|
|
7915
|
+
return getVertexCoords(target, i); // data coordinates
|
|
7916
|
+
});
|
|
7573
7917
|
return {
|
|
7918
|
+
target: target,
|
|
7574
7919
|
ids: nearestIds,
|
|
7575
7920
|
points: points
|
|
7576
7921
|
};
|
|
@@ -7580,8 +7925,7 @@
|
|
|
7580
7925
|
var target = hit.getHitTarget();
|
|
7581
7926
|
if (!target.arcs.isFlat()) return null; // vertex insertion not supported with simplification
|
|
7582
7927
|
var p = ext.translatePixelCoords(e.x, e.y);
|
|
7583
|
-
var
|
|
7584
|
-
var midpoint = findNearestMidpoint(p, shp, target.arcs);
|
|
7928
|
+
var midpoint = findNearestMidpoint(p, e.id, target);
|
|
7585
7929
|
if (!midpoint ||
|
|
7586
7930
|
midpoint.distance / ext.getPixelSize() > MIDPOINT_THRESHOLD) return null;
|
|
7587
7931
|
return midpoint;
|
|
@@ -7591,8 +7935,9 @@
|
|
|
7591
7935
|
if (!active()) return;
|
|
7592
7936
|
if (insertionPoint) {
|
|
7593
7937
|
var target = hit.getHitTarget();
|
|
7594
|
-
|
|
7938
|
+
insertVertex$1(target, insertionPoint.i, insertionPoint.point);
|
|
7595
7939
|
dragInfo = {
|
|
7940
|
+
target: target,
|
|
7596
7941
|
insertion: true,
|
|
7597
7942
|
ids: [insertionPoint.i],
|
|
7598
7943
|
points: [insertionPoint.point]
|
|
@@ -7624,6 +7969,7 @@
|
|
|
7624
7969
|
// kludge to get dataset to recalculate internal bounding boxes
|
|
7625
7970
|
hit.getHitTarget().arcs.transformPoints(function() {});
|
|
7626
7971
|
clearHoverVertex();
|
|
7972
|
+
updateVertexCoords(dragInfo.target, dragInfo.ids);
|
|
7627
7973
|
gui.dispatchEvent('vertex_dragend', dragInfo);
|
|
7628
7974
|
gui.dispatchEvent('map-needs-refresh');
|
|
7629
7975
|
dragInfo = null;
|
|
@@ -7641,9 +7987,10 @@
|
|
|
7641
7987
|
return;
|
|
7642
7988
|
}
|
|
7643
7989
|
gui.dispatchEvent('vertex_delete', {
|
|
7990
|
+
target: target,
|
|
7644
7991
|
vertex_id: vId
|
|
7645
7992
|
});
|
|
7646
|
-
|
|
7993
|
+
deleteVertex$1(target, vId);
|
|
7647
7994
|
clearHoverVertex();
|
|
7648
7995
|
gui.dispatchEvent('map-needs-refresh');
|
|
7649
7996
|
});
|
|
@@ -7661,7 +8008,7 @@
|
|
|
7661
8008
|
// if hovering near a segment midpoint: show the midpoint and save midpoint info
|
|
7662
8009
|
insertionPoint = findVertexInsertionPoint(e);
|
|
7663
8010
|
if (insertionPoint) {
|
|
7664
|
-
hit.setHoverVertex(insertionPoint.
|
|
8011
|
+
hit.setHoverVertex(insertionPoint.displayPoint);
|
|
7665
8012
|
} else {
|
|
7666
8013
|
// pointer is not over a vertex: clear any hover effect
|
|
7667
8014
|
clearHoverVertex();
|
|
@@ -7672,7 +8019,9 @@
|
|
|
7672
8019
|
|
|
7673
8020
|
// Given a location @p (e.g. corresponding to the mouse pointer location),
|
|
7674
8021
|
// find the midpoint of two vertices on @shp suitable for inserting a new vertex
|
|
7675
|
-
function findNearestMidpoint(p,
|
|
8022
|
+
function findNearestMidpoint(p, fid, target) {
|
|
8023
|
+
var arcs = target.arcs;
|
|
8024
|
+
var shp = target.layer.shapes[fid];
|
|
7676
8025
|
var minDist = Infinity, v;
|
|
7677
8026
|
internal.forEachSegmentInShape(shp, arcs, function(i, j, xx, yy) {
|
|
7678
8027
|
var x1 = xx[i],
|
|
@@ -7681,6 +8030,7 @@
|
|
|
7681
8030
|
y2 = yy[j],
|
|
7682
8031
|
cx = (x1 + x2) / 2,
|
|
7683
8032
|
cy = (y1 + y2) / 2,
|
|
8033
|
+
midpoint = [cx, cy],
|
|
7684
8034
|
dist = geom.distance2D(cx, cy, p[0], p[1]);
|
|
7685
8035
|
if (dist < minDist) {
|
|
7686
8036
|
minDist = dist;
|
|
@@ -7688,7 +8038,8 @@
|
|
|
7688
8038
|
i: (i < j ? i : j) + 1, // insertion point
|
|
7689
8039
|
segment: [i, j],
|
|
7690
8040
|
segmentLen: geom.distance2D(x1, y1, x2, y2),
|
|
7691
|
-
|
|
8041
|
+
displayPoint: midpoint,
|
|
8042
|
+
point: translateDisplayPoint(target, midpoint),
|
|
7692
8043
|
distance: dist
|
|
7693
8044
|
};
|
|
7694
8045
|
}
|
|
@@ -9062,7 +9413,7 @@
|
|
|
9062
9413
|
var popup = gui.container.findChild('.box-tool-options');
|
|
9063
9414
|
var coords = popup.findChild('.box-coords');
|
|
9064
9415
|
var _on = false;
|
|
9065
|
-
var
|
|
9416
|
+
var bboxDisplayCoords, bboxPixels, bboxDataCoords;
|
|
9066
9417
|
|
|
9067
9418
|
var infoBtn = new SimpleButton(popup.findChild('.info-btn')).on('click', function() {
|
|
9068
9419
|
if (coords.visible()) hideCoords(); else showCoords();
|
|
@@ -9093,7 +9444,7 @@
|
|
|
9093
9444
|
});
|
|
9094
9445
|
|
|
9095
9446
|
new SimpleButton(popup.findChild('.clip-btn')).on('click', function() {
|
|
9096
|
-
runCommand('-clip bbox2=' +
|
|
9447
|
+
runCommand('-clip bbox2=' + bboxDataCoords.join(','));
|
|
9097
9448
|
});
|
|
9098
9449
|
|
|
9099
9450
|
gui.addMode('box_tool', turnOn, turnOff);
|
|
@@ -9109,8 +9460,8 @@
|
|
|
9109
9460
|
// Update the visible rectangle when the map view changes
|
|
9110
9461
|
// (e.g. during zooming or panning)
|
|
9111
9462
|
ext.on('change', function() {
|
|
9112
|
-
if (!_on || !box.visible() || !
|
|
9113
|
-
var b = coordsToPix(
|
|
9463
|
+
if (!_on || !box.visible() || !bboxDisplayCoords) return;
|
|
9464
|
+
var b = coordsToPix(bboxDisplayCoords);
|
|
9114
9465
|
var pos = ext.position();
|
|
9115
9466
|
var dx = pos.pageX,
|
|
9116
9467
|
dy = pos.pageY;
|
|
@@ -9125,7 +9476,7 @@
|
|
|
9125
9476
|
gui.on('box_drag', function(e) {
|
|
9126
9477
|
var b = e.page_bbox;
|
|
9127
9478
|
bboxPixels = e.map_bbox;
|
|
9128
|
-
|
|
9479
|
+
bboxDisplayCoords = pixToCoords(bboxPixels);
|
|
9129
9480
|
if (_on || inZoomMode()) {
|
|
9130
9481
|
box.show(b[0], b[1], b[2], b[3]);
|
|
9131
9482
|
}
|
|
@@ -9133,7 +9484,8 @@
|
|
|
9133
9484
|
|
|
9134
9485
|
gui.on('box_drag_end', function(e) {
|
|
9135
9486
|
bboxPixels = e.map_bbox;
|
|
9136
|
-
|
|
9487
|
+
bboxDisplayCoords = pixToCoords(bboxPixels);
|
|
9488
|
+
bboxDataCoords = getBBoxCoords(gui.map.getActiveLayer(), bboxDisplayCoords);
|
|
9137
9489
|
if (inZoomMode()) {
|
|
9138
9490
|
box.hide();
|
|
9139
9491
|
nav.zoomToBbox(bboxPixels);
|
|
@@ -9157,7 +9509,7 @@
|
|
|
9157
9509
|
|
|
9158
9510
|
function showCoords() {
|
|
9159
9511
|
El(infoBtn.node()).addClass('selected-btn');
|
|
9160
|
-
coords.text(
|
|
9512
|
+
coords.text(bboxDataCoords.join(','));
|
|
9161
9513
|
coords.show();
|
|
9162
9514
|
GUI.selectElement(coords.node());
|
|
9163
9515
|
}
|
|
@@ -9204,238 +9556,189 @@
|
|
|
9204
9556
|
return self;
|
|
9205
9557
|
}
|
|
9206
9558
|
|
|
9207
|
-
|
|
9208
|
-
|
|
9209
|
-
|
|
9210
|
-
|
|
9211
|
-
|
|
9212
|
-
|
|
9213
|
-
|
|
9214
|
-
|
|
9215
|
-
|
|
9216
|
-
|
|
9217
|
-
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9559
|
+
function loadScript(url, cb) {
|
|
9560
|
+
var script = document.createElement('script');
|
|
9561
|
+
script.onload = cb;
|
|
9562
|
+
script.src = url;
|
|
9563
|
+
document.head.appendChild(script);
|
|
9564
|
+
}
|
|
9565
|
+
|
|
9566
|
+
function loadStylesheet(url) {
|
|
9567
|
+
var el = document.createElement('link');
|
|
9568
|
+
el.rel = 'stylesheet';
|
|
9569
|
+
el.type = 'text/css';
|
|
9570
|
+
el.media = 'screen';
|
|
9571
|
+
el.href = url;
|
|
9572
|
+
document.head.appendChild(el);
|
|
9573
|
+
}
|
|
9574
|
+
|
|
9575
|
+
function Basemap(gui, ext) {
|
|
9576
|
+
var menu = gui.container.findChild('.basemap-options');
|
|
9577
|
+
var list = menu.findChild('.basemap-styles');
|
|
9578
|
+
var container = gui.container.findChild('.basemap-container');
|
|
9579
|
+
var basemapBtn = gui.container.findChild('.basemap-btn');
|
|
9580
|
+
var basemapMsg = gui.container.findChild('.basemap-error');
|
|
9581
|
+
var mapEl = gui.container.findChild('.basemap');
|
|
9582
|
+
var extentNote = El('div').addClass('basemap-note').appendTo(container).hide();
|
|
9583
|
+
var params = window.mapboxParams;
|
|
9584
|
+
var map;
|
|
9585
|
+
var activeStyle;
|
|
9586
|
+
var loading = false;
|
|
9587
|
+
|
|
9588
|
+
if (params) {
|
|
9589
|
+
init();
|
|
9590
|
+
} else {
|
|
9591
|
+
basemapBtn.hide();
|
|
9234
9592
|
}
|
|
9235
9593
|
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
//
|
|
9242
|
-
var unitsPerPixel = 1/ext.getTransform().mx,
|
|
9243
|
-
useFiltering = filteredArcs && unitsPerPixel > filteredSegLen * 1.5;
|
|
9244
|
-
return useFiltering ? filteredArcs : unfilteredArcs;
|
|
9245
|
-
};
|
|
9246
|
-
|
|
9247
|
-
return unfilteredArcs;
|
|
9248
|
-
}
|
|
9594
|
+
function init() {
|
|
9595
|
+
gui.addMode('basemap', turnOn, turnOff, basemapBtn);
|
|
9596
|
+
// model.on('select', function() {
|
|
9597
|
+
// TODO: hide basemap
|
|
9598
|
+
// if (gui.getMode() == 'basemap') gui.clearMode();
|
|
9599
|
+
// });
|
|
9249
9600
|
|
|
9250
|
-
|
|
9251
|
-
|
|
9252
|
-
|
|
9253
|
-
|
|
9254
|
-
gutter = 6,
|
|
9255
|
-
arcs = [],
|
|
9256
|
-
shapes = [],
|
|
9257
|
-
aspectRatio = 1.1,
|
|
9258
|
-
x, y, col, row, blockSize;
|
|
9601
|
+
new SimpleButton(menu.findChild('.close-btn')).on('click', function() {
|
|
9602
|
+
gui.clearMode();
|
|
9603
|
+
turnOff();
|
|
9604
|
+
});
|
|
9259
9605
|
|
|
9260
|
-
|
|
9261
|
-
|
|
9262
|
-
|
|
9263
|
-
|
|
9264
|
-
cellHeight = 4;
|
|
9265
|
-
aspectRatio = 1.45;
|
|
9266
|
-
} else if (n > 5000) {
|
|
9267
|
-
cellWidth = 5;
|
|
9268
|
-
gutter = 3;
|
|
9269
|
-
aspectRatio = 1.45;
|
|
9270
|
-
} else if (n > 1000) {
|
|
9271
|
-
gutter = 3;
|
|
9272
|
-
cellWidth = 8;
|
|
9273
|
-
aspectRatio = 1.3;
|
|
9274
|
-
}
|
|
9606
|
+
gui.on('map_click', function() {
|
|
9607
|
+
// close menu if user click on the map
|
|
9608
|
+
if (gui.getMode() == 'basemap') gui.clearMode();
|
|
9609
|
+
});
|
|
9275
9610
|
|
|
9276
|
-
|
|
9277
|
-
|
|
9278
|
-
|
|
9279
|
-
|
|
9611
|
+
params.styles.forEach(function(style) {
|
|
9612
|
+
var btn = El('div').html(`<div class="basemap-style-btn"><img src="${style.icon}"></img></div><div class="basemap-style-label">${style.name}</div>`);
|
|
9613
|
+
btn.findChild('.basemap-style-btn').on('click', function() {
|
|
9614
|
+
updateStyle(style == activeStyle ? null : style);
|
|
9615
|
+
updateButtons();
|
|
9616
|
+
});
|
|
9617
|
+
btn.appendTo(list);
|
|
9618
|
+
});
|
|
9280
9619
|
}
|
|
9281
9620
|
|
|
9282
|
-
|
|
9283
|
-
|
|
9284
|
-
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
if (
|
|
9288
|
-
|
|
9289
|
-
|
|
9621
|
+
function updateStyle(style) {
|
|
9622
|
+
activeStyle = style || null;
|
|
9623
|
+
if (!style) {
|
|
9624
|
+
gui.map.setDisplayCRS(null);
|
|
9625
|
+
hide();
|
|
9626
|
+
} else if (map) {
|
|
9627
|
+
map.setStyle(style.url);
|
|
9628
|
+
refresh();
|
|
9290
9629
|
} else {
|
|
9291
|
-
|
|
9630
|
+
initMap();
|
|
9292
9631
|
}
|
|
9293
9632
|
}
|
|
9294
9633
|
|
|
9295
|
-
function
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
return {
|
|
9300
|
-
layer: {
|
|
9301
|
-
geometry_type: arcs ? 'polygon' : 'point',
|
|
9302
|
-
shapes: shapes,
|
|
9303
|
-
data: table
|
|
9304
|
-
},
|
|
9305
|
-
arcs: arcs ? new internal.ArcCollection(arcs) : null
|
|
9306
|
-
};
|
|
9307
|
-
}
|
|
9308
|
-
|
|
9309
|
-
// displayCRS: CRS to use for display, or null (which clears any current display CRS)
|
|
9310
|
-
function projectDisplayLayer(lyr, displayCRS) {
|
|
9311
|
-
var sourceCRS = internal.getDatasetCRS(lyr.source.dataset);
|
|
9312
|
-
var lyr2;
|
|
9313
|
-
if (!lyr.geographic || !sourceCRS) {
|
|
9314
|
-
return lyr;
|
|
9315
|
-
}
|
|
9316
|
-
if (lyr.dynamic_crs && internal.crsAreEqual(sourceCRS, lyr.dynamic_crs)) {
|
|
9317
|
-
return lyr;
|
|
9318
|
-
}
|
|
9319
|
-
lyr2 = getDisplayLayer(lyr.source.layer, lyr.source.dataset, {crs: displayCRS});
|
|
9320
|
-
// kludge: copy projection-related properties to original layer
|
|
9321
|
-
lyr.dynamic_crs = lyr2.dynamic_crs;
|
|
9322
|
-
lyr.layer = lyr2.layer;
|
|
9323
|
-
if (lyr.style && lyr.style.ids) {
|
|
9324
|
-
// re-apply layer filter
|
|
9325
|
-
lyr.layer = filterLayerByIds(lyr.layer, lyr.style.ids);
|
|
9634
|
+
function updateButtons() {
|
|
9635
|
+
list.findChildren('.basemap-style-btn').forEach(function(el, i) {
|
|
9636
|
+
el.classed('active', params.styles[i] == activeStyle);
|
|
9637
|
+
});
|
|
9326
9638
|
}
|
|
9327
|
-
lyr.bounds = lyr2.bounds;
|
|
9328
|
-
lyr.arcs = lyr2.arcs;
|
|
9329
|
-
}
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
// Wrap a layer in an object along with information needed for rendering
|
|
9333
|
-
function getDisplayLayer(layer, dataset, opts) {
|
|
9334
|
-
var obj = {
|
|
9335
|
-
layer: null,
|
|
9336
|
-
arcs: null,
|
|
9337
|
-
// display_arcs: null,
|
|
9338
|
-
style: null,
|
|
9339
|
-
source: {
|
|
9340
|
-
layer: layer,
|
|
9341
|
-
dataset: dataset
|
|
9342
|
-
},
|
|
9343
|
-
empty: internal.getFeatureCount(layer) === 0
|
|
9344
|
-
};
|
|
9345
|
-
|
|
9346
|
-
var sourceCRS = opts.crs && internal.getDatasetCRS(dataset); // get src iff display CRS is given
|
|
9347
|
-
var displayCRS = opts.crs || null;
|
|
9348
|
-
var displayArcs = dataset.displayArcs;
|
|
9349
|
-
var emptyArcs;
|
|
9350
9639
|
|
|
9351
|
-
|
|
9352
|
-
|
|
9353
|
-
|
|
9354
|
-
|
|
9355
|
-
if (needReprojectionForDisplay(sourceCRS, displayCRS)) {
|
|
9356
|
-
displayArcs = projectArcsForDisplay(dataset.arcs, sourceCRS, displayCRS);
|
|
9357
|
-
} else {
|
|
9358
|
-
displayArcs = dataset.arcs;
|
|
9640
|
+
function turnOn() {
|
|
9641
|
+
var crs = gui.map.getDisplayCRS();
|
|
9642
|
+
if (!internal.isWebMercator(crs) && !internal.isWGS84(crs)) {
|
|
9643
|
+
basemapMsg.html('The current projection is not compatible.');
|
|
9359
9644
|
}
|
|
9360
|
-
|
|
9361
|
-
// init filtered arcs
|
|
9362
|
-
dataset.displayArcs = new MultiScaleArcCollection(displayArcs);
|
|
9645
|
+
menu.show();
|
|
9363
9646
|
}
|
|
9364
9647
|
|
|
9365
|
-
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
obj.layer = layer;
|
|
9369
|
-
// treating furniture layers (other than frame) as tabular for now,
|
|
9370
|
-
// so there is something to show if they are selected
|
|
9371
|
-
obj.tabular = obj.furniture_type != 'frame';
|
|
9372
|
-
} else if (obj.empty) {
|
|
9373
|
-
obj.layer = {shapes: []}; // ideally we should avoid empty layers
|
|
9374
|
-
} else if (!layer.geometry_type) {
|
|
9375
|
-
obj.tabular = true;
|
|
9376
|
-
} else {
|
|
9377
|
-
obj.geographic = true;
|
|
9378
|
-
obj.layer = layer;
|
|
9379
|
-
obj.arcs = displayArcs;
|
|
9648
|
+
function turnOff() {
|
|
9649
|
+
basemapMsg.html('');
|
|
9650
|
+
menu.hide();
|
|
9380
9651
|
}
|
|
9381
9652
|
|
|
9382
|
-
|
|
9383
|
-
|
|
9653
|
+
function enabled() {
|
|
9654
|
+
return !!(mapEl && params);
|
|
9384
9655
|
}
|
|
9385
9656
|
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
|
|
9389
|
-
if (internal.layerHasPoints(layer)) {
|
|
9390
|
-
obj.layer = projectPointsForDisplay(layer, sourceCRS, displayCRS);
|
|
9391
|
-
} else if (internal.layerHasPaths(layer)) {
|
|
9392
|
-
emptyArcs = findEmptyArcs(displayArcs);
|
|
9393
|
-
if (emptyArcs.length > 0) {
|
|
9394
|
-
// Don't try to draw paths containing coordinates that failed to project
|
|
9395
|
-
obj.layer = internal.filterPathLayerByArcIds(obj.layer, emptyArcs);
|
|
9396
|
-
}
|
|
9397
|
-
}
|
|
9657
|
+
function show() {
|
|
9658
|
+
gui.container.addClass('basemap-on');
|
|
9659
|
+
mapEl.node().style.display = 'block';
|
|
9398
9660
|
}
|
|
9399
9661
|
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
|
|
9662
|
+
function hide() {
|
|
9663
|
+
gui.container.removeClass('basemap-on');
|
|
9664
|
+
mapEl.node().style.display = 'none';
|
|
9665
|
+
}
|
|
9403
9666
|
|
|
9667
|
+
function getBounds() {
|
|
9668
|
+
var bbox = ext.getBounds().toArray();
|
|
9669
|
+
var tr = getLonLat(bbox[2], bbox[3]);
|
|
9670
|
+
var bl = getLonLat(bbox[0], bbox[1]);
|
|
9671
|
+
return bl.concat(tr);
|
|
9672
|
+
}
|
|
9404
9673
|
|
|
9405
|
-
|
|
9406
|
-
|
|
9407
|
-
|
|
9408
|
-
|
|
9674
|
+
function getLonLat(x, y) {
|
|
9675
|
+
var R = 6378137;
|
|
9676
|
+
var R2D = 180 / Math.PI;
|
|
9677
|
+
var lon = x / R * R2D;
|
|
9678
|
+
var lat = R2D * (Math.PI * 0.5 - 2 * Math.atan(Math.exp(-y / R)));
|
|
9679
|
+
return [lon, lat];
|
|
9680
|
+
}
|
|
9409
9681
|
|
|
9410
|
-
|
|
9411
|
-
|
|
9412
|
-
|
|
9413
|
-
|
|
9414
|
-
|
|
9415
|
-
|
|
9416
|
-
|
|
9417
|
-
|
|
9418
|
-
|
|
9419
|
-
|
|
9420
|
-
|
|
9682
|
+
function initMap() {
|
|
9683
|
+
if (!enabled() || map || loading) return;
|
|
9684
|
+
loading = true;
|
|
9685
|
+
loadStylesheet(params.css);
|
|
9686
|
+
loadScript(params.js, function() {
|
|
9687
|
+
map = new window.mapboxgl.Map({
|
|
9688
|
+
accessToken: params.key,
|
|
9689
|
+
logoPosition: 'bottom-left',
|
|
9690
|
+
container: mapEl.node(),
|
|
9691
|
+
style: activeStyle.url,
|
|
9692
|
+
bounds: getBounds(),
|
|
9693
|
+
doubleClickZoom: false,
|
|
9694
|
+
dragPan: false,
|
|
9695
|
+
dragRotate: false,
|
|
9696
|
+
scrollZoom: false,
|
|
9697
|
+
interactive: false,
|
|
9698
|
+
keyboard: false,
|
|
9699
|
+
maxPitch: 0,
|
|
9700
|
+
renderWorldCopies: true // false // false prevents panning off the map
|
|
9701
|
+
});
|
|
9702
|
+
map.on('load', function() {
|
|
9703
|
+
loading = false;
|
|
9704
|
+
refresh();
|
|
9705
|
+
});
|
|
9706
|
+
});
|
|
9421
9707
|
}
|
|
9422
9708
|
|
|
9423
|
-
|
|
9424
|
-
|
|
9709
|
+
function checkBounds(bbox) {
|
|
9710
|
+
var msg;
|
|
9711
|
+
if (bbox[1] >= -85 && bbox[3] <= 85) {
|
|
9712
|
+
extentNote.hide();
|
|
9713
|
+
return true;
|
|
9714
|
+
}
|
|
9715
|
+
if (bbox[1] > 0) msg = 'pan south to see the basemap';
|
|
9716
|
+
else if (bbox[3] < 0) msg = 'pan north to see the basemap';
|
|
9717
|
+
else msg = msg = 'zoom in to see the basemap';
|
|
9718
|
+
extentNote.html(msg).show();
|
|
9719
|
+
return false;
|
|
9425
9720
|
}
|
|
9426
|
-
return bounds;
|
|
9427
|
-
}
|
|
9428
9721
|
|
|
9429
|
-
|
|
9430
|
-
|
|
9431
|
-
|
|
9432
|
-
|
|
9433
|
-
|
|
9434
|
-
if (
|
|
9435
|
-
|
|
9722
|
+
function refresh() {
|
|
9723
|
+
if (!enabled() || !map || loading || !activeStyle) return;
|
|
9724
|
+
var crs = gui.map.getDisplayCRS();
|
|
9725
|
+
if (internal.isWGS84(crs)) {
|
|
9726
|
+
gui.map.setDisplayCRS(internal.getCRS('webmercator'));
|
|
9727
|
+
} else if (!internal.isWebMercator(crs)) {
|
|
9728
|
+
return;
|
|
9729
|
+
}
|
|
9730
|
+
var bbox = getBounds();
|
|
9731
|
+
if (!checkBounds(bbox)) {
|
|
9732
|
+
// map does not display outside these bounds
|
|
9733
|
+
hide();
|
|
9734
|
+
} else {
|
|
9735
|
+
show();
|
|
9736
|
+
map.resize();
|
|
9737
|
+
map.fitBounds(bbox, {animate: false});
|
|
9436
9738
|
}
|
|
9437
9739
|
}
|
|
9438
|
-
|
|
9740
|
+
|
|
9741
|
+
return {refresh: refresh}; // called by map when extent changes
|
|
9439
9742
|
}
|
|
9440
9743
|
|
|
9441
9744
|
utils$1.inherit(MshpMap, EventDispatcher);
|
|
@@ -9458,6 +9761,8 @@
|
|
|
9458
9761
|
_inspector, _stack,
|
|
9459
9762
|
_dynamicCRS;
|
|
9460
9763
|
|
|
9764
|
+
var _basemap = new Basemap(gui, _ext);
|
|
9765
|
+
|
|
9461
9766
|
if (gui.options.showMouseCoordinates) {
|
|
9462
9767
|
new CoordinatesDisplay(gui, _ext, _mouse);
|
|
9463
9768
|
}
|
|
@@ -9482,6 +9787,8 @@
|
|
|
9482
9787
|
|
|
9483
9788
|
model.on('update', onUpdate);
|
|
9484
9789
|
|
|
9790
|
+
|
|
9791
|
+
|
|
9485
9792
|
// Update display of segment intersections
|
|
9486
9793
|
this.setIntersectionLayer = function(lyr, dataset) {
|
|
9487
9794
|
if (lyr == _intersectionLyr) return; // no change
|
|
@@ -9499,6 +9806,12 @@
|
|
|
9499
9806
|
target.layer.pinned = !!pinned;
|
|
9500
9807
|
};
|
|
9501
9808
|
|
|
9809
|
+
this.translatePixelCoords = function(x, y) {
|
|
9810
|
+
var p = _ext.translatePixelCoords(x, y);
|
|
9811
|
+
if (!_dynamicCRS) return p;
|
|
9812
|
+
return internal.toLngLat(p, _dynamicCRS);
|
|
9813
|
+
};
|
|
9814
|
+
|
|
9502
9815
|
this.getCenterLngLat = function() {
|
|
9503
9816
|
var bounds = _ext.getBounds();
|
|
9504
9817
|
var crs = this.getDisplayCRS();
|
|
@@ -9520,6 +9833,7 @@
|
|
|
9520
9833
|
this.getExtent = function() {return _ext;};
|
|
9521
9834
|
this.isActiveLayer = isActiveLayer;
|
|
9522
9835
|
this.isVisibleLayer = isVisibleLayer;
|
|
9836
|
+
this.getActiveLayer = function() { return _activeLyr; };
|
|
9523
9837
|
|
|
9524
9838
|
// called by layer menu after layer visibility is updated
|
|
9525
9839
|
this.redraw = function() {
|
|
@@ -9551,6 +9865,7 @@
|
|
|
9551
9865
|
|
|
9552
9866
|
// Update map extent (also triggers redraw)
|
|
9553
9867
|
projectMapExtent(_ext, oldCRS, this.getDisplayCRS(), getFullBounds());
|
|
9868
|
+
_fullBounds = getFullBounds(); // update this so map extent doesn't get reset after next update
|
|
9554
9869
|
};
|
|
9555
9870
|
|
|
9556
9871
|
// Refresh map display in response to data changes, layer selection, etc.
|
|
@@ -9604,6 +9919,7 @@
|
|
|
9604
9919
|
needReset = mapNeedsReset(fullBounds, _fullBounds, _ext.getBounds(), e.flags);
|
|
9605
9920
|
}
|
|
9606
9921
|
|
|
9922
|
+
|
|
9607
9923
|
if (isFrameView()) {
|
|
9608
9924
|
_nav.setZoomFactor(0.05); // slow zooming way down to allow fine-tuning frame placement // 0.03
|
|
9609
9925
|
_ext.setFrame(getFullBounds()); // TODO: remove redundancy with drawLayers()
|
|
@@ -9643,6 +9959,7 @@
|
|
|
9643
9959
|
}
|
|
9644
9960
|
|
|
9645
9961
|
_ext.on('change', function(e) {
|
|
9962
|
+
if (_basemap) _basemap.refresh(); // keep basemap synced up (if enabled)
|
|
9646
9963
|
if (e.reset) return; // don't need to redraw map here if extent has been reset
|
|
9647
9964
|
if (isFrameView()) {
|
|
9648
9965
|
updateFrameExtent();
|
|
@@ -10013,7 +10330,9 @@
|
|
|
10013
10330
|
startEditing = function() {};
|
|
10014
10331
|
|
|
10015
10332
|
window.addEventListener('beforeunload', function(e) {
|
|
10016
|
-
if (
|
|
10333
|
+
// don't prompt if there are no datasets (this means the last layer was deleted,
|
|
10334
|
+
// hitting the 'cancel' button would leave the interface in a bad state)
|
|
10335
|
+
if (gui.session.unsavedChanges() && !gui.model.isEmpty()) {
|
|
10017
10336
|
e.returnValue = 'There are unsaved changes.';
|
|
10018
10337
|
e.preventDefault();
|
|
10019
10338
|
}
|