diff --git a/css/app.css b/css/app.css index 243b1c43c..79b45a37a 100644 --- a/css/app.css +++ b/css/app.css @@ -2132,7 +2132,7 @@ div.full-screen > button:hover { user-select: none; } -#supersurface, .layer-layer { +#supersurface, .layer { position: absolute; top: 0; left: 0; diff --git a/css/map.css b/css/map.css index 88fcb6003..aadefb962 100644 --- a/css/map.css +++ b/css/map.css @@ -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 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 */ @@ -1500,7 +1500,7 @@ g.turn circle { } /* GPX Paths */ -div.layer-gpx { +.layer-gpx { pointer-events: none; } diff --git a/js/id/renderer/background.js b/js/id/renderer/background.js index 8bed81f87..d04f471f9 100644 --- a/js/id/renderer/background.js +++ b/js/id/renderer/background.js @@ -55,19 +55,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); diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index bb3ca1d50..39492ceaa 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -12,13 +12,15 @@ iD.Map = function(context) { transformStart, transformed = false, minzoom = 0, + drawSurface = iD.svg.Surface(projection, context), 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, + surface, + supersurface, mouse, mousemove; @@ -35,18 +37,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'); + var dataLayer = supersurface + .append('div') + .attr('class', 'layer layer-data'); - map.surface = surface = dataLayer.append('svg') + map.surface = surface = dataLayer + .call(drawSurface) + .select('.surface') + .attr('id', 'surface'); + + surface .on('mousedown.zoom', function() { if (d3.event.button === 2) { d3.event.stopPropagation(); @@ -55,30 +60,28 @@ iD.Map = function(context) { .on('mouseup.zoom', function() { if (resetTransform()) redraw(); }) - .attr('id', 'surface') - .call(iD.svg.Surface(projection, context)); + .on('mousemove.map', function() { + mousemove = d3.event; + }) + .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}); + } + }) + .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}); + } + }); - 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) { @@ -328,7 +331,7 @@ iD.Map = function(context) { if (!arguments.length) return dimensions; var center = map.center(); dimensions = _; - surface.dimensions(dimensions); + drawSurface.dimensions(dimensions); context.background().dimensions(dimensions); projection.clipExtent([[0, 0], dimensions]); mouse = iD.util.fastMouse(supersurface.node()); diff --git a/js/id/svg/gpx.js b/js/id/svg/gpx.js index 8bf4ab9cd..7073b8a26 100644 --- a/js/id/svg/gpx.js +++ b/js/id/svg/gpx.js @@ -40,7 +40,7 @@ iD.svg.Gpx = function(projection, context) { layer.enter() .append('g') - .attr('class', 'layer layer-gpx'); + .attr('class', 'layer-gpx'); layer.exit() .remove(); diff --git a/js/id/svg/mapillary_images.js b/js/id/svg/mapillary_images.js index 075828cd8..3ba2889e9 100644 --- a/js/id/svg/mapillary_images.js +++ b/js/id/svg/mapillary_images.js @@ -110,13 +110,13 @@ iD.svg.MapillaryImages = function(projection, context) { function render(selection) { var 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; @@ -172,7 +172,6 @@ iD.svg.MapillaryImages = function(projection, context) { }; render.dimensions = function(_) { - if (layer.empty()) return null; if (!arguments.length) return layer.dimensions(); layer.dimensions(_); return render; diff --git a/js/id/svg/mapillary_signs.js b/js/id/svg/mapillary_signs.js index 98a25115b..d0648256c 100644 --- a/js/id/svg/mapillary_signs.js +++ b/js/id/svg/mapillary_signs.js @@ -65,7 +65,7 @@ iD.svg.MapillarySigns = function(projection, context) { var mapillary = getMapillary(), data = (mapillary ? mapillary.signs(projection, layer.dimensions()) : []); - var signs = layer.select('.mapillary-sign-offset') + var signs = layer.select('.layer-mapillary-signs') .selectAll('.icon-sign') .data(data, function(d) { return d.key; }); @@ -117,15 +117,13 @@ iD.svg.MapillarySigns = function(projection, context) { function render(selection) { var 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() @@ -154,7 +152,6 @@ iD.svg.MapillarySigns = function(projection, context) { }; render.dimensions = function(_) { - if (layer.empty()) return null; if (!arguments.length) return layer.dimensions(); layer.dimensions(_); return render; diff --git a/js/id/svg/osm.js b/js/id/svg/osm.js index 31ba891ac..72f93bbb8 100644 --- a/js/id/svg/osm.js +++ b/js/id/svg/osm.js @@ -4,6 +4,6 @@ iD.svg.Osm = function() { .data(['areas', 'lines', 'hit', 'halo', 'label']); layers.enter().append('g') - .attr('class', function(d) { return 'layer layer-osm layer-' + d; }); + .attr('class', function(d) { return 'layer-osm layer-' + d; }); }; }; diff --git a/js/id/svg/surface.js b/js/id/svg/surface.js index 06df27eac..2f017622d 100644 --- a/js/id/svg/surface.js +++ b/js/id/svg/surface.js @@ -1,27 +1,30 @@ -iD.svg.Surface = function (projection, context) { - var all = [ - { order: 1, id: 'osm', render: iD.svg.Osm(projection, context) }, - { order: 2, id: 'gpx', render: iD.svg.Gpx(projection, context) }, - { order: 3, id: 'mapillary-images', render: iD.svg.MapillaryImages(projection, context) }, - { order: 4, id: 'mapillary-signs', render: iD.svg.MapillarySigns(projection, context) } - ]; +iD.svg.Surface = 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) } + ]; - function surface (selection) { - selection.selectAll('defs') - .data([0]) - .enter() + function surface(selection) { + svg = selection.selectAll('.surface') + .data([0]); + + svg.enter() + .append('svg') + .attr('class', 'surface') .append('defs'); - var groups = selection.selectAll('.data-layer') - .data(all); + var groups = svg.selectAll('.data-layer') + .data(layers); groups.enter() .append('g') - .attr('class', function(d) { return 'layer data-layer data-layer-' + d.id; }); + .attr('class', function(d) { return 'data-layer data-layer-' + d.id; }); groups - .sort(function(a, b) { return a.order - b.order; }) .each(function(d) { d3.select(this).call(d.render); }); groups.exit() @@ -29,25 +32,36 @@ iD.svg.Surface = function (projection, context) { } - surface.only = function (what) { + surface.only = function(what) { var arr = [].concat(what); - surface.remove(_.difference(_.pluck(all, 'id'), arr)); + surface.remove(_.difference(_.pluck(layers, 'id'), arr)); return surface; }; - surface.remove = function (what) { + surface.remove = function(what) { var arr = [].concat(what); - _.each(arr, function(id) { - all = _.reject(all, function(d) { return d.id === id; }); + arr.forEach(function(id) { + layers = _.reject(layers, function(d) { return d.id === id; }); }); return surface; }; - surface.add = function (what) { + surface.add = function(what) { var arr = [].concat(what); - _.each(arr, function(obj) { - if ('order' in obj && 'id' in obj && 'render' in obj) { - all.push(obj); + arr.forEach(function(obj) { + if ('id' in obj && 'render' in obj) { + layers.push(obj); + } + }); + return surface; + }; + + surface.dimensions = function(_) { + if (!arguments.length) return svg.dimensions(); + svg.dimensions(_); + layers.forEach(function(layer) { + if (layer.render.dimensions) { + layer.render.dimensions(_); } }); return surface; diff --git a/js/id/ui/background.js b/js/id/ui/background.js index adb0a893c..3a2abf730 100644 --- a/js/id/ui/background.js +++ b/js/id/ui/background.js @@ -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); diff --git a/js/id/ui/preset/restrictions.js b/js/id/ui/preset/restrictions.js index 6a57ecbf9..9c5081010 100644 --- a/js/id/ui/preset/restrictions.js +++ b/js/id/ui/preset/restrictions.js @@ -39,14 +39,17 @@ iD.ui.preset.restrictions = function(field, context) { .translate([c[0] - s[0], c[1] - s[1]]) .clipExtent([[0, 0], d]); + enter - .append('svg') - .call(iD.svg.Surface(projection, context).only('osm')) + .call(iD.svg.Surface(projection, context).only('osm').dimensions(d)) + .select('.surface') .call(iD.behavior.Hover(context)); - var surface = wrap.selectAll('svg'); + + var surface = wrap.select('.surface'); surface + .dimensions(d) .call(vertices, graph, [vertex], filter, extent, z) .call(lines, graph, intersection.ways, filter) .call(turns, graph, intersection.turns(fromNodeID)); @@ -72,7 +75,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__;