diff --git a/modules/modes/select.js b/modules/modes/select.js index 93c9e1036..8f216387c 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -477,6 +477,8 @@ export function modeSelect(context, selectedIDs) { var loc = extent.center(); context.map().centerEase(loc); + } else { + context.map().pan([0,0]); } timeout = window.setTimeout(function() { diff --git a/modules/renderer/map.js b/modules/renderer/map.js index b51bdd475..8c5cc16ff 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -42,7 +42,7 @@ export function rendererMap(context) { drawLayers = svgLayers(projection, context), drawPoints = svgPoints(projection, context), drawVertices = svgVertices(projection, context), - drawLines = svgLines(projection), + drawLines = svgLines(projection, context), drawAreas = svgAreas(projection, context), drawMidpoints = svgMidpoints(projection, context), drawLabels = svgLabels(projection, context), diff --git a/modules/svg/lines.js b/modules/svg/lines.js index f88174a1a..da8d93c24 100644 --- a/modules/svg/lines.js +++ b/modules/svg/lines.js @@ -11,7 +11,7 @@ import { osmEntity, osmSimpleMultipolygonOuterMember } from '../osm/index'; import { utilDetect } from '../util/detect'; -export function svgLines(projection) { +export function svgLines(projection, context) { var detected = utilDetect(); var highway_stack = { @@ -29,15 +29,45 @@ export function svgLines(projection) { footway: 11 }; + function waystack(a, b) { - var as = 0, bs = 0; - if (a.tags.highway) { as -= highway_stack[a.tags.highway]; } - if (b.tags.highway) { bs -= highway_stack[b.tags.highway]; } - return as - bs; + var selected = context.selectedIDs(), + scoreA = selected.indexOf(a.id) !== -1 ? 20 : 0, + scoreB = selected.indexOf(b.id) !== -1 ? 20 : 0; + + if (a.tags.highway) { scoreA -= highway_stack[a.tags.highway]; } + if (b.tags.highway) { scoreB -= highway_stack[b.tags.highway]; } + return scoreA - scoreB; } return function drawLines(selection, graph, entities, filter) { + + + function drawLineGroup(selection, klass, data) { + var lines = selection + .selectAll('path') + .filter(filter) + .data(data, osmEntity.key); + + lines.exit() + .remove(); + + // Optimization: call simple TagClasses only on enter selection. This + // works because osmEntity.key is defined to include the entity v attribute. + lines.enter() + .append('path') + .attr('class', function(d) { return 'way line ' + klass + ' ' + d.id; }) + .call(svgTagClasses()) + .merge(lines) + .sort(waystack) + .attr('d', getPath) + .call(svgTagClasses().tags(svgRelationMemberTags(graph))); + + return selection; + } + + var ways = [], pathdata = {}, onewaydata = {}, getPath = svgPath(projection, graph); @@ -77,7 +107,7 @@ export function svgLines(projection) { var linegroup = layergroup .selectAll('g.linegroup') - .data(['shadow', 'casing', 'stroke']); + .data(['shadow', 'casing', 'stroke', 'shadow2', 'casing2', 'stroke2']); linegroup = linegroup.enter() .append('g') @@ -85,27 +115,64 @@ export function svgLines(projection) { .merge(linegroup); - var lines = linegroup - .selectAll('path') - .filter(filter) - .data( - function() { return pathdata[this.parentNode.__data__] || []; }, - osmEntity.key - ); + layergroup.selectAll('g.line-shadow') + .call(drawLineGroup, 'shadow', function() { + var data = pathdata[this.parentNode.__data__] || []; + return data.filter(function(d) { return context.selectedIDs().indexOf(d.id) === -1; }); + }); + layergroup.selectAll('g.line-casing') + .call(drawLineGroup, 'casing', function() { + var data = pathdata[this.parentNode.__data__] || []; + return data.filter(function(d) { return context.selectedIDs().indexOf(d.id) === -1; }); + }); + layergroup.selectAll('g.line-stroke') + .call(drawLineGroup, 'stroke', function() { + var data = pathdata[this.parentNode.__data__] || []; + return data.filter(function(d) { return context.selectedIDs().indexOf(d.id) === -1; }); + }); + layergroup.selectAll('g.line-shadow2') + .call(drawLineGroup, 'shadow', function() { + var data = pathdata[this.parentNode.__data__] || []; + return data.filter(function(d) { return context.selectedIDs().indexOf(d.id) !== -1; }); + }); + layergroup.selectAll('g.line-casing2') + .call(drawLineGroup, 'casing', function() { + var data = pathdata[this.parentNode.__data__] || []; + return data.filter(function(d) { return context.selectedIDs().indexOf(d.id) !== -1; }); + }); + layergroup.selectAll('g.line-stroke2') + .call(drawLineGroup, 'stroke', function() { + var data = pathdata[this.parentNode.__data__] || []; + return data.filter(function(d) { return context.selectedIDs().indexOf(d.id) !== -1; }); + }); + + + // var lines = linegroup + // .selectAll('path') + // .filter(filter) + // .data( + // function() { + // var data = pathdata[this.parentNode.__data__] || []; + // return data.filter(function(d) { return context.selectedIDs().indexOf(d.id) === -1; }); + // }, + // osmEntity.key + // ); + + // lines.exit() + // .remove(); + + // // Optimization: call simple TagClasses only on enter selection. This + // // works because osmEntity.key is defined to include the entity v attribute. + // lines.enter() + // .append('path') + // .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; }) + // .call(svgTagClasses()) + // .merge(lines) + // .sort(waystack) + // .attr('d', getPath) + // .call(svgTagClasses().tags(svgRelationMemberTags(graph))); - lines.exit() - .remove(); - // Optimization: call simple TagClasses only on enter selection. This - // works because osmEntity.key is defined to include the entity v attribute. - lines.enter() - .append('path') - .attr('class', function(d) { return 'way line ' + this.parentNode.__data__ + ' ' + d.id; }) - .call(svgTagClasses()) - .merge(lines) - .sort(waystack) - .attr('d', getPath) - .call(svgTagClasses().tags(svgRelationMemberTags(graph))); var onewaygroup = layergroup diff --git a/test/spec/svg/lines.js b/test/spec/svg/lines.js index 001e12cc6..805d5f400 100644 --- a/test/spec/svg/lines.js +++ b/test/spec/svg/lines.js @@ -22,7 +22,7 @@ describe('iD.svgLines', function () { line = iD.Way({nodes: [a.id, b.id]}), graph = iD.Graph([a, b, line]); - surface.call(iD.svgLines(projection), graph, [line], all); + surface.call(iD.svgLines(projection, context), graph, [line], all); expect(surface.select('path.way')).to.be.classed('way'); expect(surface.select('path.line')).to.be.classed('line'); @@ -34,7 +34,7 @@ describe('iD.svgLines', function () { line = iD.Way({nodes: [a.id, b.id], tags: {highway: 'residential'}}), graph = iD.Graph([a, b, line]); - surface.call(iD.svgLines(projection), graph, [line], all); + surface.call(iD.svgLines(projection, context), graph, [line], all); expect(surface.select('.line')).to.be.classed('tag-highway'); expect(surface.select('.line')).to.be.classed('tag-highway-residential'); @@ -47,7 +47,7 @@ describe('iD.svgLines', function () { relation = iD.Relation({members: [{id: line.id}], tags: {type: 'multipolygon', natural: 'wood'}}), graph = iD.Graph([a, b, line, relation]); - surface.call(iD.svgLines(projection), graph, [line], all); + surface.call(iD.svgLines(projection, context), graph, [line], all); expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); @@ -60,7 +60,7 @@ describe('iD.svgLines', function () { r = iD.Relation({members: [{id: w.id}], tags: {type: 'multipolygon'}}), graph = iD.Graph([a, b, c, w, r]); - surface.call(iD.svgLines(projection), graph, [w], all); + surface.call(iD.svgLines(projection, context), graph, [w], all); expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); @@ -74,7 +74,7 @@ describe('iD.svgLines', function () { r = iD.Relation({members: [{id: o.id, role: 'outer'}, {id: i.id, role: 'inner'}], tags: {type: 'multipolygon'}}), graph = iD.Graph([a, b, c, o, i, r]); - surface.call(iD.svgLines(projection), graph, [i], all); + surface.call(iD.svgLines(projection, context), graph, [i], all); expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); @@ -90,7 +90,7 @@ describe('iD.svgLines', function () { ]); it('stacks higher lines above lower ones in a single render', function () { - surface.call(iD.svgLines(projection), graph, [graph.entity('lo'), graph.entity('hi')], none); + surface.call(iD.svgLines(projection, context), graph, [graph.entity('lo'), graph.entity('hi')], none); var selection = surface.selectAll('g.line-stroke > path.line'); expect(selection.nodes()[0].__data__.id).to.eql('lo'); @@ -98,7 +98,7 @@ describe('iD.svgLines', function () { }); it('stacks higher lines above lower ones in a single render (reverse)', function () { - surface.call(iD.svgLines(projection), graph, [graph.entity('hi'), graph.entity('lo')], none); + surface.call(iD.svgLines(projection, context), graph, [graph.entity('hi'), graph.entity('lo')], none); var selection = surface.selectAll('g.line-stroke > path.line'); expect(selection.nodes()[0].__data__.id).to.eql('lo'); @@ -106,8 +106,8 @@ describe('iD.svgLines', function () { }); it('stacks higher lines above lower ones in separate renders', function () { - surface.call(iD.svgLines(projection), graph, [graph.entity('lo')], none); - surface.call(iD.svgLines(projection), graph, [graph.entity('hi')], none); + surface.call(iD.svgLines(projection, context), graph, [graph.entity('lo')], none); + surface.call(iD.svgLines(projection, context), graph, [graph.entity('hi')], none); var selection = surface.selectAll('g.line-stroke > path.line'); expect(selection.nodes()[0].__data__.id).to.eql('lo'); @@ -115,8 +115,8 @@ describe('iD.svgLines', function () { }); it('stacks higher lines above lower in separate renders (reverse)', function () { - surface.call(iD.svgLines(projection), graph, [graph.entity('hi')], none); - surface.call(iD.svgLines(projection), graph, [graph.entity('lo')], none); + surface.call(iD.svgLines(projection, context), graph, [graph.entity('hi')], none); + surface.call(iD.svgLines(projection, context), graph, [graph.entity('lo')], none); var selection = surface.selectAll('g.line-stroke > path.line'); expect(selection.nodes()[0].__data__.id).to.eql('lo');