mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-18 14:45:12 +02:00
Move data layers out of Background
This commit is contained in:
@@ -1,9 +1,6 @@
|
||||
iD.Background = function(context) {
|
||||
var dispatch = d3.dispatch('change'),
|
||||
baseLayer = iD.TileLayer().projection(context.projection),
|
||||
gpxLayer = iD.svg.Gpx(context.projection, context),
|
||||
mapillaryImageLayer,
|
||||
mapillarySignLayer,
|
||||
overlayLayers = [];
|
||||
|
||||
var backgroundSources;
|
||||
@@ -47,7 +44,8 @@ iD.Background = function(context) {
|
||||
}
|
||||
});
|
||||
|
||||
if (background.showsGpxLayer()) {
|
||||
var gpx = context.layers().layer('gpx');
|
||||
if (gpx && gpx.enabled() && gpx.hasGpx()) {
|
||||
imageryUsed.push('Local GPX');
|
||||
}
|
||||
|
||||
@@ -77,51 +75,6 @@ iD.Background = function(context) {
|
||||
|
||||
overlays.exit()
|
||||
.remove();
|
||||
|
||||
|
||||
|
||||
// selection.selectAll('#surface')
|
||||
// .call(gpxLayer);
|
||||
|
||||
|
||||
|
||||
|
||||
// var mapillary = iD.services.mapillary,
|
||||
// supportsMapillaryImages = !!mapillary,
|
||||
// supportsMapillarySigns = !!mapillary && mapillary().signsSupported();
|
||||
|
||||
// var mapillaryImages = selection.selectAll('.layer-mapillary-images')
|
||||
// .data(supportsMapillaryImages ? [0] : []);
|
||||
|
||||
// mapillaryImages.enter().insert('div')
|
||||
// .attr('class', 'layer-layer layer-mapillary-images');
|
||||
|
||||
// if (supportsMapillaryImages) {
|
||||
// if (!mapillaryImageLayer) { mapillaryImageLayer = iD.svg.MapillaryImages(context); }
|
||||
// mapillaryImages.call(mapillaryImageLayer);
|
||||
// } else {
|
||||
// mapillaryImageLayer = null;
|
||||
// }
|
||||
|
||||
// mapillaryImages.exit()
|
||||
// .remove();
|
||||
|
||||
|
||||
// var mapillarySigns = selection.selectAll('.layer-mapillary-signs')
|
||||
// .data(supportsMapillarySigns ? [0] : []);
|
||||
|
||||
// mapillarySigns.enter().insert('div')
|
||||
// .attr('class', 'layer-layer layer-mapillary-signs');
|
||||
|
||||
// if (supportsMapillarySigns) {
|
||||
// if (!mapillarySignLayer) { mapillarySignLayer = iD.svg.MapillarySigns(context); }
|
||||
// mapillarySigns.call(mapillarySignLayer);
|
||||
// } else {
|
||||
// mapillarySignLayer = null;
|
||||
// }
|
||||
|
||||
// mapillarySigns.exit()
|
||||
// .remove();
|
||||
}
|
||||
|
||||
background.sources = function(extent) {
|
||||
@@ -132,8 +85,6 @@ iD.Background = function(context) {
|
||||
|
||||
background.dimensions = function(_) {
|
||||
baseLayer.dimensions(_);
|
||||
if (mapillaryImageLayer) mapillaryImageLayer.dimensions(_);
|
||||
if (mapillarySignLayer) mapillarySignLayer.dimensions(_);
|
||||
|
||||
overlayLayers.forEach(function(layer) {
|
||||
layer.dimensions(_);
|
||||
@@ -154,43 +105,6 @@ iD.Background = function(context) {
|
||||
background.baseLayerSource(findSource('Bing'));
|
||||
};
|
||||
|
||||
background.gpxLayer = function() {
|
||||
return gpxLayer;
|
||||
};
|
||||
|
||||
background.hasGpxLayer = function() {
|
||||
return !_.isEmpty(gpxLayer.geojson());
|
||||
};
|
||||
|
||||
background.showsGpxLayer = function() {
|
||||
return background.hasGpxLayer() && gpxLayer.enabled();
|
||||
};
|
||||
|
||||
background.toggleGpxLayer = function() {
|
||||
gpxLayer.enabled(!gpxLayer.enabled());
|
||||
dispatch.change();
|
||||
};
|
||||
|
||||
background.showsMapillaryImageLayer = function() {
|
||||
return mapillaryImageLayer && mapillaryImageLayer.enable();
|
||||
};
|
||||
|
||||
background.showsMapillarySignLayer = function() {
|
||||
return mapillarySignLayer && mapillarySignLayer.enable();
|
||||
};
|
||||
|
||||
background.toggleMapillaryImageLayer = function() {
|
||||
if (!mapillaryImageLayer) return;
|
||||
mapillaryImageLayer.enable(!mapillaryImageLayer.enable());
|
||||
dispatch.change();
|
||||
};
|
||||
|
||||
background.toggleMapillarySignLayer = function() {
|
||||
if (!mapillarySignLayer) return;
|
||||
mapillarySignLayer.enable(!mapillarySignLayer.enable());
|
||||
dispatch.change();
|
||||
};
|
||||
|
||||
background.showsLayer = function(d) {
|
||||
return d === baseLayer.source() ||
|
||||
(d.id === 'custom' && baseLayer.source().id === 'custom') ||
|
||||
@@ -285,7 +199,8 @@ iD.Background = function(context) {
|
||||
});
|
||||
|
||||
if (q.gpx) {
|
||||
gpxLayer.url(q.gpx);
|
||||
var gpx = context.layers().layer('gpx');
|
||||
if (gpx) { gpx.url(q.gpx); }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -19,8 +19,9 @@ iD.Map = function(context) {
|
||||
drawAreas = iD.svg.Areas(projection),
|
||||
drawMidpoints = iD.svg.Midpoints(projection, context),
|
||||
drawLabels = iD.svg.Labels(projection, context),
|
||||
surface,
|
||||
supersurface,
|
||||
wrapper,
|
||||
surface,
|
||||
mouse,
|
||||
mousemove;
|
||||
|
||||
@@ -42,13 +43,11 @@ iD.Map = function(context) {
|
||||
|
||||
// Need a wrapper div because Opera can't cope with an absolutely positioned
|
||||
// SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
|
||||
var wrap = supersurface
|
||||
wrapper = supersurface
|
||||
.append('div')
|
||||
.attr('class', 'layer layer-data');
|
||||
|
||||
map.layers = drawLayers;
|
||||
|
||||
map.surface = surface = wrap
|
||||
map.surface = surface = wrapper
|
||||
.call(drawLayers)
|
||||
.selectAll('.surface')
|
||||
.attr('id', 'surface');
|
||||
@@ -226,7 +225,7 @@ iD.Map = function(context) {
|
||||
editOff();
|
||||
}
|
||||
|
||||
surface
|
||||
wrapper
|
||||
.call(drawLayers);
|
||||
|
||||
transformStart = [
|
||||
@@ -484,5 +483,7 @@ iD.Map = function(context) {
|
||||
return map;
|
||||
};
|
||||
|
||||
map.layers = drawLayers;
|
||||
|
||||
return d3.rebind(map, dispatch, 'on');
|
||||
};
|
||||
|
||||
+15
-10
@@ -99,30 +99,35 @@ iD.svg.Gpx = function(projection, context) {
|
||||
drawGpx.showLabels = function(_) {
|
||||
if (!arguments.length) return showLabels;
|
||||
showLabels = _;
|
||||
return drawGpx;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawGpx.enabled = function(_) {
|
||||
if (!arguments.length) return iD.svg.Gpx.enabled;
|
||||
iD.svg.Gpx.enabled = _;
|
||||
return drawGpx;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawGpx.hasGpx = function() {
|
||||
var geojson = iD.svg.Gpx.geojson;
|
||||
return (!(_.isEmpty(geojson) || _.isEmpty(geojson.features)));
|
||||
};
|
||||
|
||||
drawGpx.geojson = function(gj) {
|
||||
if (!arguments.length) return iD.svg.Gpx.geojson;
|
||||
if (_.isEmpty(gj) || _.isEmpty(gj.features)) return drawGpx;
|
||||
if (_.isEmpty(gj) || _.isEmpty(gj.features)) return this;
|
||||
iD.svg.Gpx.geojson = gj;
|
||||
return drawGpx;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawGpx.url = function(url) {
|
||||
d3.text(url, function(err, data) {
|
||||
if (!err) {
|
||||
drawGpx.geojson(toGeoJSON.gpx(toDom(data)));
|
||||
this.geojson(toGeoJSON.gpx(toDom(data)));
|
||||
redraw();
|
||||
}
|
||||
});
|
||||
return drawGpx;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawGpx.files = function(fileList) {
|
||||
@@ -130,17 +135,17 @@ iD.svg.Gpx = function(projection, context) {
|
||||
reader = new FileReader();
|
||||
|
||||
reader.onload = function(e) {
|
||||
drawGpx.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
|
||||
this.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
|
||||
redraw();
|
||||
};
|
||||
|
||||
reader.readAsText(f);
|
||||
return drawGpx;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawGpx.fitZoom = function() {
|
||||
if (!this.hasGpx()) return this;
|
||||
var geojson = iD.svg.Gpx.geojson;
|
||||
if (_.isEmpty(geojson) || _.isEmpty(geojson.features)) return drawGpx;
|
||||
|
||||
var map = context.map(),
|
||||
viewport = map.trimmedExtent().polygon(),
|
||||
@@ -154,7 +159,7 @@ iD.svg.Gpx = function(projection, context) {
|
||||
map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
|
||||
}
|
||||
|
||||
return drawGpx;
|
||||
return this;
|
||||
};
|
||||
|
||||
init();
|
||||
|
||||
+15
-14
@@ -1,10 +1,10 @@
|
||||
iD.svg.Layers = function(projection, context) {
|
||||
var svg = d3.select(null),
|
||||
layers = [
|
||||
{ id: 'osm', render: iD.svg.Osm(projection, context) },
|
||||
{ id: 'gpx', render: iD.svg.Gpx(projection, context) },
|
||||
{ id: 'mapillary-images', render: iD.svg.MapillaryImages(projection, context) },
|
||||
{ id: 'mapillary-signs', render: iD.svg.MapillarySigns(projection, context) }
|
||||
{ id: 'osm', layer: iD.svg.Osm(projection, context) },
|
||||
{ id: 'gpx', layer: iD.svg.Gpx(projection, context) },
|
||||
{ id: 'mapillary-images', layer: iD.svg.MapillaryImages(projection, context) },
|
||||
{ id: 'mapillary-signs', layer: iD.svg.MapillarySigns(projection, context) }
|
||||
];
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ iD.svg.Layers = function(projection, context) {
|
||||
.attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
|
||||
|
||||
groups
|
||||
.each(function(d) { d3.select(this).call(d.render); });
|
||||
.each(function(d) { d3.select(this).call(d.layer); });
|
||||
|
||||
groups.exit()
|
||||
.remove();
|
||||
@@ -36,13 +36,14 @@ iD.svg.Layers = function(projection, context) {
|
||||
};
|
||||
|
||||
drawLayers.layer = function(id) {
|
||||
return _.find(layers, 'id', id);
|
||||
var obj = _.find(layers, 'id', id);
|
||||
return obj && obj.layer;
|
||||
};
|
||||
|
||||
drawLayers.only = function(what) {
|
||||
var arr = [].concat(what);
|
||||
drawLayers.remove(_.difference(_.pluck(layers, 'id'), arr));
|
||||
return drawLayers;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawLayers.remove = function(what) {
|
||||
@@ -50,28 +51,28 @@ iD.svg.Layers = function(projection, context) {
|
||||
arr.forEach(function(id) {
|
||||
layers = _.reject(layers, 'id', id);
|
||||
});
|
||||
return drawLayers;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawLayers.add = function(what) {
|
||||
var arr = [].concat(what);
|
||||
arr.forEach(function(obj) {
|
||||
if ('id' in obj && 'render' in obj) {
|
||||
if ('id' in obj && 'layer' in obj) {
|
||||
layers.push(obj);
|
||||
}
|
||||
});
|
||||
return drawLayers;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawLayers.dimensions = function(_) {
|
||||
if (!arguments.length) return svg.dimensions();
|
||||
svg.dimensions(_);
|
||||
layers.forEach(function(layer) {
|
||||
if (layer.render.dimensions) {
|
||||
layer.render.dimensions(_);
|
||||
layers.forEach(function(obj) {
|
||||
if (obj.layer.dimensions) {
|
||||
obj.layer.dimensions(_);
|
||||
}
|
||||
});
|
||||
return drawLayers;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
iD.svg.MapillaryImages = function(projection, context) {
|
||||
var debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
|
||||
enabled = false,
|
||||
minZoom = 12,
|
||||
layer = d3.select(null),
|
||||
_mapillary;
|
||||
|
||||
|
||||
function init() {
|
||||
if (iD.svg.MapillaryImages.initialized) return; // run once
|
||||
iD.svg.MapillaryImages.enabled = false;
|
||||
iD.svg.MapillaryImages.initialized = true;
|
||||
}
|
||||
|
||||
function getMapillary() {
|
||||
if (iD.services.mapillary && !_mapillary) {
|
||||
_mapillary = iD.services.mapillary().on('loadedImages', debouncedRedraw);
|
||||
@@ -108,7 +114,8 @@ iD.svg.MapillaryImages = function(projection, context) {
|
||||
}
|
||||
|
||||
function drawImages(selection) {
|
||||
var mapillary = getMapillary();
|
||||
var enabled = iD.svg.MapillaryImages.enabled,
|
||||
mapillary = getMapillary();
|
||||
|
||||
layer = selection.selectAll('.layer-mapillary-images')
|
||||
.data(mapillary ? [0] : []);
|
||||
@@ -160,22 +167,27 @@ iD.svg.MapillaryImages = function(projection, context) {
|
||||
}
|
||||
}
|
||||
|
||||
drawImages.enable = function(_) {
|
||||
if (!arguments.length) return enabled;
|
||||
enabled = _;
|
||||
if (enabled) {
|
||||
drawImages.enabled = function(_) {
|
||||
if (!arguments.length) return iD.svg.MapillaryImages.enabled;
|
||||
iD.svg.MapillaryImages.enabled = _;
|
||||
if (iD.svg.MapillaryImages.enabled) {
|
||||
showLayer();
|
||||
} else {
|
||||
hideLayer();
|
||||
}
|
||||
return drawImages;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawImages.supported = function() {
|
||||
return !!getMapillary();
|
||||
};
|
||||
|
||||
drawImages.dimensions = function(_) {
|
||||
if (!arguments.length) return layer.dimensions();
|
||||
layer.dimensions(_);
|
||||
return drawImages;
|
||||
return this;
|
||||
};
|
||||
|
||||
init();
|
||||
return drawImages;
|
||||
};
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
iD.svg.MapillarySigns = function(projection, context) {
|
||||
var debouncedRedraw = _.debounce(function () { context.pan([0,0]); }, 1000),
|
||||
enabled = false,
|
||||
minZoom = 12,
|
||||
layer = d3.select(null),
|
||||
_mapillary;
|
||||
|
||||
|
||||
function init() {
|
||||
if (iD.svg.MapillarySigns.initialized) return; // run once
|
||||
iD.svg.MapillarySigns.enabled = false;
|
||||
iD.svg.MapillarySigns.initialized = true;
|
||||
}
|
||||
|
||||
function getMapillary() {
|
||||
if (iD.services.mapillary && !_mapillary) {
|
||||
_mapillary = iD.services.mapillary().on('loadedSigns', debouncedRedraw);
|
||||
@@ -65,8 +71,7 @@ iD.svg.MapillarySigns = function(projection, context) {
|
||||
var mapillary = getMapillary(),
|
||||
data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []);
|
||||
|
||||
var signs = layer.select('.layer-mapillary-signs')
|
||||
.selectAll('.icon-sign')
|
||||
var signs = layer.selectAll('.icon-sign')
|
||||
.data(data, function(d) { return d.key; });
|
||||
|
||||
// Enter
|
||||
@@ -115,7 +120,8 @@ iD.svg.MapillarySigns = function(projection, context) {
|
||||
}
|
||||
|
||||
function drawSigns(selection) {
|
||||
var mapillary = getMapillary();
|
||||
var enabled = iD.svg.MapillarySigns.enabled,
|
||||
mapillary = getMapillary();
|
||||
|
||||
layer = selection.selectAll('.layer-mapillary-signs')
|
||||
.data(mapillary ? [0] : []);
|
||||
@@ -140,22 +146,28 @@ iD.svg.MapillarySigns = function(projection, context) {
|
||||
}
|
||||
}
|
||||
|
||||
drawSigns.enable = function(_) {
|
||||
if (!arguments.length) return enabled;
|
||||
enabled = _;
|
||||
if (enabled) {
|
||||
drawSigns.enabled = function(_) {
|
||||
if (!arguments.length) return iD.svg.MapillarySigns.enabled;
|
||||
iD.svg.MapillarySigns.enabled = _;
|
||||
if (iD.svg.MapillarySigns.enabled) {
|
||||
showLayer();
|
||||
} else {
|
||||
hideLayer();
|
||||
}
|
||||
return drawSigns;
|
||||
return this;
|
||||
};
|
||||
|
||||
drawSigns.supported = function() {
|
||||
var mapillary = getMapillary();
|
||||
return (mapillary && mapillary.signsSupported());
|
||||
};
|
||||
|
||||
drawSigns.dimensions = function(_) {
|
||||
if (!arguments.length) return layer.dimensions();
|
||||
layer.dimensions(_);
|
||||
return drawSigns;
|
||||
return this;
|
||||
};
|
||||
|
||||
init();
|
||||
return drawSigns;
|
||||
};
|
||||
|
||||
+31
-24
@@ -1,6 +1,7 @@
|
||||
iD.ui.MapData = function(context) {
|
||||
var key = 'F',
|
||||
features = context.features().keys(),
|
||||
layers = context.layers(),
|
||||
fills = ['wireframe', 'partial', 'full'],
|
||||
fillDefault = context.storage('area-fill') || 'partial',
|
||||
fillSelected = fillDefault;
|
||||
@@ -38,30 +39,38 @@ iD.ui.MapData = function(context) {
|
||||
update();
|
||||
}
|
||||
|
||||
function toggleLayer(which) {
|
||||
var layer = layers.layer(which);
|
||||
if (layer) {
|
||||
layer.enabled(!layer.enabled());
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
function clickGpx() {
|
||||
context.background().toggleGpxLayer();
|
||||
update();
|
||||
toggleLayer('gpx');
|
||||
}
|
||||
|
||||
function clickMapillaryImages() {
|
||||
context.background().toggleMapillaryImageLayer();
|
||||
update();
|
||||
toggleLayer('mapillary-images');
|
||||
}
|
||||
|
||||
function clickMapillarySigns() {
|
||||
context.background().toggleMapillarySignLayer();
|
||||
update();
|
||||
toggleLayer('mapillary-signs');
|
||||
}
|
||||
|
||||
|
||||
function drawMapillaryItems(selection) {
|
||||
var mapillary = iD.services.mapillary,
|
||||
supportsMapillaryImages = !!mapillary,
|
||||
supportsMapillarySigns = !!mapillary && mapillary().signsSupported();
|
||||
var mapillaryImages = layers.layer('mapillary-images'),
|
||||
mapillarySigns = layers.layer('mapillary-signs'),
|
||||
supportsMapillaryImages = mapillaryImages && mapillaryImages.supported(),
|
||||
supportsMapillarySigns = mapillarySigns && mapillarySigns.supported(),
|
||||
showsMapillaryImages = supportsMapillaryImages && mapillaryImages.enabled(),
|
||||
showsMapillarySigns = supportsMapillarySigns && mapillarySigns.enabled();
|
||||
|
||||
var mapillaryList = selection
|
||||
.selectAll('.mapillary-list')
|
||||
.data([0]);
|
||||
.selectAll('.mapillary-list')
|
||||
.data([0]);
|
||||
|
||||
// Enter
|
||||
mapillaryList
|
||||
@@ -70,8 +79,8 @@ iD.ui.MapData = function(context) {
|
||||
.attr('class', 'layer-list mapillary-list');
|
||||
|
||||
var mapillaryImageLayerItem = mapillaryList
|
||||
.selectAll('.item-mapillary-images')
|
||||
.data(supportsMapillaryImages ? [0] : []);
|
||||
.selectAll('.item-mapillary-images')
|
||||
.data(supportsMapillaryImages ? [0] : []);
|
||||
|
||||
var enterImages = mapillaryImageLayerItem.enter()
|
||||
.append('li')
|
||||
@@ -91,8 +100,8 @@ iD.ui.MapData = function(context) {
|
||||
|
||||
|
||||
var mapillarySignLayerItem = mapillaryList
|
||||
.selectAll('.item-mapillary-signs')
|
||||
.data(supportsMapillarySigns ? [0] : []);
|
||||
.selectAll('.item-mapillary-signs')
|
||||
.data(supportsMapillarySigns ? [0] : []);
|
||||
|
||||
var enterSigns = mapillarySignLayerItem.enter()
|
||||
.append('li')
|
||||
@@ -111,9 +120,6 @@ iD.ui.MapData = function(context) {
|
||||
.text(t('mapillary_signs.title'));
|
||||
|
||||
// Update
|
||||
var showsMapillaryImages = supportsMapillaryImages && context.background().showsMapillaryImageLayer(),
|
||||
showsMapillarySigns = supportsMapillarySigns && context.background().showsMapillarySignLayer();
|
||||
|
||||
mapillaryImageLayerItem
|
||||
.classed('active', showsMapillaryImages)
|
||||
.selectAll('input')
|
||||
@@ -133,9 +139,13 @@ iD.ui.MapData = function(context) {
|
||||
|
||||
|
||||
function drawGpxItem(selection) {
|
||||
var gpx = layers.layer('gpx'),
|
||||
hasGpx = gpx && gpx.hasGpx(),
|
||||
showsGpx = hasGpx && gpx.enabled();
|
||||
|
||||
var gpxLayerItem = selection
|
||||
.selectAll('.layer-gpx')
|
||||
.data([0]);
|
||||
.data(gpx ? [0] : []);
|
||||
|
||||
// Enter
|
||||
var enter = gpxLayerItem.enter()
|
||||
@@ -152,7 +162,7 @@ iD.ui.MapData = function(context) {
|
||||
.on('click', function() {
|
||||
d3.event.preventDefault();
|
||||
d3.event.stopPropagation();
|
||||
context.background().gpxLayer().fitZoom();
|
||||
gpx.fitZoom();
|
||||
})
|
||||
.call(iD.svg.Icon('#icon-search'));
|
||||
|
||||
@@ -165,7 +175,7 @@ iD.ui.MapData = function(context) {
|
||||
d3.select(document.createElement('input'))
|
||||
.attr('type', 'file')
|
||||
.on('change', function() {
|
||||
context.background().gpxLayer().files(d3.event.target.files);
|
||||
gpx.files(d3.event.target.files);
|
||||
})
|
||||
.node().click();
|
||||
})
|
||||
@@ -184,9 +194,6 @@ iD.ui.MapData = function(context) {
|
||||
.text(t('gpx.local_layer'));
|
||||
|
||||
// Update
|
||||
var hasGpx = context.background().hasGpxLayer(),
|
||||
showsGpx = context.background().showsGpxLayer();
|
||||
|
||||
gpxLayerItem
|
||||
.classed('active', showsGpx)
|
||||
.selectAll('input')
|
||||
|
||||
Reference in New Issue
Block a user