Merge pull request #3001 from openstreetmap/data-layer-refactor2

Data layer refactor
This commit is contained in:
Bryan Housel
2016-02-27 23:10:06 -05:00
38 changed files with 662 additions and 573 deletions
+1 -1
View File
@@ -296,7 +296,7 @@ correspondence with entities:
two vertices.
* `iD.svg.Labels` renders the textual
[labels](http://mapbox.com/osmdev/2013/02/12/labeling-id/).
* `iD.svg.Surface` sets up a number of layers that ensure that map elements
* `iD.svg.Layers` sets up a number of layers that ensure that map elements
appear in an appropriate z-order.
## Other UI
+2 -2
View File
@@ -2132,7 +2132,7 @@ div.full-screen > button:hover {
user-select: none;
}
#supersurface, .layer-layer {
#supersurface, .layer {
position: absolute;
top: 0;
left: 0;
@@ -2208,7 +2208,7 @@ div.full-screen > button:hover {
border-bottom: 1px solid black;
}
.infobox .selection-heading {
.infobox .infobox-heading {
display: block;
border-radius: 4px 0 0 0;
padding: 5px 10px;
+5 -5
View File
@@ -24,11 +24,11 @@ img.tile-removing {
use { pointer-events: none; }
/* base styles */
.layer path:not(.oneway) { fill: none; } /* IE needs :not(.oneway) */
.layer-osm path:not(.oneway) { fill: none; } /* IE needs :not(.oneway) */
/* the above fill: none rule affects paths in <use> shadow dom only in Firefox */
.layer use.icon path { fill: #333; } /* FF svg Maki icons */
.layer .turn use path { fill: #000; } /* FF turn restriction icons */
.layer-osm use.icon path { fill: #333; } /* FF svg Maki icons */
.layer-osm .turn use path { fill: #000; } /* FF turn restriction icons */
#turn-only-shape2, #turn-only-u-shape2 { fill: #7092FF; } /* FF turn-only, turn-only-u */
#turn-no-shape2, #turn-no-u-shape2 { fill: #E06D5F; } /* FF turn-no, turn-no-u */
#turn-yes-shape2, #turn-yes-u-shape2 { fill: #8CD05F; } /* FF turn-yes, turn-yes-u */
@@ -1268,7 +1268,7 @@ path.shadow.tag-cutting {
/* Surface - unpaved */
path.casing.tag-unpaved {
stroke: #eaeaea;
stroke: #ccc;
stroke-linecap: butt;
stroke-dasharray: 4, 3;
}
@@ -1500,7 +1500,7 @@ g.turn circle {
}
/* GPX Paths */
div.layer-gpx {
.layer-gpx {
pointer-events: none;
}
+6 -5
View File
@@ -56,21 +56,22 @@
<script src='js/id/renderer/background.js'></script>
<script src='js/id/renderer/background_source.js'></script>
<script src='js/id/renderer/features.js'></script>
<script src='js/id/renderer/gpx_layer.js'></script>
<script src='js/id/renderer/tile_layer.js'></script>
<script src='js/id/renderer/map.js'></script>
<script src='js/id/renderer/mapillary_image_layer.js'></script>
<script src='js/id/renderer/mapillary_sign_layer.js'></script>
<script src='js/id/renderer/tile_layer.js'></script>
<script src="js/id/svg.js"></script>
<script src="js/id/svg/areas.js"></script>
<script src="js/id/svg/defs.js"></script>
<script src='js/id/svg/gpx.js'></script>
<script src="js/id/svg/icon.js"></script>
<script src="js/id/svg/labels.js"></script>
<script src="js/id/svg/lines.js"></script>
<script src='js/id/svg/mapillary_images.js'></script>
<script src='js/id/svg/mapillary_signs.js'></script>
<script src="js/id/svg/midpoints.js"></script>
<script src="js/id/svg/osm.js"></script>
<script src="js/id/svg/points.js"></script>
<script src="js/id/svg/surface.js"></script>
<script src="js/id/svg/layers.js"></script>
<script src="js/id/svg/tag_classes.js"></script>
<script src="js/id/svg/turns.js"></script>
<script src="js/id/svg/vertices.js"></script>
+13 -138
View File
@@ -1,11 +1,6 @@
iD.Background = function(context) {
var dispatch = d3.dispatch('change'),
baseLayer = iD.TileLayer()
.projection(context.projection),
gpxLayer = iD.GpxLayer(context, dispatch)
.projection(context.projection),
mapillaryImageLayer,
mapillarySignLayer,
baseLayer = iD.TileLayer().projection(context.projection),
overlayLayers = [];
var backgroundSources;
@@ -49,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');
}
@@ -57,19 +53,21 @@ iD.Background = function(context) {
}
function background(selection) {
var base = selection.selectAll('.background-layer')
var base = selection.selectAll('.layer-background')
.data([0]);
base.enter().insert('div', '.layer-data')
.attr('class', 'layer-layer background-layer');
base.enter()
.insert('div', '.layer-data')
.attr('class', 'layer layer-background');
base.call(baseLayer);
var overlays = selection.selectAll('.layer-overlay')
.data(overlayLayers, function(d) { return d.source().name(); });
overlays.enter().insert('div', '.layer-data')
.attr('class', 'layer-layer layer-overlay');
overlays.enter()
.insert('div', '.layer-data')
.attr('class', 'layer layer-overlay');
overlays.each(function(layer) {
d3.select(this).call(layer);
@@ -77,52 +75,6 @@ iD.Background = function(context) {
overlays.exit()
.remove();
var gpx = selection.selectAll('.layer-gpx')
.data([0]);
gpx.enter().insert('div')
.attr('class', 'layer-layer layer-gpx');
gpx.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.MapillaryImageLayer(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.MapillarySignLayer(context); }
mapillarySigns.call(mapillarySignLayer);
} else {
mapillarySignLayer = null;
}
mapillarySigns.exit()
.remove();
}
background.sources = function(extent) {
@@ -133,9 +85,6 @@ iD.Background = function(context) {
background.dimensions = function(_) {
baseLayer.dimensions(_);
gpxLayer.dimensions(_);
if (mapillaryImageLayer) mapillaryImageLayer.dimensions(_);
if (mapillarySignLayer) mapillarySignLayer.dimensions(_);
overlayLayers.forEach(function(layer) {
layer.dimensions(_);
@@ -156,74 +105,6 @@ iD.Background = function(context) {
background.baseLayerSource(findSource('Bing'));
};
background.hasGpxLayer = function() {
return !_.isEmpty(gpxLayer.geojson());
};
background.showsGpxLayer = function() {
return background.hasGpxLayer() && gpxLayer.enable();
};
function toDom(x) {
return (new DOMParser()).parseFromString(x, 'text/xml');
}
background.gpxLayerFiles = function(fileList) {
var f = fileList[0],
reader = new FileReader();
reader.onload = function(e) {
gpxLayer.geojson(toGeoJSON.gpx(toDom(e.target.result)));
iD.ui.MapInMap.gpxLayer.geojson(toGeoJSON.gpx(toDom(e.target.result)));
background.zoomToGpxLayer();
dispatch.change();
};
reader.readAsText(f);
};
background.zoomToGpxLayer = function() {
if (background.hasGpxLayer()) {
var map = context.map(),
viewport = map.trimmedExtent().polygon(),
coords = _.reduce(gpxLayer.geojson().features, function(coords, feature) {
var c = feature.geometry.coordinates;
return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
}, []);
if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
var extent = iD.geo.Extent(d3.geo.bounds(gpxLayer.geojson()));
map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
}
}
};
background.toggleGpxLayer = function() {
gpxLayer.enable(!gpxLayer.enable());
iD.ui.MapInMap.gpxLayer.enable(!iD.ui.MapInMap.gpxLayer.enable());
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') ||
@@ -317,15 +198,9 @@ iD.Background = function(context) {
if (overlay) background.toggleOverlayLayer(overlay);
});
var gpx = q.gpx;
if (gpx) {
d3.text(gpx, function(err, gpxTxt) {
if (!err) {
gpxLayer.geojson(toGeoJSON.gpx(toDom(gpxTxt)));
iD.ui.MapInMap.gpxLayer.geojson(toGeoJSON.gpx(toDom(gpxTxt)));
dispatch.change();
}
});
if (q.gpx) {
var gpx = context.layers().layer('gpx');
if (gpx) { gpx.url(q.gpx); }
}
};
-101
View File
@@ -1,101 +0,0 @@
iD.GpxLayer = function(context) {
var projection,
gj = {},
enable = true,
svg;
function render(selection) {
svg = selection.selectAll('svg')
.data([render]);
svg.enter()
.append('svg');
svg.style('display', enable ? 'block' : 'none');
var paths = svg
.selectAll('path')
.data([gj]);
paths
.enter()
.append('path')
.attr('class', 'gpx');
var path = d3.geo.path()
.projection(projection);
paths
.attr('d', path);
if (typeof gj.features !== 'undefined') {
svg
.selectAll('text')
.remove();
svg
.selectAll('path')
.data(gj.features)
.enter()
.append('text')
.attr('class', 'gpx')
.text(function(d) {
return d.properties.desc || d.properties.name;
})
.attr('x', function(d) {
var centroid = path.centroid(d);
return centroid[0] + 5;
})
.attr('y', function(d) {
var centroid = path.centroid(d);
return centroid[1];
});
}
}
render.projection = function(_) {
if (!arguments.length) return projection;
projection = _;
return render;
};
render.enable = function(_) {
if (!arguments.length) return enable;
enable = _;
return render;
};
render.geojson = function(_) {
if (!arguments.length) return gj;
gj = _;
return render;
};
render.dimensions = function(_) {
if (!arguments.length) return svg.dimensions();
svg.dimensions(_);
return render;
};
render.id = 'layer-gpx';
function over() {
d3.event.stopPropagation();
d3.event.preventDefault();
d3.event.dataTransfer.dropEffect = 'copy';
}
d3.select('body')
.attr('dropzone', 'copy')
.on('drop.localgpx', function() {
d3.event.stopPropagation();
d3.event.preventDefault();
if (!iD.detect().filedrop) return;
context.background().gpxLayerFiles(d3.event.dataTransfer.files);
})
.on('dragenter.localgpx', over)
.on('dragexit.localgpx', over)
.on('dragover.localgpx', over);
return render;
};
+60 -47
View File
@@ -12,13 +12,16 @@ iD.Map = function(context) {
transformStart,
transformed = false,
minzoom = 0,
points = iD.svg.Points(projection, context),
vertices = iD.svg.Vertices(projection, context),
lines = iD.svg.Lines(projection),
areas = iD.svg.Areas(projection),
midpoints = iD.svg.Midpoints(projection, context),
labels = iD.svg.Labels(projection, context),
supersurface, surface,
drawLayers = iD.svg.Layers(projection, context),
drawPoints = iD.svg.Points(projection, context),
drawVertices = iD.svg.Vertices(projection, context),
drawLines = iD.svg.Lines(projection),
drawAreas = iD.svg.Areas(projection),
drawMidpoints = iD.svg.Midpoints(projection, context),
drawLabels = iD.svg.Labels(projection, context),
supersurface,
wrapper,
surface,
mouse,
mousemove;
@@ -35,18 +38,21 @@ iD.Map = function(context) {
.call(zoom);
supersurface = selection.append('div')
.attr('id', 'supersurface');
// Mapillary streetsigns require supersurface transform to have
// a value in order to do correct foreignObject positioning in Chrome
iD.util.setTransform(supersurface, 0, 0);
.attr('id', 'supersurface')
.call(iD.util.setTransform, 0, 0);
// Need a wrapper div because Opera can't cope with an absolutely positioned
// SVG element: http://bl.ocks.org/jfirebaugh/6fbfbd922552bf776c16
var dataLayer = supersurface.append('div')
.attr('class', 'layer-layer layer-data');
wrapper = supersurface
.append('div')
.attr('class', 'layer layer-data');
map.surface = surface = dataLayer.append('svg')
map.surface = surface = wrapper
.call(drawLayers)
.selectAll('.surface')
.attr('id', 'surface');
surface
.on('mousedown.zoom', function() {
if (d3.event.button === 2) {
d3.event.stopPropagation();
@@ -55,30 +61,28 @@ iD.Map = function(context) {
.on('mouseup.zoom', function() {
if (resetTransform()) redraw();
})
.attr('id', 'surface')
.call(iD.svg.Surface(context));
.on('mousemove.map', function() {
mousemove = d3.event;
})
.on('mouseover.vertices', function() {
if (map.editable() && !transformed) {
var hover = d3.event.target.__data__;
surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
dispatch.drawn({full: false});
}
})
.on('mouseout.vertices', function() {
if (map.editable() && !transformed) {
var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
surface.call(drawVertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
dispatch.drawn({full: false});
}
});
supersurface.call(context.background());
surface.on('mousemove.map', function() {
mousemove = d3.event;
});
supersurface
.call(context.background());
surface.on('mouseover.vertices', function() {
if (map.editable() && !transformed) {
var hover = d3.event.target.__data__;
surface.call(vertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
dispatch.drawn({full: false});
}
});
surface.on('mouseout.vertices', function() {
if (map.editable() && !transformed) {
var hover = d3.event.relatedTarget && d3.event.relatedTarget.__data__;
surface.call(vertices.drawHover, context.graph(), hover, map.extent(), map.zoom());
dispatch.drawn({full: false});
}
});
context.on('enter.map', function() {
if (map.editable() && !transformed) {
@@ -87,15 +91,16 @@ iD.Map = function(context) {
graph = context.graph();
all = context.features().filter(all, graph);
surface.call(vertices, graph, all, filter, map.extent(), map.zoom());
surface.call(midpoints, graph, all, filter, map.trimmedExtent());
surface
.call(drawVertices, graph, all, filter, map.extent(), map.zoom())
.call(drawMidpoints, graph, all, filter, map.trimmedExtent());
dispatch.drawn({full: false});
}
});
map.dimensions(selection.dimensions());
labels.supersurface(supersurface);
drawLabels.supersurface(supersurface);
}
function pxCenter() { return [dimensions[0] / 2, dimensions[1] / 2]; }
@@ -133,19 +138,19 @@ iD.Map = function(context) {
data = features.filter(data, graph);
surface
.call(vertices, graph, data, filter, map.extent(), map.zoom())
.call(lines, graph, data, filter)
.call(areas, graph, data, filter)
.call(midpoints, graph, data, filter, map.trimmedExtent())
.call(labels, graph, data, filter, dimensions, !difference && !extent)
.call(points, data, filter);
.call(drawVertices, graph, data, filter, map.extent(), map.zoom())
.call(drawLines, graph, data, filter)
.call(drawAreas, graph, data, filter)
.call(drawMidpoints, graph, data, filter, map.trimmedExtent())
.call(drawLabels, graph, data, filter, dimensions, !difference && !extent)
.call(drawPoints, graph, data, filter);
dispatch.drawn({full: true});
}
function editOff() {
context.features().resetStats();
surface.selectAll('.layer *').remove();
surface.selectAll('.layer-osm *').remove();
dispatch.drawn({full: true});
}
@@ -185,6 +190,8 @@ iD.Map = function(context) {
function resetTransform() {
if (!transformed) return false;
surface.selectAll('.radial-menu').interrupt().remove();
iD.util.setTransform(supersurface, 0, 0);
transformed = false;
return true;
@@ -212,6 +219,7 @@ iD.Map = function(context) {
supersurface.call(context.background());
}
// OSM
if (map.editable()) {
context.loadTiles(projection, dimensions);
drawVector(difference, extent);
@@ -219,6 +227,9 @@ iD.Map = function(context) {
editOff();
}
wrapper
.call(drawLayers);
transformStart = [
projection.scale() * 2 * Math.PI,
projection.translate().slice()];
@@ -328,7 +339,7 @@ iD.Map = function(context) {
if (!arguments.length) return dimensions;
var center = map.center();
dimensions = _;
surface.dimensions(dimensions);
drawLayers.dimensions(dimensions);
context.background().dimensions(dimensions);
projection.clipExtent([[0, 0], dimensions]);
mouse = iD.util.fastMouse(supersurface.node());
@@ -474,5 +485,7 @@ iD.Map = function(context) {
return map;
};
map.layers = drawLayers;
return d3.rebind(map, dispatch, 'on');
};
+1 -1
View File
@@ -82,7 +82,7 @@ iD.svg.Areas = function(projection) {
.remove();
var areagroup = surface
.select('.layer-areas')
.selectAll('.layer-areas')
.selectAll('g.areagroup')
.data(['fill', 'shadow', 'stroke']);
+1 -1
View File
@@ -15,7 +15,7 @@ iD.svg.Defs = function(context) {
};
}
return function (selection) {
return function drawDefs(selection) {
var defs = selection.append('defs');
// marker
+167
View File
@@ -0,0 +1,167 @@
iD.svg.Gpx = function(projection, context) {
var showLabels = true,
layer;
function init() {
if (iD.svg.Gpx.initialized) return; // run once
iD.svg.Gpx.geojson = {};
iD.svg.Gpx.enabled = true;
function over() {
d3.event.stopPropagation();
d3.event.preventDefault();
d3.event.dataTransfer.dropEffect = 'copy';
}
d3.select('body')
.attr('dropzone', 'copy')
.on('drop.localgpx', function() {
d3.event.stopPropagation();
d3.event.preventDefault();
if (!iD.detect().filedrop) return;
drawGpx.files(d3.event.dataTransfer.files);
})
.on('dragenter.localgpx', over)
.on('dragexit.localgpx', over)
.on('dragover.localgpx', over);
iD.svg.Gpx.initialized = true;
}
function drawGpx(surface) {
var geojson = iD.svg.Gpx.geojson,
enabled = iD.svg.Gpx.enabled;
layer = surface.selectAll('.layer-gpx')
.data(enabled ? [0] : []);
layer.enter()
.append('g')
.attr('class', 'layer-gpx');
layer.exit()
.remove();
var paths = layer
.selectAll('path')
.data([geojson]);
paths.enter()
.append('path')
.attr('class', 'gpx');
paths.exit()
.remove();
var path = d3.geo.path()
.projection(projection);
paths
.attr('d', path);
var labels = layer.selectAll('text')
.data(showLabels && geojson.features ? geojson.features : []);
labels.enter()
.append('text')
.attr('class', 'gpx')
.text(function(d) {
return d.properties.desc || d.properties.name;
});
labels.exit()
.remove();
labels
.attr('x', function(d) {
var centroid = path.centroid(d);
return centroid[0] + 7;
})
.attr('y', function(d) {
var centroid = path.centroid(d);
return centroid[1];
});
}
function toDom(x) {
return (new DOMParser()).parseFromString(x, 'text/xml');
}
function redraw() {
context.pan([0,0]);
}
drawGpx.showLabels = function(_) {
if (!arguments.length) return showLabels;
showLabels = _;
return this;
};
drawGpx.enabled = function(_) {
if (!arguments.length) return iD.svg.Gpx.enabled;
iD.svg.Gpx.enabled = _;
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 this;
iD.svg.Gpx.geojson = gj;
return this;
};
drawGpx.url = function(url) {
d3.text(url, function(err, data) {
if (!err) {
this.geojson(toGeoJSON.gpx(toDom(data)));
redraw();
}
});
return this;
};
drawGpx.files = function(fileList) {
var f = fileList[0],
reader = new FileReader();
reader.onload = function(e) {
this.geojson(toGeoJSON.gpx(toDom(e.target.result))).fitZoom();
redraw();
};
reader.readAsText(f);
return this;
};
drawGpx.fitZoom = function() {
if (!this.hasGpx()) return this;
var geojson = iD.svg.Gpx.geojson;
var map = context.map(),
viewport = map.trimmedExtent().polygon(),
coords = _.reduce(geojson.features, function(coords, feature) {
var c = feature.geometry.coordinates;
return _.union(coords, feature.geometry.type === 'Point' ? [c] : c);
}, []);
if (!iD.geo.polygonIntersectsPolygon(viewport, coords, true)) {
var extent = iD.geo.Extent(d3.geo.bounds(geojson));
map.centerZoom(extent.center(), map.trimmedExtentZoom(extent));
}
return this;
};
init();
return drawGpx;
};
+1 -1
View File
@@ -1,5 +1,5 @@
iD.svg.Icon = function(name, svgklass, useklass) {
return function (selection) {
return function drawIcon(selection) {
selection.selectAll('svg')
.data([0])
.enter()
+6 -8
View File
@@ -131,7 +131,6 @@ iD.svg.Labels = function(projection, context) {
}
function drawPointLabels(group, entities, filter, classes, labels) {
var texts = group.selectAll('text.' + classes)
.filter(filter)
.data(entities, iD.Entity.key);
@@ -248,9 +247,8 @@ iD.svg.Labels = function(projection, context) {
var rtree = rbush(),
rectangles = {};
function labels(surface, graph, entities, filter, dimensions, fullRedraw) {
var hidePoints = !surface.select('.node.point').node();
function drawLabels(surface, graph, entities, filter, dimensions, fullRedraw) {
var hidePoints = !surface.selectAll('.node.point').node();
var labelable = [], i, k, entity;
for (i = 0; i < label_stack.length; i++) labelable.push([]);
@@ -409,8 +407,8 @@ iD.svg.Labels = function(projection, context) {
return v;
}
var label = surface.select('.layer-label'),
halo = surface.select('.layer-halo');
var label = surface.selectAll('.layer-label'),
halo = surface.selectAll('.layer-halo');
// points
drawPointLabels(label, labelled.point, filter, 'pointlabel', positions.point);
@@ -427,7 +425,7 @@ iD.svg.Labels = function(projection, context) {
drawAreaIcons(label, labelled.area, filter, 'arealabel-icon', positions.area);
}
labels.supersurface = function(supersurface) {
drawLabels.supersurface = function(supersurface) {
supersurface
.on('mousemove.hidelabels', hideOnMouseover)
.on('mousedown.hidelabels', function () {
@@ -438,5 +436,5 @@ iD.svg.Labels = function(projection, context) {
});
};
return labels;
return drawLabels;
};
+80
View File
@@ -0,0 +1,80 @@
iD.svg.Layers = function(projection, context) {
var svg = d3.select(null),
layers = [
{ 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) }
];
function drawLayers(selection) {
svg = selection.selectAll('.surface')
.data([0]);
svg.enter()
.append('svg')
.attr('class', 'surface')
.append('defs');
var groups = svg.selectAll('.data-layer')
.data(layers);
groups.enter()
.append('g')
.attr('class', function(d) { return 'data-layer data-layer-' + d.id; });
groups
.each(function(d) { d3.select(this).call(d.layer); });
groups.exit()
.remove();
}
drawLayers.all = function() {
return layers;
};
drawLayers.layer = function(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 this;
};
drawLayers.remove = function(what) {
var arr = [].concat(what);
arr.forEach(function(id) {
layers = _.reject(layers, 'id', id);
});
return this;
};
drawLayers.add = function(what) {
var arr = [].concat(what);
arr.forEach(function(obj) {
if ('id' in obj && 'layer' in obj) {
layers.push(obj);
}
});
return this;
};
drawLayers.dimensions = function(_) {
if (!arguments.length) return svg.dimensions();
svg.dimensions(_);
layers.forEach(function(obj) {
if (obj.layer.dimensions) {
obj.layer.dimensions(_);
}
});
return this;
};
return drawLayers;
};
+1 -1
View File
@@ -50,7 +50,7 @@ iD.svg.Lines = function(projection) {
});
var layergroup = surface
.select('.layer-lines')
.selectAll('.layer-lines')
.selectAll('g.layergroup')
.data(d3.range(-10, 11));
@@ -1,10 +1,16 @@
iD.MapillaryImageLayer = function(context) {
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);
@@ -19,7 +25,7 @@ iD.MapillaryImageLayer = function(context) {
if (!mapillary) return;
var thumb = mapillary.selectedThumbnail(),
posX = context.projection(image.loc)[0],
posX = projection(image.loc)[0],
width = layer.dimensions()[0],
position = (posX < width / 2) ? 'right' : 'left';
@@ -71,14 +77,14 @@ iD.MapillaryImageLayer = function(context) {
}
function transform(d) {
var t = iD.svg.PointTransform(context.projection)(d);
var t = iD.svg.PointTransform(projection)(d);
if (d.ca) t += ' rotate(' + Math.floor(d.ca) + ',0,0)';
return t;
}
function drawMarkers() {
function update() {
var mapillary = getMapillary(),
data = (mapillary ? mapillary.images(context.projection, layer.dimensions()) : []);
data = (mapillary ? mapillary.images(projection, layer.dimensions()) : []);
var markers = layer.selectAll('.viewfield-group')
.data(data, function(d) { return d.key; });
@@ -107,16 +113,17 @@ iD.MapillaryImageLayer = function(context) {
.attr('transform', transform);
}
function render(selection) {
var mapillary = getMapillary();
function drawImages(selection) {
var enabled = iD.svg.MapillaryImages.enabled,
mapillary = getMapillary();
layer = selection.selectAll('svg')
layer = selection.selectAll('.layer-mapillary-images')
.data(mapillary ? [0] : []);
layer.enter()
.append('svg')
.append('g')
.attr('class', 'layer-mapillary-images')
.style('display', enabled ? 'block' : 'none')
.dimensions(context.map().dimensions())
.on('click', function() { // deselect/select
var mapillary = getMapillary();
if (!mapillary) return;
@@ -152,31 +159,35 @@ iD.MapillaryImageLayer = function(context) {
if (enabled) {
if (mapillary && ~~context.map().zoom() >= minZoom) {
editOn();
drawMarkers();
mapillary.loadImages(context.projection, layer.dimensions());
update();
mapillary.loadImages(projection, layer.dimensions());
} else {
editOff();
}
}
}
render.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 render;
return this;
};
render.dimensions = function(_) {
if (layer.empty()) return null;
drawImages.supported = function() {
return !!getMapillary();
};
drawImages.dimensions = function(_) {
if (!arguments.length) return layer.dimensions();
layer.dimensions(_);
return render;
return this;
};
return render;
init();
return drawImages;
};
@@ -1,10 +1,16 @@
iD.MapillarySignLayer = function(context) {
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);
@@ -19,7 +25,7 @@ iD.MapillarySignLayer = function(context) {
if (!mapillary) return;
var thumb = mapillary.selectedThumbnail(),
posX = context.projection(image.loc)[0],
posX = projection(image.loc)[0],
width = layer.dimensions()[0],
position = (posX < width / 2) ? 'right' : 'left';
@@ -61,12 +67,11 @@ iD.MapillarySignLayer = function(context) {
layer.style('display', 'none');
}
function drawSigns() {
function update() {
var mapillary = getMapillary(),
data = (mapillary ? mapillary.signs(context.projection, layer.dimensions()) : []);
data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []);
var signs = layer.select('.mapillary-sign-offset')
.selectAll('.icon-sign')
var signs = layer.selectAll('.icon-sign')
.data(data, function(d) { return d.key; });
// Enter
@@ -111,21 +116,20 @@ iD.MapillarySignLayer = function(context) {
// Update
signs
.attr('transform', iD.svg.PointTransform(context.projection));
.attr('transform', iD.svg.PointTransform(projection));
}
function render(selection) {
var mapillary = getMapillary();
function drawSigns(selection) {
var enabled = iD.svg.MapillarySigns.enabled,
mapillary = getMapillary();
layer = selection.selectAll('svg')
layer = selection.selectAll('.layer-mapillary-signs')
.data(mapillary ? [0] : []);
layer.enter()
.append('svg')
.style('display', enabled ? 'block' : 'none')
.dimensions(context.map().dimensions())
.append('g')
.attr('class', 'mapillary-sign-offset')
.attr('class', 'layer-mapillary-signs')
.style('display', enabled ? 'block' : 'none')
.attr('transform', 'translate(-16, -16)'); // center signs on loc
layer.exit()
@@ -134,31 +138,36 @@ iD.MapillarySignLayer = function(context) {
if (enabled) {
if (mapillary && ~~context.map().zoom() >= minZoom) {
editOn();
drawSigns();
mapillary.loadSigns(context, context.projection, layer.dimensions());
update();
mapillary.loadSigns(context, projection, layer.dimensions());
} else {
editOff();
}
}
}
render.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 render;
return this;
};
render.dimensions = function(_) {
if (layer.empty()) return null;
drawSigns.supported = function() {
var mapillary = getMapillary();
return (mapillary && mapillary.signsSupported());
};
drawSigns.dimensions = function(_) {
if (!arguments.length) return layer.dimensions();
layer.dimensions(_);
return render;
return this;
};
return render;
init();
return drawSigns;
};
+1 -1
View File
@@ -67,7 +67,7 @@ iD.svg.Midpoints = function(projection, context) {
return false;
}
var groups = surface.select('.layer-hit').selectAll('g.midpoint')
var groups = surface.selectAll('.layer-hit').selectAll('g.midpoint')
.filter(midpointFilter)
.data(_.values(midpoints), function(d) { return d.id; });
+9
View File
@@ -0,0 +1,9 @@
iD.svg.Osm = function() {
return function drawOsm(selection) {
var layers = selection.selectAll('.layer-osm')
.data(['areas', 'lines', 'hit', 'halo', 'label']);
layers.enter().append('g')
.attr('class', function(d) { return 'layer-osm layer-' + d; });
};
};
+4 -5
View File
@@ -10,16 +10,15 @@ iD.svg.Points = function(projection, context) {
return b.loc[1] - a.loc[1];
}
return function drawPoints(surface, entities, filter) {
var graph = context.graph(),
wireframe = surface.classed('fill-wireframe'),
return function drawPoints(surface, graph, entities, filter) {
var wireframe = surface.classed('fill-wireframe'),
points = wireframe ? [] : _.filter(entities, function(e) {
return e.geometry(graph) === 'point';
});
points.sort(sortY);
var groups = surface.select('.layer-hit').selectAll('g.point')
var groups = surface.selectAll('.layer-hit').selectAll('g.point')
.filter(filter)
.data(points, iD.Entity.key);
@@ -49,7 +48,7 @@ iD.svg.Points = function(projection, context) {
groups.select('.stroke');
groups.select('.icon')
.attr('xlink:href', function(entity) {
var preset = context.presets().match(entity, context.graph());
var preset = context.presets().match(entity, graph);
return preset.icon ? '#' + preset.icon + '-12' : '';
});
-14
View File
@@ -1,14 +0,0 @@
iD.svg.Surface = function() {
return function (selection) {
selection.selectAll('defs')
.data([0])
.enter()
.append('defs');
var layers = selection.selectAll('.layer')
.data(['areas', 'lines', 'hit', 'halo', 'label']);
layers.enter().append('g')
.attr('class', function(d) { return 'layer layer-' + d; });
};
};
+2 -2
View File
@@ -1,5 +1,5 @@
iD.svg.Turns = function(projection) {
return function(surface, graph, turns) {
return function drawTurns(surface, graph, turns) {
function key(turn) {
return [turn.from.node + turn.via.node + turn.to.node].join('-');
}
@@ -13,7 +13,7 @@ iD.svg.Turns = function(projection) {
(!turn.indirect_restriction && /^only_/.test(restriction) ? 'only' : 'no') + u;
}
var groups = surface.select('.layer-hit').selectAll('g.turn')
var groups = surface.selectAll('.layer-hit').selectAll('g.turn')
.data(turns, key);
// Enter
+9 -19
View File
@@ -48,19 +48,10 @@ iD.svg.Vertices = function(projection, context) {
function draw(selection, vertices, klass, graph, zoom) {
var icons = {},
z;
z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);
if (zoom < 17) {
z = 0;
} else if (zoom < 18) {
z = 1;
} else {
z = 2;
}
var groups = selection.data(vertices, function(entity) {
return iD.Entity.key(entity);
});
var groups = selection
.data(vertices, iD.Entity.key);
function icon(entity) {
if (entity.id in icons) return icons[entity.id];
@@ -162,7 +153,7 @@ iD.svg.Vertices = function(projection, context) {
}
}
surface.select('.layer-hit').selectAll('g.vertex.vertex-persistent')
surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-persistent')
.filter(filter)
.call(draw, vertices, 'vertex-persistent', graph, zoom);
@@ -172,15 +163,14 @@ iD.svg.Vertices = function(projection, context) {
function drawHover(surface, graph, extent, zoom) {
var hovered = hover ? siblingAndChildVertices([hover.id], graph, extent) : {};
surface.select('.layer-hit').selectAll('g.vertex.vertex-hover')
surface.selectAll('.layer-hit').selectAll('g.vertex.vertex-hover')
.call(draw, d3.values(hovered), 'vertex-hover', graph, zoom);
}
drawVertices.drawHover = function(surface, graph, _, extent, zoom) {
if (hover !== _) {
hover = _;
drawHover(surface, graph, extent, zoom);
}
drawVertices.drawHover = function(surface, graph, target, extent, zoom) {
if (target === hover) return;
hover = target;
drawHover(surface, graph, extent, zoom);
};
return drawVertices;
+4 -8
View File
@@ -28,18 +28,14 @@ iD.ui = function(context) {
.attr('id', 'bar')
.attr('class', 'fillD');
var m = content.append('div')
content.append('div')
.attr('id', 'map')
.call(map);
content.append('div')
.attr('class', 'map-in-map')
.style('display', 'none')
content
.call(iD.ui.MapInMap(context));
content.append('div')
.attr('class', 'infobox fillD2')
.style('display', 'none')
.call(iD.ui.Info(context));
bar.append('div')
@@ -169,8 +165,8 @@ iD.ui = function(context) {
var mapDimensions = map.dimensions();
d3.select(window).on('resize.editor', function() {
mapDimensions = m.dimensions();
map.dimensions(m.dimensions());
mapDimensions = content.dimensions(null);
map.dimensions(mapDimensions);
});
function pan(d) {
+1 -1
View File
@@ -24,7 +24,7 @@ iD.ui.Background = function(context) {
}
function setOpacity(d) {
var bg = context.container().selectAll('.background-layer')
var bg = context.container().selectAll('.layer-background')
.transition()
.style('opacity', d)
.attr('data-opacity', d);
+25 -18
View File
@@ -1,7 +1,11 @@
iD.ui.Contributors = function(context) {
function update(selection) {
var debouncedUpdate = _.debounce(function() { update(); }, 1000),
limit = 4,
hidden = false,
wrap = d3.select(null);
function update() {
var users = {},
limit = 4,
entities = context.intersects(context.map().extent());
entities.forEach(function(entity) {
@@ -11,7 +15,7 @@ iD.ui.Contributors = function(context) {
var u = Object.keys(users),
subset = u.slice(0, u.length > limit ? limit - 1 : limit);
selection.html('')
wrap.html('')
.call(iD.svg.Icon('#icon-nearby', 'pre-text light'));
var userList = d3.select(document.createElement('span'));
@@ -37,29 +41,32 @@ iD.ui.Contributors = function(context) {
})
.text(u.length - limit + 1);
selection.append('span')
.html(t('contributors.truncated_list', {users: userList.html(), count: count.html()}));
wrap.append('span')
.html(t('contributors.truncated_list', { users: userList.html(), count: count.html() }));
} else {
selection.append('span')
.html(t('contributors.list', {users: userList.html()}));
wrap.append('span')
.html(t('contributors.list', { users: userList.html() }));
}
if (!u.length) {
selection.transition().style('opacity', 0);
} else if (selection.style('opacity') === '0') {
selection.transition().style('opacity', 1);
hidden = true;
wrap
.transition()
.style('opacity', 0);
} else if (hidden) {
wrap
.transition()
.style('opacity', 1);
}
}
return function(selection) {
update(selection);
wrap = selection;
update();
context.connection().on('loaded.contributors', function() {
update(selection);
});
context.map().on('move.contributors', _.debounce(function() {
update(selection);
}, 500));
context.connection().on('loaded.contributors', debouncedUpdate);
context.map().on('move.contributors', debouncedUpdate);
};
};
+31 -25
View File
@@ -1,6 +1,7 @@
iD.ui.Info = function(context) {
var key = iD.ui.cmd('⌘I'),
imperial = (iD.detect().locale.toLowerCase() === 'en-us');
imperial = (iD.detect().locale.toLowerCase() === 'en-us'),
hidden = true;
function info(selection) {
function radiansToMeters(r) {
@@ -95,7 +96,7 @@ iD.ui.Info = function(context) {
function redraw() {
if (hidden()) return;
if (hidden) return;
var resolver = context.graph(),
selected = _.filter(context.selectedIDs(), function(e) { return context.hasEntity(e); }),
@@ -103,9 +104,9 @@ iD.ui.Info = function(context) {
extent = iD.geo.Extent(),
entity;
selection.html('');
selection.append('h4')
.attr('class', 'selection-heading fillD')
wrap.html('');
wrap.append('h4')
.attr('class', 'infobox-heading fillD')
.text(singular || t('infobox.selected', { n: selected.length }));
if (!selected.length) return;
@@ -118,16 +119,16 @@ iD.ui.Info = function(context) {
center = extent.center();
var list = selection.append('ul');
var list = wrap.append('ul');
// multiple selection, just display extent center..
// multiple wrap, just display extent center..
if (!singular) {
list.append('li')
.text(t('infobox.center') + ': ' + center[0].toFixed(5) + ', ' + center[1].toFixed(5));
return;
}
// single selection, display details..
// single wrap, display details..
if (!entity) return;
var geometry = entity.geometry(resolver);
@@ -156,7 +157,7 @@ iD.ui.Info = function(context) {
var toggle = imperial ? 'imperial' : 'metric';
selection.append('a')
wrap.append('a')
.text(t('infobox.' + toggle))
.attr('href', '#')
.attr('class', 'button')
@@ -178,26 +179,13 @@ iD.ui.Info = function(context) {
}
function hidden() {
return selection.style('display') === 'none';
}
function toggle() {
if (d3.event) d3.event.preventDefault();
if (hidden()) {
selection
.style('display', 'block')
.style('opacity', 0)
.transition()
.duration(200)
.style('opacity', 1);
hidden = !hidden;
redraw();
} else {
selection
if (hidden) {
wrap
.style('display', 'block')
.style('opacity', 1)
.transition()
@@ -206,9 +194,27 @@ iD.ui.Info = function(context) {
.each('end', function() {
d3.select(this).style('display', 'none');
});
} else {
wrap
.style('display', 'block')
.style('opacity', 0)
.transition()
.duration(200)
.style('opacity', 1);
redraw();
}
}
var wrap = selection.selectAll('.infobox')
.data([0]);
wrap.enter()
.append('div')
.attr('class', 'infobox fillD2')
.style('display', (hidden ? 'none' : 'block'));
context.map()
.on('drawn.info', redraw);
+33 -27
View File
@@ -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,10 +139,13 @@ iD.ui.MapData = function(context) {
function drawGpxItem(selection) {
var supportsGpx = iD.detect().filedrop,
gpxLayerItem = selection
.selectAll('.layer-gpx')
.data(supportsGpx ? [0] : []);
var gpx = layers.layer('gpx'),
hasGpx = gpx && gpx.hasGpx(),
showsGpx = hasGpx && gpx.enabled();
var gpxLayerItem = selection
.selectAll('.layer-gpx')
.data(gpx ? [0] : []);
// Enter
var enter = gpxLayerItem.enter()
@@ -153,7 +162,7 @@ iD.ui.MapData = function(context) {
.on('click', function() {
d3.event.preventDefault();
d3.event.stopPropagation();
context.background().zoomToGpxLayer();
gpx.fitZoom();
})
.call(iD.svg.Icon('#icon-search'));
@@ -166,7 +175,7 @@ iD.ui.MapData = function(context) {
d3.select(document.createElement('input'))
.attr('type', 'file')
.on('change', function() {
context.background().gpxLayerFiles(d3.event.target.files);
gpx.files(d3.event.target.files);
})
.node().click();
})
@@ -185,9 +194,6 @@ iD.ui.MapData = function(context) {
.text(t('gpx.local_layer'));
// Update
var hasGpx = supportsGpx && context.background().hasGpxLayer(),
showsGpx = supportsGpx && context.background().showsGpxLayer();
gpxLayerItem
.classed('active', showsGpx)
.selectAll('input')
+39 -45
View File
@@ -2,21 +2,18 @@ iD.ui.MapInMap = function(context) {
var key = '/';
function map_in_map(selection) {
var backgroundLayer = iD.TileLayer(),
overlayLayers = {},
dispatch = d3.dispatch('change'),
gpxLayer = iD.GpxLayer(context, dispatch),
projection = iD.geo.RawMercator(),
gpxLayer = iD.svg.Gpx(projection, context).showLabels(false),
zoom = d3.behavior.zoom()
.scaleExtent([ztok(0.5), ztok(24)])
.on('zoom', zoomPan),
transformed = false,
panning = false,
hidden = true,
zDiff = 6, // by default, minimap renders at (main zoom - 6)
tStart, tLast, tCurr, kLast, kCurr, tiles, svg, gpx, timeoutId;
iD.ui.MapInMap.gpxLayer = gpxLayer;
tStart, tLast, tCurr, kLast, kCurr, tiles, svg, timeoutId;
function ztok(z) { return 256 * Math.pow(2, z); }
function ktoz(k) { return Math.log(k) / Math.LN2 - 8; }
@@ -72,7 +69,7 @@ iD.ui.MapInMap = function(context) {
panning = false;
if (tCurr[0] !== tStart[0] && tCurr[1] !== tStart[1]) {
var dMini = selection.dimensions(),
var dMini = wrap.dimensions(),
cMini = [ dMini[0] / 2, dMini[1] / 2 ];
context.map().center(projection.invert(cMini));
@@ -82,7 +79,7 @@ iD.ui.MapInMap = function(context) {
function updateProjection() {
var loc = context.map().center(),
dMini = selection.dimensions(),
dMini = wrap.dimensions(),
cMini = [ dMini[0] / 2, dMini[1] / 2 ],
tMain = context.projection.translate(),
kMain = context.projection.scale(),
@@ -122,15 +119,15 @@ iD.ui.MapInMap = function(context) {
function redraw() {
if (hidden()) return;
if (hidden) return;
updateProjection();
var dMini = selection.dimensions(),
var dMini = wrap.dimensions(),
zMini = ktoz(projection.scale() * 2 * Math.PI);
// setup tile container
tiles = selection
tiles = wrap
.selectAll('.map-in-map-tiles')
.data([0]);
@@ -156,6 +153,7 @@ iD.ui.MapInMap = function(context) {
background
.call(backgroundLayer);
// redraw overlay
var overlaySources = context.background().overlayLayerSources();
var activeOverlayLayers = [];
@@ -189,27 +187,27 @@ iD.ui.MapInMap = function(context) {
overlays.exit()
.remove();
// redraw gpx overlay
gpxLayer
.projection(projection);
gpx = tiles
var gpx = tiles
.selectAll('.map-in-map-gpx')
.data([0]);
.data(gpxLayer.enabled() ? [0] : []);
gpx.enter()
.append('div')
.append('svg')
.attr('class', 'map-in-map-gpx');
gpx.exit()
.remove();
gpx.call(gpxLayer);
gpx.dimensions(dMini);
// redraw bounding box
if (!panning) {
var getPath = d3.geo.path().projection(projection),
bbox = { type: 'Polygon', coordinates: [context.map().extent().polygon()] };
svg = selection.selectAll('.map-in-map-svg')
svg = wrap.selectAll('.map-in-map-svg')
.data([0]);
svg.enter()
@@ -236,31 +234,17 @@ iD.ui.MapInMap = function(context) {
}
function hidden() {
return selection.style('display') === 'none';
}
function toggle() {
if (d3.event) d3.event.preventDefault();
hidden = !hidden;
var label = d3.select('.minimap-toggle');
label.classed('active', !hidden)
.select('input').property('checked', !hidden);
if (hidden()) {
selection
.style('display', 'block')
.style('opacity', 0)
.transition()
.duration(200)
.style('opacity', 1);
label.classed('active', true)
.select('input').property('checked', true);
redraw();
} else {
selection
if (hidden) {
wrap
.style('display', 'block')
.style('opacity', 1)
.transition()
@@ -269,19 +253,29 @@ iD.ui.MapInMap = function(context) {
.each('end', function() {
d3.select(this).style('display', 'none');
});
} else {
wrap
.style('display', 'block')
.style('opacity', 0)
.transition()
.duration(200)
.style('opacity', 1);
label.classed('active', false)
.select('input').property('checked', false);
redraw();
}
}
iD.ui.MapInMap.toggle = toggle;
selection
.on('mousedown.map-in-map', startMouse)
.on('mouseup.map-in-map', endMouse);
var wrap = selection.selectAll('.map-in-map')
.data([0]);
selection
wrap.enter()
.append('div')
.attr('class', 'map-in-map')
.style('display', (hidden ? 'none' : 'block'))
.on('mousedown.map-in-map', startMouse)
.on('mouseup.map-in-map', endMouse)
.call(zoom)
.on('dblclick.zoom', null);
+50 -16
View File
@@ -1,36 +1,39 @@
iD.ui.preset.restrictions = function(field, context) {
var dispatch = d3.dispatch('change'),
hover = iD.behavior.Hover(context),
vertexID,
fromNodeID;
function restrictions(selection) {
// if form field is hidden or has detached from dom, clean up.
if (!d3.select('.inspector-wrap.inspector-hidden').empty() || !selection.node().parentNode) {
selection.call(restrictions.off);
return;
}
var wrap = selection.selectAll('.preset-input-wrap')
.data([0]);
var enter = wrap.enter().append('div')
var enter = wrap.enter()
.append('div')
.attr('class', 'preset-input-wrap');
enter.append('div')
enter
.append('div')
.attr('class', 'restriction-help');
enter.append('svg')
.call(iD.svg.Surface(context))
.call(iD.behavior.Hover(context));
var intersection = iD.geo.Intersection(context.graph(), vertexID),
graph = intersection.graph,
vertex = graph.entity(vertexID),
surface = wrap.selectAll('svg'),
filter = function () { return true; },
filter = d3.functor(true),
extent = iD.geo.Extent(),
projection = iD.geo.RawMercator(),
lines = iD.svg.Lines(projection, context),
vertices = iD.svg.Vertices(projection, context),
turns = iD.svg.Turns(projection, context);
projection = iD.geo.RawMercator();
var d = wrap.dimensions(),
c = [d[0] / 2, d[1] / 2],
z = 21;
z = 24;
projection
.scale(256 * Math.pow(2, z) / (2 * Math.PI));
@@ -41,10 +44,24 @@ iD.ui.preset.restrictions = function(field, context) {
.translate([c[0] - s[0], c[1] - s[1]])
.clipExtent([[0, 0], d]);
var drawLayers = iD.svg.Layers(projection, context).only('osm').dimensions(d),
drawVertices = iD.svg.Vertices(projection, context),
drawLines = iD.svg.Lines(projection, context),
drawTurns = iD.svg.Turns(projection, context);
enter
.call(drawLayers)
.selectAll('.surface')
.call(hover);
var surface = wrap.selectAll('.surface');
surface
.call(vertices, graph, [vertex], filter, extent, z)
.call(lines, graph, intersection.ways, filter)
.call(turns, graph, intersection.turns(fromNodeID));
.dimensions(d)
.call(drawVertices, graph, [vertex], filter, extent, z)
.call(drawLines, graph, intersection.ways, filter)
.call(drawTurns, graph, intersection.turns(fromNodeID));
surface
.on('click.restrictions', click)
@@ -67,7 +84,10 @@ iD.ui.preset.restrictions = function(field, context) {
.on('change.restrictions', render);
d3.select(window)
.on('resize.restrictions', render);
.on('resize.restrictions', function() {
wrap.dimensions(null);
render();
});
function click() {
var datum = d3.event.target.__data__;
@@ -136,5 +156,19 @@ iD.ui.preset.restrictions = function(field, context) {
restrictions.tags = function() {};
restrictions.focus = function() {};
restrictions.off = function(selection) {
selection.selectAll('.surface')
.call(hover.off)
.on('click.restrictions', null)
.on('mouseover.restrictions', null)
.on('mouseout.restrictions', null);
context.history()
.on('change.restrictions', null);
d3.select(window)
.on('resize.restrictions', null);
};
return d3.rebind(restrictions, dispatch, 'on');
};
+18 -12
View File
@@ -1,17 +1,23 @@
d3.selection.prototype.dimensions = function (dimensions) {
if (!arguments.length) {
var node = this.node();
if (!node) return;
var prop = this.property('__dimensions__');
if (!prop) {
var cr = node.getBoundingClientRect();
prop = [cr.width, cr.height];
this.property('__dimensions__', prop);
}
var refresh = (function(node) {
var cr = node.getBoundingClientRect();
prop = [cr.width, cr.height];
this.property('__dimensions__', prop);
return prop;
}).bind(this);
var node = this.node();
if (!arguments.length) {
if (!node) return [0,0];
return this.property('__dimensions__') || refresh(node);
}
if (dimensions === null) {
if (!node) return [0,0];
return refresh(node);
}
this.property('__dimensions__', [dimensions[0], dimensions[1]]);
return this.attr({width: dimensions[0], height: dimensions[1]});
return this
.property('__dimensions__', [dimensions[0], dimensions[1]])
.attr({width: dimensions[0], height: dimensions[1]});
};
+5 -4
View File
@@ -62,20 +62,21 @@
<script src='../js/id/renderer/background_source.js'></script>
<script src='../js/id/renderer/features.js'></script>
<script src='../js/id/renderer/map.js'></script>
<script src='../js/id/renderer/gpx_layer.js'></script>
<script src='../js/id/renderer/tile_layer.js'></script>
<script src='../js/id/renderer/mapillary_image_layer.js'></script>
<script src='../js/id/renderer/mapillary_sign_layer.js'></script>
<script src="../js/id/svg.js"></script>
<script src="../js/id/svg/areas.js"></script>
<script src="../js/id/svg/defs.js"></script>
<script src='../js/id/svg/gpx.js'></script>
<script src="../js/id/svg/icon.js"></script>
<script src="../js/id/svg/labels.js"></script>
<script src="../js/id/svg/lines.js"></script>
<script src='../js/id/svg/mapillary_images.js'></script>
<script src='../js/id/svg/mapillary_signs.js'></script>
<script src="../js/id/svg/midpoints.js"></script>
<script src="../js/id/svg/osm.js"></script>
<script src="../js/id/svg/points.js"></script>
<script src="../js/id/svg/surface.js"></script>
<script src="../js/id/svg/layers.js"></script>
<script src="../js/id/svg/tag_classes.js"></script>
<script src="../js/id/svg/turns.js"></script>
<script src="../js/id/svg/vertices.js"></script>
+6 -5
View File
@@ -21,8 +21,9 @@
<script src="../js/id/svg/icon.js"></script>
<script src="../js/id/svg/lines.js"></script>
<script src="../js/id/svg/midpoints.js"></script>
<script src="../js/id/svg/osm.js"></script>
<script src="../js/id/svg/points.js"></script>
<script src="../js/id/svg/surface.js"></script>
<script src="../js/id/svg/layers.js"></script>
<script src="../js/id/svg/tag_classes.js"></script>
<script src="../js/id/svg/vertices.js"></script>
@@ -146,7 +147,7 @@
.attr('width', 30)
.attr('height', 40)
.attr('data-zoom', function (d) { return d.zoom; })
.call(iD.svg.Surface(context))
.call(iD.svg.Layers(context))
.each(function (d) {
var n = node.update({tags: d}),
graph = iD.Graph([n]);
@@ -214,7 +215,7 @@
.attr('width', 30)
.attr('height', 30)
.attr('data-zoom', function (d) { return d.zoom; })
.call(iD.svg.Surface(context))
.call(iD.svg.Layers(context))
.each(function (d) {
var n = node.update({tags: d.tags}),
graph = iD.Graph([n, way]);
@@ -302,7 +303,7 @@
.attr('width', 200)
.attr('height', 30)
.attr('data-zoom', function (d) { return d.zoom; })
.call(iD.svg.Surface(context))
.call(iD.svg.Layers(context))
.each(function (d) {
var highway = way.update({tags: d.tags}),
graph = iD.Graph([a, b, highway]);
@@ -364,7 +365,7 @@
.append('svg')
.attr('width', 100)
.attr('height', 100)
.call(iD.svg.Surface(context))
.call(iD.svg.Layers(context))
.each(function (datum) {
var area = way.update({tags: datum.tags}),
graph = iD.Graph([a, b, c, d, area]);
+5 -5
View File
@@ -15,7 +15,7 @@ describe("iD.behavior.Select", function() {
.append('div')
.attr('class', 'inspector-wrap');
context.surface().selectAll('circle')
context.surface().select('.data-layer-osm').selectAll('circle')
.data([a, b])
.enter().append('circle')
.attr('class', function(d) { return d.id; });
@@ -33,7 +33,7 @@ describe("iD.behavior.Select", function() {
});
specify("click on entity selects the entity", function() {
happen.click(context.surface().select('.' + a.id).node());
happen.click(context.surface().selectAll('.' + a.id).node());
expect(context.selectedIDs()).to.eql([a.id]);
});
@@ -45,19 +45,19 @@ describe("iD.behavior.Select", function() {
specify("shift-click on unselected entity adds it to the selection", function() {
context.enter(iD.modes.Select(context, [a.id]));
happen.click(context.surface().select('.' + b.id).node(), {shiftKey: true});
happen.click(context.surface().selectAll('.' + b.id).node(), {shiftKey: true});
expect(context.selectedIDs()).to.eql([a.id, b.id]);
});
specify("shift-click on selected entity removes it from the selection", function() {
context.enter(iD.modes.Select(context, [a.id, b.id]));
happen.click(context.surface().select('.' + b.id).node(), {shiftKey: true});
happen.click(context.surface().selectAll('.' + b.id).node(), {shiftKey: true});
expect(context.selectedIDs()).to.eql([a.id]);
});
specify("shift-click on last selected entity clears the selection", function() {
context.enter(iD.modes.Select(context, [a.id]));
happen.click(context.surface().select('.' + a.id).node(), {shiftKey: true});
happen.click(context.surface().selectAll('.' + a.id).node(), {shiftKey: true});
expect(context.mode().id).to.eql('browse');
});
+1 -1
View File
@@ -7,7 +7,7 @@ describe("iD.svg.Areas", function () {
beforeEach(function () {
surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.call(iD.svg.Surface(iD()));
.call(iD.svg.Layers(iD()));
});
it("adds way and area classes", function () {
+1 -1
View File
@@ -7,7 +7,7 @@ describe("iD.svg.Lines", function () {
beforeEach(function () {
surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.call(iD.svg.Surface(iD()));
.call(iD.svg.Layers(iD()));
});
it("adds way and line classes", function () {
+1 -1
View File
@@ -7,7 +7,7 @@ describe("iD.svg.Midpoints", function () {
beforeEach(function () {
context = iD();
surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.call(iD.svg.Surface(context));
.call(iD.svg.Layers(context));
});
it("creates midpoint on segment completely within the extent", function () {
+4 -3
View File
@@ -6,13 +6,14 @@ describe("iD.svg.Points", function () {
beforeEach(function () {
context = iD().presets(iD.data.presets);
surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.call(iD.svg.Surface(context));
.call(iD.svg.Layers(context));
});
it("adds tag classes", function () {
var point = iD.Node({tags: {amenity: "cafe"}, loc: [0, 0]});
var point = iD.Node({tags: {amenity: "cafe"}, loc: [0, 0]}),
graph = iD.Graph([point]);
surface.call(iD.svg.Points(projection, context), [point]);
surface.call(iD.svg.Points(projection, context), graph, [point]);
expect(surface.select('.point')).to.be.classed('tag-amenity');
expect(surface.select('.point')).to.be.classed('tag-amenity-cafe');
+1 -1
View File
@@ -6,7 +6,7 @@ describe("iD.svg.Vertices", function () {
beforeEach(function () {
context = iD();
surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
.call(iD.svg.Surface(context));
.call(iD.svg.Layers(context));
});
it("adds the .shared class to vertices that are members of two or more ways", function () {