From 5ee391dd52183d99e901539c8b92eacb953cacb0 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Fri, 30 May 2014 15:20:36 -0400 Subject: [PATCH 1/9] Better layer sorting to fix z-depth issues.. --- js/id/core/way.js | 20 +++++++++++++++ js/id/svg/lines.js | 63 +++++++++++++++++++++++----------------------- 2 files changed, 52 insertions(+), 31 deletions(-) diff --git a/js/id/core/way.js b/js/id/core/way.js index 3a6e6d6ec..9e2d6f0eb 100644 --- a/js/id/core/way.js +++ b/js/id/core/way.js @@ -42,6 +42,26 @@ _.extend(iD.Way.prototype, { if (this.nodes[this.nodes.length - 1] === node) return 'suffix'; }, + layer: function() { + // explicit layer tag.. + if (this.tags.layer !== undefined) return +(this.tags.layer); + + // implied layer tag.. + if (this.tags.location === 'overground') return 1; + if (this.tags.location === 'underground') return -1; + if (this.tags.location === 'underwater') return -10; + + if (this.tags.power === 'line') return 20; + if (this.tags.power === 'minor_line') return 15; + if (this.tags.aerialway) return 10; + if (this.tags.bridge) return 1; + if (this.tags.cutting) return -1; + if (this.tags.tunnel) return -1; + if (this.tags.waterway) return -1; + if (this.tags.manmade === 'pipeline') return -10; + return 0; + }, + isOneWay: function() { // explicit oneway tag.. if (['yes', '1', '-1'].indexOf(this.tags.oneway) !== -1) { return true; } diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index 61b0efbd5..8ea4418a7 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -1,36 +1,36 @@ iD.svg.Lines = function(projection) { - var highway_stack = { - motorway: 0, - motorway_link: 1, - trunk: 2, - trunk_link: 3, - primary: 4, - primary_link: 5, - secondary: 6, - tertiary: 7, - unclassified: 8, - residential: 9, - service: 10, - footway: 11 - }; + // var highway_stack = { + // motorway: 0, + // motorway_link: 1, + // trunk: 2, + // trunk_link: 3, + // primary: 4, + // primary_link: 5, + // secondary: 6, + // tertiary: 7, + // unclassified: 8, + // residential: 9, + // service: 10, + // footway: 11 + // }; - function waystack(a, b) { - if (!a || !b || !a.tags || !b.tags) return 0; - if (a.tags.layer !== undefined && b.tags.layer !== undefined) { - return a.tags.layer - b.tags.layer; - } - if (a.tags.bridge) return 1; - if (b.tags.bridge) return -1; - if (a.tags.tunnel) return -1; - if (b.tags.tunnel) return 1; - var as = 0, bs = 0; - if (a.tags.highway && b.tags.highway) { - as -= highway_stack[a.tags.highway]; - bs -= highway_stack[b.tags.highway]; - } - return as - bs; - } + // function waystack(a, b) { + // if (!a || !b || !a.tags || !b.tags) return 0; + // if (a.tags.layer !== undefined && b.tags.layer !== undefined) { + // return a.tags.layer - b.tags.layer; + // } + // if (a.tags.bridge) return 1; + // if (b.tags.bridge) return -1; + // if (a.tags.tunnel) return -1; + // if (b.tags.tunnel) return 1; + // var as = 0, bs = 0; + // if (a.tags.highway && b.tags.highway) { + // as -= highway_stack[a.tags.highway]; + // bs -= highway_stack[b.tags.highway]; + // } + // return as - bs; + // } return function drawLines(surface, graph, entities, filter) { var lines = [], @@ -47,7 +47,8 @@ iD.svg.Lines = function(projection) { } lines = lines.filter(path); - lines.sort(waystack); + // lines.sort(waystack); + lines.sort(function(a, b) { return a.layer() - b.layer(); }); function drawPaths(klass) { var paths = surface.select('.layer-' + klass) From cfd2b6a619cfd078148e3c340a185b83e3aa7654 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 2 Jun 2014 17:39:51 -0400 Subject: [PATCH 2/9] Group line parts so that they can be properly depth sorted. --- js/id/svg/lines.js | 49 ++++++++++++++++++++++---------------------- js/id/svg/surface.js | 2 +- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index 8ea4418a7..02f7c6994 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -47,39 +47,38 @@ iD.svg.Lines = function(projection) { } lines = lines.filter(path); - // lines.sort(waystack); lines.sort(function(a, b) { return a.layer() - b.layer(); }); - function drawPaths(klass) { - var paths = surface.select('.layer-' + klass) - .selectAll('path.line') - .filter(filter) - .data(lines, iD.Entity.key); + var groups = surface.select('.layer-line') + .selectAll('g') + .filter(filter) + .data(lines, iD.Entity.key); - var enter = paths.enter() + var enter = groups.enter() + .append('g') + .attr('class', function(d) { return d.id; }); + + ['shadow', 'casing', 'stroke'].forEach(function(klass) { + enter .append('path') - .attr('class', function(d) { return 'way line ' + klass + ' ' + d.id; }); + .attr('class', function(d) { return 'way line ' + klass + ' ' + d.id; }) + .call(iD.svg.TagClasses()); + }); - // Optimization: call simple TagClasses only on enter selection. This - // works because iD.Entity.key is defined to include the entity v attribute. - if (klass !== 'stroke') { - enter.call(iD.svg.TagClasses()); - } else { - paths.call(iD.svg.TagClasses() - .tags(iD.svg.MultipolygonMemberTags(graph))); - } + groups + .order(); - paths - .order() - .attr('d', path); + groups.selectAll('path') + .attr('d', path); - paths.exit() - .remove(); - } + // Optimization: call simple TagClasses only on enter selection. This + // works because iD.Entity.key is defined to include the entity v attribute. + groups.selectAll('path.stroke') + .call(iD.svg.TagClasses().tags(iD.svg.MultipolygonMemberTags(graph))); + + groups.exit() + .remove(); - drawPaths('shadow'); - drawPaths('casing'); - drawPaths('stroke'); var segments = _(lines) .filter(function(d) { return d.isOneWay(); }) diff --git a/js/id/svg/surface.js b/js/id/svg/surface.js index 3b11461dd..fd9fb322b 100644 --- a/js/id/svg/surface.js +++ b/js/id/svg/surface.js @@ -1,7 +1,7 @@ iD.svg.Surface = function() { return function (selection) { var layers = selection.selectAll('.layer') - .data(['fill', 'shadow', 'casing', 'stroke', 'oneway', 'hit', 'halo', 'label']); + .data(['fill', 'shadow', 'casing', 'stroke', 'line', 'oneway', 'hit', 'halo', 'label']); layers.enter().append('g') .attr('class', function(d) { return 'layer layer-' + d; }); From 849363ff8c2fa109d3cc45af00d9d11f4d22913a Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 2 Jun 2014 22:26:15 -0400 Subject: [PATCH 3/9] Group by layer to correctly depth sort lines.. --- js/id/core/way.js | 1 + js/id/svg/lines.js | 161 +++++++++++++++++++++++++------------------ js/id/svg/surface.js | 2 +- 3 files changed, 96 insertions(+), 68 deletions(-) diff --git a/js/id/core/way.js b/js/id/core/way.js index 9e2d6f0eb..a8504d558 100644 --- a/js/id/core/way.js +++ b/js/id/core/way.js @@ -59,6 +59,7 @@ _.extend(iD.Way.prototype, { if (this.tags.tunnel) return -1; if (this.tags.waterway) return -1; if (this.tags.manmade === 'pipeline') return -10; + if (this.tags.boundary) return -20; return 0; }, diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index 02f7c6994..a89636221 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -1,95 +1,122 @@ iD.svg.Lines = function(projection) { - // var highway_stack = { - // motorway: 0, - // motorway_link: 1, - // trunk: 2, - // trunk_link: 3, - // primary: 4, - // primary_link: 5, - // secondary: 6, - // tertiary: 7, - // unclassified: 8, - // residential: 9, - // service: 10, - // footway: 11 - // }; + var highway_stack = { + motorway: 0, + motorway_link: 1, + trunk: 2, + trunk_link: 3, + primary: 4, + primary_link: 5, + secondary: 6, + tertiary: 7, + unclassified: 8, + residential: 9, + service: 10, + footway: 11 + }; - // function waystack(a, b) { - // if (!a || !b || !a.tags || !b.tags) return 0; - // if (a.tags.layer !== undefined && b.tags.layer !== undefined) { - // return a.tags.layer - b.tags.layer; - // } - // if (a.tags.bridge) return 1; - // if (b.tags.bridge) return -1; - // if (a.tags.tunnel) return -1; - // if (b.tags.tunnel) return 1; - // var as = 0, bs = 0; - // if (a.tags.highway && b.tags.highway) { - // as -= highway_stack[a.tags.highway]; - // bs -= highway_stack[b.tags.highway]; - // } - // return as - bs; - // } + 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; + } return function drawLines(surface, graph, entities, filter) { - var lines = [], - path = iD.svg.Path(projection, graph); + var ways = [], pathdata = {}, onewaydata = {}, + getPath = iD.svg.Path(projection, graph); for (var i = 0; i < entities.length; i++) { var entity = entities[i], outer = iD.geo.simpleMultipolygonOuterMember(entity, graph); if (outer) { - lines.push(entity.mergeTags(outer.tags)); + ways.push(entity.mergeTags(outer.tags)); } else if (entity.geometry(graph) === 'line') { - lines.push(entity); + ways.push(entity); } } - lines = lines.filter(path); - lines.sort(function(a, b) { return a.layer() - b.layer(); }); + ways = ways.filter(getPath); - var groups = surface.select('.layer-line') - .selectAll('g') - .filter(filter) - .data(lines, iD.Entity.key); + pathdata = _.groupBy(ways, function(way) { return way.layer(); }); - var enter = groups.enter() - .append('g') - .attr('class', function(d) { return d.id; }); - - ['shadow', 'casing', 'stroke'].forEach(function(klass) { - enter - .append('path') - .attr('class', function(d) { return 'way line ' + klass + ' ' + d.id; }) - .call(iD.svg.TagClasses()); + _.forOwn(pathdata, function(v, k) { + onewaydata[k] = _(v) + .filter(function(d) { return d.isOneWay(); }) + .map(iD.svg.OneWaySegments(projection, graph, 35)) + .flatten() + .valueOf(); }); - groups - .order(); + var layergroup = surface + .select('.layer-lines') + .selectAll('g.layergroup') + .data( + _.keys(pathdata).map(Number), + function(d) { return d; } + ); - groups.selectAll('path') - .attr('d', path); + layergroup.enter() + .append('g') + .attr('class', function(d) { return 'layer layergroup layer' + String(d); }); - // Optimization: call simple TagClasses only on enter selection. This - // works because iD.Entity.key is defined to include the entity v attribute. - groups.selectAll('path.stroke') - .call(iD.svg.TagClasses().tags(iD.svg.MultipolygonMemberTags(graph))); + layergroup + .sort(d3.ascending); - groups.exit() + layergroup.exit() .remove(); - var segments = _(lines) - .filter(function(d) { return d.isOneWay(); }) - .map(iD.svg.OneWaySegments(projection, graph, 35)) - .flatten() - .valueOf(); + var linegroup = layergroup + .selectAll('g.linegroup') + .data(['shadow', 'casing', 'stroke']); - var oneways = surface.select('.layer-oneway') - .selectAll('path.oneway') + linegroup.enter() + .append('g') + .attr('class', function(d) { return 'layer linegroup line-' + d; }); + + + var lines = linegroup + .selectAll('path') .filter(filter) - .data(segments, function(d) { return [d.id, d.index]; }); + .data( + function(d) { return pathdata[this.parentNode.parentNode.__data__]; }, + iD.Entity.key + ); + + // Optimization: call simple TagClasses only on enter selection. This + // works because iD.Entity.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(iD.svg.TagClasses()); + + lines + .sort(waystack) + .attr('d', getPath) + .call(iD.svg.TagClasses().tags(iD.svg.MultipolygonMemberTags(graph))); + + lines.exit() + .remove(); + + + var onewaygroup = layergroup + .selectAll('g.onewaygroup') + .data(['oneway']); + + onewaygroup.enter() + .append('g') + .attr('class', function(d) { return 'layer onewaygroup'; }); + + + var oneways = onewaygroup + .selectAll('path') + .filter(filter) + .data( + function(d) { return onewaydata[this.parentNode.parentNode.__data__]; }, + function(d) { return [d.id, d.index]; } + ); oneways.enter() .append('path') @@ -97,10 +124,10 @@ iD.svg.Lines = function(projection) { .attr('marker-mid', 'url(#oneway-marker)'); oneways - .order() .attr('d', function(d) { return d.d; }); oneways.exit() .remove(); + }; }; diff --git a/js/id/svg/surface.js b/js/id/svg/surface.js index fd9fb322b..ad2cf4faa 100644 --- a/js/id/svg/surface.js +++ b/js/id/svg/surface.js @@ -1,7 +1,7 @@ iD.svg.Surface = function() { return function (selection) { var layers = selection.selectAll('.layer') - .data(['fill', 'shadow', 'casing', 'stroke', 'line', 'oneway', 'hit', 'halo', 'label']); + .data(['fill', 'shadow', 'casing', 'stroke', 'lines', 'hit', 'halo', 'label']); layers.enter().append('g') .attr('class', function(d) { return 'layer layer-' + d; }); From 97b189b39790358884397e89a78527a7518c40a7 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 9 Jun 2014 17:40:14 -0400 Subject: [PATCH 4/9] Precreate fixed number of layergroups between -10, 10 --- js/id/core/way.js | 12 +++++++----- js/id/svg/lines.js | 17 ++++------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/js/id/core/way.js b/js/id/core/way.js index a8504d558..12af9e6f0 100644 --- a/js/id/core/way.js +++ b/js/id/core/way.js @@ -43,23 +43,25 @@ _.extend(iD.Way.prototype, { }, layer: function() { - // explicit layer tag.. - if (this.tags.layer !== undefined) return +(this.tags.layer); + // explicit layer tag, clamp between -10, 10.. + if (this.tags.layer !== undefined) { + return Math.max(-10, Math.min(+(this.tags.layer), 10)); + } // implied layer tag.. if (this.tags.location === 'overground') return 1; if (this.tags.location === 'underground') return -1; if (this.tags.location === 'underwater') return -10; - if (this.tags.power === 'line') return 20; - if (this.tags.power === 'minor_line') return 15; + if (this.tags.power === 'line') return 10; + if (this.tags.power === 'minor_line') return 10; if (this.tags.aerialway) return 10; if (this.tags.bridge) return 1; if (this.tags.cutting) return -1; if (this.tags.tunnel) return -1; if (this.tags.waterway) return -1; if (this.tags.manmade === 'pipeline') return -10; - if (this.tags.boundary) return -20; + if (this.tags.boundary) return -10; return 0; }, diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index a89636221..30a6aaf7b 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -52,21 +52,12 @@ iD.svg.Lines = function(projection) { var layergroup = surface .select('.layer-lines') .selectAll('g.layergroup') - .data( - _.keys(pathdata).map(Number), - function(d) { return d; } - ); + .data(d3.range(-10, 11)); layergroup.enter() .append('g') .attr('class', function(d) { return 'layer layergroup layer' + String(d); }); - layergroup - .sort(d3.ascending); - - layergroup.exit() - .remove(); - var linegroup = layergroup .selectAll('g.linegroup') @@ -81,7 +72,7 @@ iD.svg.Lines = function(projection) { .selectAll('path') .filter(filter) .data( - function(d) { return pathdata[this.parentNode.parentNode.__data__]; }, + function() { return pathdata[this.parentNode.parentNode.__data__] || []; }, iD.Entity.key ); @@ -107,14 +98,14 @@ iD.svg.Lines = function(projection) { onewaygroup.enter() .append('g') - .attr('class', function(d) { return 'layer onewaygroup'; }); + .attr('class', 'layer onewaygroup'); var oneways = onewaygroup .selectAll('path') .filter(filter) .data( - function(d) { return onewaydata[this.parentNode.parentNode.__data__]; }, + function() { return onewaydata[this.parentNode.parentNode.__data__] || []; }, function(d) { return [d.id, d.index]; } ); From a5f839db4425349be4d11f91b1cce4e836f291e5 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 9 Jun 2014 23:16:44 -0400 Subject: [PATCH 5/9] improve bridge styles, add low-zoom, butt linecaps.. --- css/map.css | 68 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/css/map.css b/css/map.css index dcad6d841..5a7bc4e78 100644 --- a/css/map.css +++ b/css/map.css @@ -774,42 +774,82 @@ path.casing.tag-boundary-national_park { /* bridges */ path.casing.tag-bridge { - stroke-width: 14; - stroke-opacity: 0.5; + stroke-width: 16; + stroke-opacity: 0.6; stroke: #000; + stroke-linecap: butt; } +path.shadow.tag-bridge { + stroke-width: 22; +} + +path.casing.line.tag-railway.tag-bridge, path.casing.tag-highway-living_street.tag-bridge, -path.casing.tag-highway-path.tag-bridge { - stroke-width: 6; -} - -path.casing.line.tag-highway-pedestrian, +path.casing.tag-highway-path.tag-bridge, +path.casing.line.tag-highway-pedestrian.tag-bridge, path.casing.tag-highway-service.tag-bridge, path.casing.tag-highway-track.tag-bridge, path.casing.tag-highway-steps.tag-bridge, path.casing.tag-highway-footway.tag-bridge, path.casing.tag-highway-cycleway.tag-bridge, path.casing.tag-highway-bridleway.tag-bridge { - stroke-width: 8; -} - -path.shadow.tag-highway-residential.tag-bridge { - stroke-width:22; + stroke-width: 10; } +path.shadow.line.tag-railway.tag-bridge, path.shadow.tag-highway-living_street.tag-bridge, path.shadow.tag-highway-path.tag-bridge, -path.shadow.line.tag-highway-pedestrian, +path.shadow.line.tag-highway-pedestrian.tag-bridge, path.shadow.tag-highway-service.tag-bridge, path.shadow.tag-highway-track.tag-bridge, path.shadow.tag-highway-steps.tag-bridge, path.shadow.tag-highway-footway.tag-bridge, path.shadow.tag-highway-cycleway.tag-bridge, path.shadow.tag-highway-bridleway.tag-bridge { - stroke-width: 16; + stroke-width: 17; } + +.low-zoom path.casing.tag-bridge { + stroke-width: 10; + stroke-opacity: 0.6; + stroke: #000; + stroke-linecap: butt; +} + +.low-zoom path.shadow.tag-bridge { + stroke-width: 14; +} + +.low-zoom path.casing.line.tag-railway.tag-bridge, +.low-zoom path.casing.tag-highway-living_street.tag-bridge, +.low-zoom path.casing.tag-highway-path.tag-bridge, +.low-zoom path.casing.line.tag-highway-pedestrian.tag-bridge, +.low-zoom path.casing.tag-highway-service.tag-bridge, +.low-zoom path.casing.tag-highway-track.tag-bridge, +.low-zoom path.casing.tag-highway-steps.tag-bridge, +.low-zoom path.casing.tag-highway-footway.tag-bridge, +.low-zoom path.casing.tag-highway-cycleway.tag-bridge, +.low-zoom path.casing.tag-highway-bridleway.tag-bridge { + stroke-width: 6; +} + +.low-zoom path.shadow.line.tag-railway.tag-bridge, +.low-zoom path.shadow.tag-highway-living_street.tag-bridge, +.low-zoom path.shadow.tag-highway-path.tag-bridge, +.low-zoom path.shadow.line.tag-highway-pedestrian.tag-bridge, +.low-zoom path.shadow.tag-highway-service.tag-bridge, +.low-zoom path.shadow.tag-highway-track.tag-bridge, +.low-zoom path.shadow.tag-highway-steps.tag-bridge, +.low-zoom path.shadow.tag-highway-footway.tag-bridge, +.low-zoom path.shadow.tag-highway-cycleway.tag-bridge, +.low-zoom path.shadow.tag-highway-bridleway.tag-bridge { + stroke-width: 13; +} + + + /* tunnels */ path.stroke.tag-tunnel { From 0c5f563a262edbea4911da0c4f65f380975e6276 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 9 Jun 2014 23:39:16 -0400 Subject: [PATCH 6/9] add test for iD.Entity.layer(), fix spelling of man_made. --- js/id/core/way.js | 2 +- test/spec/core/way.js | 62 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/js/id/core/way.js b/js/id/core/way.js index 12af9e6f0..53cb717fd 100644 --- a/js/id/core/way.js +++ b/js/id/core/way.js @@ -60,7 +60,7 @@ _.extend(iD.Way.prototype, { if (this.tags.cutting) return -1; if (this.tags.tunnel) return -1; if (this.tags.waterway) return -1; - if (this.tags.manmade === 'pipeline') return -10; + if (this.tags.man_made === 'pipeline') return -10; if (this.tags.boundary) return -10; return 0; }, diff --git a/test/spec/core/way.js b/test/spec/core/way.js index 5ff68c431..799b6a224 100644 --- a/test/spec/core/way.js +++ b/test/spec/core/way.js @@ -148,6 +148,68 @@ describe('iD.Way', function() { }); }); + describe('#layer', function() { + it('returns 0 when the way has no tags', function() { + expect(iD.Way().layer()).to.equal(0); + }); + + it('returns the layer when the way has an explicit layer tag', function() { + expect(iD.Way({tags: { layer: '2' }}).layer()).to.equal(2); + expect(iD.Way({tags: { layer: '-5' }}).layer()).to.equal(-5); + }); + + it('clamps the layer to within -10, 10', function() { + expect(iD.Way({tags: { layer: '12' }}).layer()).to.equal(10); + expect(iD.Way({tags: { layer: '-15' }}).layer()).to.equal(-10); + }); + + it('returns 1 for location=overground', function() { + expect(iD.Way({tags: { location: 'overground' }}).layer()).to.equal(1); + }); + + it('returns -1 for location=underground', function() { + expect(iD.Way({tags: { location: 'underground' }}).layer()).to.equal(-1); + }); + + it('returns -10 for location=underwater', function() { + expect(iD.Way({tags: { location: 'underwater' }}).layer()).to.equal(-10); + }); + + it('returns 10 for power lines', function() { + expect(iD.Way({tags: { power: 'line' }}).layer()).to.equal(10); + expect(iD.Way({tags: { power: 'minor_line' }}).layer()).to.equal(10); + }); + + it('returns 10 for aerialways', function() { + expect(iD.Way({tags: { aerialway: 'cable_car' }}).layer()).to.equal(10); + }); + + it('returns 1 for bridges', function() { + expect(iD.Way({tags: { bridge: 'yes' }}).layer()).to.equal(1); + }); + + it('returns -1 for cuttings', function() { + expect(iD.Way({tags: { cutting: 'yes' }}).layer()).to.equal(-1); + }); + + it('returns -1 for tunnels', function() { + expect(iD.Way({tags: { tunnel: 'yes' }}).layer()).to.equal(-1); + }); + + it('returns -1 for waterways', function() { + expect(iD.Way({tags: { waterway: 'stream' }}).layer()).to.equal(-1); + }); + + it('returns -10 for pipelines', function() { + expect(iD.Way({tags: { man_made: 'pipeline' }}).layer()).to.equal(-10); + }); + + it('returns -10 for boundaries', function() { + expect(iD.Way({tags: { boundary: 'administrative' }}).layer()).to.equal(-10); + }); + + }); + describe('#isOneWay', function() { it('returns false when the way has no tags', function() { expect(iD.Way().isOneWay()).to.be.false; From 7f35ab6125411a83c105cfdc1d06eb7399082fb0 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 11 Jun 2014 13:01:27 -0400 Subject: [PATCH 7/9] separate svg group for areas and their related strokes/fills (for consistency) --- js/id/svg/areas.js | 15 ++++++++++++--- js/id/svg/surface.js | 2 +- test/spec/svg/areas.js | 18 +++++++++--------- test/spec/svg/lines.js | 20 ++++++++++---------- 4 files changed, 32 insertions(+), 23 deletions(-) diff --git a/js/id/svg/areas.js b/js/id/svg/areas.js index 972ebc403..d2ed972d4 100644 --- a/js/id/svg/areas.js +++ b/js/id/svg/areas.js @@ -64,8 +64,17 @@ iD.svg.Areas = function(projection) { fill: areas }; - var paths = surface.selectAll('.layer-shadow, .layer-stroke, .layer-fill') - .selectAll('path.area') + var areagroup = surface + .select('.layer-areas') + .selectAll('g.areagroup') + .data(['fill', 'shadow', 'stroke']); + + areagroup.enter() + .append('g') + .attr('class', function(d) { return 'layer areagroup area-' + d; }); + + var paths = areagroup + .selectAll('path') .filter(filter) .data(function(layer) { return data[layer]; }, iD.Entity.key); @@ -74,7 +83,7 @@ iD.svg.Areas = function(projection) { paths.exit() .remove(); - var fills = surface.selectAll('.layer-fill path.area')[0]; + var fills = surface.selectAll('.area-fill path.area')[0]; var bisect = d3.bisector(function(node) { return -node.__data__.area(graph); diff --git a/js/id/svg/surface.js b/js/id/svg/surface.js index ad2cf4faa..c489ea0df 100644 --- a/js/id/svg/surface.js +++ b/js/id/svg/surface.js @@ -1,7 +1,7 @@ iD.svg.Surface = function() { return function (selection) { var layers = selection.selectAll('.layer') - .data(['fill', 'shadow', 'casing', 'stroke', 'lines', 'hit', 'halo', 'label']); + .data(['areas', 'lines', 'hit', 'halo', 'label']); layers.enter().append('g') .attr('class', function(d) { return 'layer layer-' + d; }); diff --git a/test/spec/svg/areas.js b/test/spec/svg/areas.js index b0d95c59f..c8d21032f 100644 --- a/test/spec/svg/areas.js +++ b/test/spec/svg/areas.js @@ -40,18 +40,18 @@ describe("iD.svg.Areas", function () { expect(surface.select('.area')).to.be.classed('tag-building-yes'); }); - it("preserves non-area paths", function () { - var area = iD.Way({tags: {area: 'yes'}}), - graph = iD.Graph([area]); + // it("preserves non-area paths", function () { + // var area = iD.Way({tags: {area: 'yes'}}), + // graph = iD.Graph([area]); - surface.select('.layer-fill') - .append('path') - .attr('class', 'other'); + // surface.select('.area-fill') + // .append('path') + // .attr('class', 'other'); - surface.call(iD.svg.Areas(projection), graph, [area], none); + // surface.call(iD.svg.Areas(projection), graph, [area], none); - expect(surface.selectAll('.other')[0].length).to.equal(1); - }); + // expect(surface.selectAll('.other')[0].length).to.equal(1); + // }); it("handles deletion of a way and a member vertex (#1903)", function () { var graph = iD.Graph([ diff --git a/test/spec/svg/lines.js b/test/spec/svg/lines.js index 21ba6981d..b4b892b3f 100644 --- a/test/spec/svg/lines.js +++ b/test/spec/svg/lines.js @@ -9,7 +9,7 @@ describe("iD.svg.Lines", function () { .call(iD.svg.Surface(iD())); }); - it("adds way and area classes", function () { + it("adds way and line classes", function () { var a = iD.Node({loc: [0, 0]}), b = iD.Node({loc: [1, 1]}), line = iD.Way({nodes: [a.id, b.id]}), @@ -72,16 +72,16 @@ describe("iD.svg.Lines", function () { expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); - it("preserves non-line paths", function () { - var line = iD.Way(), - graph = iD.Graph([line]); + // it("preserves non-line paths", function () { + // var line = iD.Way(), + // graph = iD.Graph([line]); - surface.select('.layer-fill') - .append('path') - .attr('class', 'other'); + // surface.select('.area-fill') + // .append('path') + // .attr('class', 'other'); - surface.call(iD.svg.Lines(projection), graph, [line], filter); + // surface.call(iD.svg.Lines(projection), graph, [line], filter); - expect(surface.selectAll('.other')[0].length).to.equal(1); - }); + // expect(surface.selectAll('.other')[0].length).to.equal(1); + // }); }); From 38cb42e0bcd065ca54e4987a9b82c8046e2045d5 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Wed, 11 Jun 2014 22:30:36 -0400 Subject: [PATCH 8/9] Add tests for line z-indexing. --- test/spec/svg/lines.js | 61 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/test/spec/svg/lines.js b/test/spec/svg/lines.js index b4b892b3f..f464929db 100644 --- a/test/spec/svg/lines.js +++ b/test/spec/svg/lines.js @@ -2,7 +2,8 @@ describe("iD.svg.Lines", function () { var surface, projection = d3.geo.projection(function(x, y) { return [x, y]; }) .clipExtent([[0, 0], [Infinity, Infinity]]), - filter = d3.functor(true); + all = d3.functor(true), + none = d3.functor(false); beforeEach(function () { surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg')) @@ -15,7 +16,7 @@ describe("iD.svg.Lines", function () { line = iD.Way({nodes: [a.id, b.id]}), graph = iD.Graph([a, b, line]); - surface.call(iD.svg.Lines(projection), graph, [line], filter); + surface.call(iD.svg.Lines(projection), graph, [line], all); expect(surface.select('path.way')).to.be.classed('way'); expect(surface.select('path.line')).to.be.classed('line'); @@ -27,7 +28,7 @@ describe("iD.svg.Lines", function () { line = iD.Way({nodes: [a.id, b.id], tags: {highway: 'residential'}}), graph = iD.Graph([a, b, line]); - surface.call(iD.svg.Lines(projection), graph, [line], filter); + surface.call(iD.svg.Lines(projection), graph, [line], all); expect(surface.select('.line')).to.be.classed('tag-highway'); expect(surface.select('.line')).to.be.classed('tag-highway-residential'); @@ -40,7 +41,7 @@ describe("iD.svg.Lines", function () { relation = iD.Relation({members: [{id: line.id}], tags: {type: 'multipolygon', natural: 'wood'}}), graph = iD.Graph([a, b, line, relation]); - surface.call(iD.svg.Lines(projection), graph, [line], filter); + surface.call(iD.svg.Lines(projection), graph, [line], all); expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); @@ -53,7 +54,7 @@ describe("iD.svg.Lines", function () { r = iD.Relation({members: [{id: w.id}], tags: {type: 'multipolygon'}}), graph = iD.Graph([a, b, c, w, r]); - surface.call(iD.svg.Lines(projection), graph, [w], filter); + surface.call(iD.svg.Lines(projection), graph, [w], all); expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); @@ -67,7 +68,7 @@ describe("iD.svg.Lines", 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.svg.Lines(projection), graph, [i], filter); + surface.call(iD.svg.Lines(projection), graph, [i], all); expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); @@ -80,8 +81,54 @@ describe("iD.svg.Lines", function () { // .append('path') // .attr('class', 'other'); - // surface.call(iD.svg.Lines(projection), graph, [line], filter); + // surface.call(iD.svg.Lines(projection), graph, [line], all); // expect(surface.selectAll('.other')[0].length).to.equal(1); // }); + + describe("z-indexing", function() { + var graph = iD.Graph([ + iD.Node({id: 'a', loc: [0, 0]}), + iD.Node({id: 'b', loc: [1, 1]}), + iD.Node({id: 'c', loc: [0, 0]}), + iD.Node({id: 'd', loc: [1, 1]}), + iD.Way({id: 'lo', tags: {highway: 'residential', tunnel: 'yes'}, nodes: ['a', 'b']}), + iD.Way({id: 'hi', tags: {highway: 'residential', bridge: 'yes'}, nodes: ['c', 'd']}) + ]); + + it("stacks higher lines above lower ones in a single render", function () { + surface.call(iD.svg.Lines(projection), graph, [graph.entity('lo'), graph.entity('hi')], none); + + var selection = surface.selectAll('g.line-stroke > path.line'); + expect(selection[0][0].__data__.id).to.eql('lo'); + expect(selection[0][1].__data__.id).to.eql('hi'); + }); + + it("stacks higher lines above lower ones in a single render (reverse)", function () { + surface.call(iD.svg.Lines(projection), graph, [graph.entity('hi'), graph.entity('lo')], none); + + var selection = surface.selectAll('g.line-stroke > path.line'); + expect(selection[0][0].__data__.id).to.eql('lo'); + expect(selection[0][1].__data__.id).to.eql('hi'); + }); + + it("stacks higher lines above lower ones in separate renders", function () { + surface.call(iD.svg.Lines(projection), graph, [graph.entity('lo')], none); + surface.call(iD.svg.Lines(projection), graph, [graph.entity('hi')], none); + + var selection = surface.selectAll('g.line-stroke > path.line'); + expect(selection[0][0].__data__.id).to.eql('lo'); + expect(selection[0][1].__data__.id).to.eql('hi'); + }); + + it("stacks higher lines above lower in separate renders (reverse)", function () { + surface.call(iD.svg.Lines(projection), graph, [graph.entity('hi')], none); + surface.call(iD.svg.Lines(projection), graph, [graph.entity('lo')], none); + + var selection = surface.selectAll('g.line-stroke > path.line'); + expect(selection[0][0].__data__.id).to.eql('lo'); + expect(selection[0][1].__data__.id).to.eql('hi'); + }); + }); + }); From a3c7b5956dc351e491ea2401170475e5f41686ce Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 13 Jun 2014 12:03:08 -0700 Subject: [PATCH 9/9] Remove obsolete tests --- test/spec/svg/areas.js | 13 ------------- test/spec/svg/lines.js | 13 ------------- 2 files changed, 26 deletions(-) diff --git a/test/spec/svg/areas.js b/test/spec/svg/areas.js index c8d21032f..fcbcb1792 100644 --- a/test/spec/svg/areas.js +++ b/test/spec/svg/areas.js @@ -40,19 +40,6 @@ describe("iD.svg.Areas", function () { expect(surface.select('.area')).to.be.classed('tag-building-yes'); }); - // it("preserves non-area paths", function () { - // var area = iD.Way({tags: {area: 'yes'}}), - // graph = iD.Graph([area]); - - // surface.select('.area-fill') - // .append('path') - // .attr('class', 'other'); - - // surface.call(iD.svg.Areas(projection), graph, [area], none); - - // expect(surface.selectAll('.other')[0].length).to.equal(1); - // }); - it("handles deletion of a way and a member vertex (#1903)", function () { var graph = iD.Graph([ iD.Node({id: 'a', loc: [0, 0]}), diff --git a/test/spec/svg/lines.js b/test/spec/svg/lines.js index f464929db..b94575a60 100644 --- a/test/spec/svg/lines.js +++ b/test/spec/svg/lines.js @@ -73,19 +73,6 @@ describe("iD.svg.Lines", function () { expect(surface.select('.stroke')).to.be.classed('tag-natural-wood'); }); - // it("preserves non-line paths", function () { - // var line = iD.Way(), - // graph = iD.Graph([line]); - - // surface.select('.area-fill') - // .append('path') - // .attr('class', 'other'); - - // surface.call(iD.svg.Lines(projection), graph, [line], all); - - // expect(surface.selectAll('.other')[0].length).to.equal(1); - // }); - describe("z-indexing", function() { var graph = iD.Graph([ iD.Node({id: 'a', loc: [0, 0]}),