From 9f1506af5e755b755231b6f3e8799b3fd475b315 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 17 Jan 2013 09:48:21 -0800 Subject: [PATCH 1/6] Always use rounded projection --- js/id/renderer/map.js | 21 +++++++++++---------- js/id/svg.js | 1 - js/id/svg/areas.js | 6 +++--- js/id/svg/lines.js | 6 +++--- js/id/svg/midpoints.js | 4 ++-- js/id/svg/points.js | 4 ++-- js/id/svg/vertices.js | 4 ++-- test/spec/svg/areas.js | 2 +- test/spec/svg/points.js | 2 +- test/spec/svg/vertices.js | 4 ++-- 10 files changed, 27 insertions(+), 27 deletions(-) diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index 9edb347e4..467f7f351 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -5,6 +5,7 @@ iD.Map = function() { translateStart, keybinding = d3.keybinding(), projection = d3.geo.mercator().scale(1024), + roundedProjection = iD.svg.RoundProjection(projection), zoom = d3.behavior.zoom() .translate(projection.translate()) .scale(projection.scale()) @@ -16,11 +17,11 @@ iD.Map = function() { background = iD.Background() .projection(projection), transformProp = iD.util.prefixCSSProperty('Transform'), - points = iD.svg.Points(), - vertices = iD.svg.Vertices(), - lines = iD.svg.Lines(), - areas = iD.svg.Areas(), - midpoints = iD.svg.Midpoints(), + points = iD.svg.Points(roundedProjection), + vertices = iD.svg.Vertices(roundedProjection), + lines = iD.svg.Lines(roundedProjection), + areas = iD.svg.Areas(roundedProjection), + midpoints = iD.svg.Midpoints(roundedProjection), tail = d3.tail(), surface, tilegroup; @@ -97,11 +98,11 @@ iD.Map = function() { } surface - .call(points, graph, all, filter, projection) - .call(vertices, graph, all, filter, projection) - .call(lines, graph, all, filter, projection) - .call(areas, graph, all, filter, projection) - .call(midpoints, graph, all, filter, projection); + .call(points, graph, all, filter) + .call(vertices, graph, all, filter) + .call(lines, graph, all, filter) + .call(areas, graph, all, filter) + .call(midpoints, graph, all, filter); } function editOff() { diff --git a/js/id/svg.js b/js/id/svg.js index 5860126e9..e1d26e058 100644 --- a/js/id/svg.js +++ b/js/id/svg.js @@ -6,7 +6,6 @@ iD.svg = { }, PointTransform: function (projection) { - projection = iD.svg.RoundProjection(projection); return function (entity) { return 'translate(' + projection(entity.loc) + ')'; }; diff --git a/js/id/svg/areas.js b/js/id/svg/areas.js index ff24afecc..4fe06ba92 100644 --- a/js/id/svg/areas.js +++ b/js/id/svg/areas.js @@ -1,4 +1,4 @@ -iD.svg.Areas = function() { +iD.svg.Areas = function(projection) { var area_stack = { building: 0, @@ -26,7 +26,7 @@ iD.svg.Areas = function() { return as - bs; } - return function drawAreas(surface, graph, entities, filter, projection) { + return function drawAreas(surface, graph, entities, filter) { var areas = []; for (var i = 0; i < entities.length; i++) { @@ -47,7 +47,7 @@ iD.svg.Areas = function() { var nodes = _.pluck(entity.nodes, 'loc'); if (nodes.length === 0) return (lineStrings[entity.id] = ''); else return (lineStrings[entity.id] = - 'M' + nodes.map(iD.svg.RoundProjection(projection)).join('L')); + 'M' + nodes.map(projection).join('L')); } function drawPaths(group, areas, filter, classes) { diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index 3f1b634d7..4a2acfe38 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -1,4 +1,4 @@ -iD.svg.Lines = function() { +iD.svg.Lines = function(projection) { var arrowtext = '►\u3000\u3000', alength; @@ -53,7 +53,7 @@ iD.svg.Lines = function() { return paths; } - return function drawLines(surface, graph, entities, filter, projection) { + return function drawLines(surface, graph, entities, filter) { if (!alength) { var arrow = surface.append('text').text(arrowtext); @@ -80,7 +80,7 @@ iD.svg.Lines = function() { var nodes = _.pluck(entity.nodes, 'loc'); if (nodes.length === 0) return (lineStrings[entity.id] = ''); else return (lineStrings[entity.id] = - 'M' + nodes.map(iD.svg.RoundProjection(projection)).join('L')); + 'M' + nodes.map(projection).join('L')); } var casing = surface.select('.layer-casing'), diff --git a/js/id/svg/midpoints.js b/js/id/svg/midpoints.js index 9c060ea3b..321e75c8e 100644 --- a/js/id/svg/midpoints.js +++ b/js/id/svg/midpoints.js @@ -1,5 +1,5 @@ -iD.svg.Midpoints = function() { - return function drawMidpoints(surface, graph, entities, filter, projection) { +iD.svg.Midpoints = function(projection) { + return function drawMidpoints(surface, graph, entities, filter) { var midpoints = []; for (var i = 0; i < entities.length; i++) { diff --git a/js/id/svg/points.js b/js/id/svg/points.js index 7a2600814..37c4bbf91 100644 --- a/js/id/svg/points.js +++ b/js/id/svg/points.js @@ -1,4 +1,4 @@ -iD.svg.Points = function() { +iD.svg.Points = function(projection) { function imageHref(d) { // TODO: optimize for (var k in d.tags) { @@ -10,7 +10,7 @@ iD.svg.Points = function() { return 'icons/unknown.png'; } - return function drawPoints(surface, graph, entities, filter, projection) { + return function drawPoints(surface, graph, entities, filter) { var points = []; for (var i = 0; i < entities.length; i++) { diff --git a/js/id/svg/vertices.js b/js/id/svg/vertices.js index 700ef5538..ff775fa3e 100644 --- a/js/id/svg/vertices.js +++ b/js/id/svg/vertices.js @@ -1,5 +1,5 @@ -iD.svg.Vertices = function() { - return function drawVertices(surface, graph, entities, filter, projection) { +iD.svg.Vertices = function(projection) { + return function drawVertices(surface, graph, entities, filter) { var vertices = []; for (var i = 0; i < entities.length; i++) { diff --git a/test/spec/svg/areas.js b/test/spec/svg/areas.js index 54a7c1d35..5e910dbfc 100644 --- a/test/spec/svg/areas.js +++ b/test/spec/svg/areas.js @@ -12,7 +12,7 @@ describe("iD.svg.Areas", function () { var area = iD.Way({tags: {area: 'yes', building: 'yes'}}), graph = iD.Graph([area]); - surface.call(iD.svg.Areas(), graph, [area], filter, projection); + surface.call(iD.svg.Areas(projection), graph, [area], filter); expect(surface.select('.area')).to.be.classed('tag-building'); expect(surface.select('.area')).to.be.classed('tag-building-yes'); diff --git a/test/spec/svg/points.js b/test/spec/svg/points.js index 664f88a80..be06ae487 100644 --- a/test/spec/svg/points.js +++ b/test/spec/svg/points.js @@ -12,7 +12,7 @@ describe("iD.svg.Points", function () { var node = iD.Node({tags: {amenity: "cafe"}, loc: [0, 0], _poi: true}), graph = iD.Graph([node]); - surface.call(iD.svg.Points(), graph, [node], filter, projection); + surface.call(iD.svg.Points(projection), graph, [node], filter); expect(surface.select('.point')).to.be.classed('tag-amenity'); expect(surface.select('.point')).to.be.classed('tag-amenity-cafe'); diff --git a/test/spec/svg/vertices.js b/test/spec/svg/vertices.js index 760734053..dccdf80a0 100644 --- a/test/spec/svg/vertices.js +++ b/test/spec/svg/vertices.js @@ -12,7 +12,7 @@ describe("iD.svg.Vertices", function () { var node = iD.Node({tags: {highway: "traffic_signals"}, loc: [0, 0]}), graph = iD.Graph([node]); - surface.call(iD.svg.Vertices(), graph, [node], filter, projection); + surface.call(iD.svg.Vertices(projection), graph, [node], filter); expect(surface.select('.vertex')).to.be.classed('tag-highway'); expect(surface.select('.vertex')).to.be.classed('tag-highway-traffic_signals'); @@ -24,7 +24,7 @@ describe("iD.svg.Vertices", function () { way2 = iD.Way({nodes: [node.id]}), graph = iD.Graph([node, way1, way2]); - surface.call(iD.svg.Vertices(), graph, [node], filter, projection); + surface.call(iD.svg.Vertices(projection), graph, [node], filter); expect(surface.select('.vertex')).to.be.classed('shared'); }); From e24b22b518b35778c0e9344d6470bc0858637e9a Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 17 Jan 2013 09:57:22 -0800 Subject: [PATCH 2/6] Extract iD.svg.LineString --- js/id/svg.js | 16 ++++++++++++++++ js/id/svg/areas.js | 12 +----------- js/id/svg/lines.js | 10 +--------- test/index.html | 1 + test/index_packaged.html | 1 + test/spec/svg.js | 10 ++++++++++ 6 files changed, 30 insertions(+), 20 deletions(-) create mode 100644 test/spec/svg.js diff --git a/js/id/svg.js b/js/id/svg.js index e1d26e058..bf73f32b8 100644 --- a/js/id/svg.js +++ b/js/id/svg.js @@ -9,5 +9,21 @@ iD.svg = { return function (entity) { return 'translate(' + projection(entity.loc) + ')'; }; + }, + + LineString: function (projection) { + var cache = {}; + return function (entity) { + if (cache[entity.id] !== undefined) { + return cache[entity.id]; + } + + if (entity.nodes.length === 0) { + return (cache[entity.id] = ''); + } + + return (cache[entity.id] = + 'M' + entity.nodes.map(function (n) { return projection(n.loc); }).join('L')); + } } }; diff --git a/js/id/svg/areas.js b/js/id/svg/areas.js index 4fe06ba92..3862aca0c 100644 --- a/js/id/svg/areas.js +++ b/js/id/svg/areas.js @@ -38,17 +38,7 @@ iD.svg.Areas = function(projection) { areas.sort(areastack); - var lineStrings = {}; - - function lineString(entity) { - if (lineStrings[entity.id] !== undefined) { - return lineStrings[entity.id]; - } - var nodes = _.pluck(entity.nodes, 'loc'); - if (nodes.length === 0) return (lineStrings[entity.id] = ''); - else return (lineStrings[entity.id] = - 'M' + nodes.map(projection).join('L')); - } + var lineString = iD.svg.LineString(projection); function drawPaths(group, areas, filter, classes) { var paths = group.selectAll('path') diff --git a/js/id/svg/lines.js b/js/id/svg/lines.js index 4a2acfe38..167a9e75e 100644 --- a/js/id/svg/lines.js +++ b/js/id/svg/lines.js @@ -73,15 +73,7 @@ iD.svg.Lines = function(projection) { lines.sort(waystack); - function lineString(entity) { - if (lineStrings[entity.id] !== undefined) { - return lineStrings[entity.id]; - } - var nodes = _.pluck(entity.nodes, 'loc'); - if (nodes.length === 0) return (lineStrings[entity.id] = ''); - else return (lineStrings[entity.id] = - 'M' + nodes.map(projection).join('L')); - } + var lineString = iD.svg.LineString(projection); var casing = surface.select('.layer-casing'), stroke = surface.select('.layer-stroke'), diff --git a/test/index.html b/test/index.html index 195b459f6..96095a244 100644 --- a/test/index.html +++ b/test/index.html @@ -151,6 +151,7 @@ + diff --git a/test/index_packaged.html b/test/index_packaged.html index 92c61df79..cf333b416 100644 --- a/test/index_packaged.html +++ b/test/index_packaged.html @@ -60,6 +60,7 @@ + diff --git a/test/spec/svg.js b/test/spec/svg.js new file mode 100644 index 000000000..bbb78c990 --- /dev/null +++ b/test/spec/svg.js @@ -0,0 +1,10 @@ +describe("iD.svg.LineString", function () { + it("returns an SVG path description for the entity's nodes", function () { + var a = iD.Node({loc: [0, 0]}), + b = iD.Node({loc: [2, 3]}), + way = iD.Way({nodes: [a, b]}), + projection = Object; + + expect(iD.svg.LineString(projection)(way)).to.equal("M0,0L2,3"); + }); +}); From f64c2df17ff81421eb9e9f9ccf2339c0153f2e52 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 17 Jan 2013 10:40:14 -0800 Subject: [PATCH 3/6] Return null rather than empty string Empty string still generates the error 'Problem parsing d=""', while null results in no 'd' attribute at all. --- js/id/svg.js | 2 +- test/spec/svg.js | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/js/id/svg.js b/js/id/svg.js index bf73f32b8..e2b1dc2ad 100644 --- a/js/id/svg.js +++ b/js/id/svg.js @@ -19,7 +19,7 @@ iD.svg = { } if (entity.nodes.length === 0) { - return (cache[entity.id] = ''); + return (cache[entity.id] = null); } return (cache[entity.id] = diff --git a/test/spec/svg.js b/test/spec/svg.js index bbb78c990..265562071 100644 --- a/test/spec/svg.js +++ b/test/spec/svg.js @@ -7,4 +7,11 @@ describe("iD.svg.LineString", function () { expect(iD.svg.LineString(projection)(way)).to.equal("M0,0L2,3"); }); + + it("returns null for an entity with no nodes", function () { + var way = iD.Way(), + projection = Object; + + expect(iD.svg.LineString(projection)(way)).to.be.null; + }); }); From 8564279926257f48ef93273373a554da1a932ffc Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 17 Jan 2013 10:43:04 -0800 Subject: [PATCH 4/6] Use identity projection in tests --- test/spec/svg/areas.js | 2 +- test/spec/svg/points.js | 2 +- test/spec/svg/vertices.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/spec/svg/areas.js b/test/spec/svg/areas.js index 5e910dbfc..d978e81c6 100644 --- a/test/spec/svg/areas.js +++ b/test/spec/svg/areas.js @@ -1,6 +1,6 @@ describe("iD.svg.Areas", function () { var surface, - projection = d3.geo.mercator(), + projection = Object, filter = d3.functor(true); beforeEach(function () { diff --git a/test/spec/svg/points.js b/test/spec/svg/points.js index be06ae487..6e991962c 100644 --- a/test/spec/svg/points.js +++ b/test/spec/svg/points.js @@ -1,6 +1,6 @@ describe("iD.svg.Points", function () { var surface, - projection = d3.geo.mercator(), + projection = Object, filter = d3.functor(true); beforeEach(function () { diff --git a/test/spec/svg/vertices.js b/test/spec/svg/vertices.js index dccdf80a0..8ce5e3a80 100644 --- a/test/spec/svg/vertices.js +++ b/test/spec/svg/vertices.js @@ -1,6 +1,6 @@ describe("iD.svg.Vertices", function () { var surface, - projection = d3.geo.mercator(), + projection = Object, filter = d3.functor(true); beforeEach(function () { From 545789efcc64daeaa83b2ca0821dcde74e092e50 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 17 Jan 2013 10:51:51 -0800 Subject: [PATCH 5/6] More area tests --- js/id/svg/areas.js | 2 +- test/spec/svg/areas.js | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/js/id/svg/areas.js b/js/id/svg/areas.js index 3862aca0c..e77fe8a4d 100644 --- a/js/id/svg/areas.js +++ b/js/id/svg/areas.js @@ -41,7 +41,7 @@ iD.svg.Areas = function(projection) { var lineString = iD.svg.LineString(projection); function drawPaths(group, areas, filter, classes) { - var paths = group.selectAll('path') + var paths = group.selectAll('path.area') .filter(filter) .data(areas, iD.Entity.key); diff --git a/test/spec/svg/areas.js b/test/spec/svg/areas.js index d978e81c6..112e25d03 100644 --- a/test/spec/svg/areas.js +++ b/test/spec/svg/areas.js @@ -8,6 +8,16 @@ describe("iD.svg.Areas", function () { .call(iD.svg.Surface()); }); + it("adds way and area classes", function () { + var area = iD.Way({tags: {area: 'yes'}}), + graph = iD.Graph([area]); + + surface.call(iD.svg.Areas(projection), graph, [area], filter); + + expect(surface.select('path')).to.be.classed('way'); + expect(surface.select('path')).to.be.classed('area'); + }); + it("adds tag classes", function () { var area = iD.Way({tags: {area: 'yes', building: 'yes'}}), graph = iD.Graph([area]); @@ -17,4 +27,17 @@ describe("iD.svg.Areas", function () { expect(surface.select('.area')).to.be.classed('tag-building'); 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('.layer-fill') + .append('path') + .attr('class', 'other'); + + surface.call(iD.svg.Areas(projection), graph, [area], filter); + + expect(surface.selectAll('.other')[0].length).to.equal(1); + }); }); From 9a76b81125368c3380d1616d56bbdc825c7a89b7 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 17 Jan 2013 11:01:20 -0800 Subject: [PATCH 6/6] First cut on multipolygon rendering --- css/map.css | 22 ++++++++++---- index.html | 1 + js/id/renderer/map.js | 2 ++ js/id/svg/multipolygons.js | 54 ++++++++++++++++++++++++++++++++++ js/id/svg/tag_classes.js | 2 +- test/index.html | 2 ++ test/index_packaged.html | 1 + test/spec/svg/multipolygons.js | 43 +++++++++++++++++++++++++++ 8 files changed, 121 insertions(+), 6 deletions(-) create mode 100644 js/id/svg/multipolygons.js create mode 100644 test/spec/svg/multipolygons.js diff --git a/css/map.css b/css/map.css index b2929f149..fc54d7499 100644 --- a/css/map.css +++ b/css/map.css @@ -142,29 +142,37 @@ path.stroke.tag-railway-subway { stroke-dasharray: 8,8; } -path.area { +path.area, +path.multipolygon { stroke-width:2; stroke:#fff; fill:#fff; fill-opacity:0.3; } +path.multipolygon { + fill-rule: evenodd; +} + path.area.selected { stroke-width:4 !important; } -path.area.tag-natural { +path.area.tag-natural, +path.multipolygon.tag-natural { stroke: #ADD6A5; fill: #ADD6A5; stroke-width:1; } -path.area.tag-natural-water { +path.area.tag-natural-water, +path.multipolygon.tag-natural-water { stroke: #6382FF; fill: #ADBEFF; } -path.area.tag-building { +path.area.tag-building, +path.multipolygon.tag-building { stroke: #9E176A; stroke-width: 1; fill: #ff6ec7; @@ -173,7 +181,11 @@ path.area.tag-building { path.area.tag-landuse, path.area.tag-natural-wood, path.area.tag-natural-tree, -path.area.tag-natural-grassland { +path.area.tag-natural-grassland, +path.multipolygon.tag-landuse, +path.multipolygon.tag-natural-wood, +path.multipolygon.tag-natural-tree, +path.multipolygon.tag-natural-grassland { stroke: #006B34; stroke-width: 1; fill: #189E59; diff --git a/index.html b/index.html index 2d42c9f1c..4e42441f7 100644 --- a/index.html +++ b/index.html @@ -41,6 +41,7 @@ + diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index 467f7f351..ec232d542 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -21,6 +21,7 @@ iD.Map = function() { vertices = iD.svg.Vertices(roundedProjection), lines = iD.svg.Lines(roundedProjection), areas = iD.svg.Areas(roundedProjection), + multipolygons = iD.svg.Multipolygons(roundedProjection), midpoints = iD.svg.Midpoints(roundedProjection), tail = d3.tail(), surface, tilegroup; @@ -102,6 +103,7 @@ iD.Map = function() { .call(vertices, graph, all, filter) .call(lines, graph, all, filter) .call(areas, graph, all, filter) + .call(multipolygons, graph, all, filter) .call(midpoints, graph, all, filter); } diff --git a/js/id/svg/multipolygons.js b/js/id/svg/multipolygons.js new file mode 100644 index 000000000..bad07ff41 --- /dev/null +++ b/js/id/svg/multipolygons.js @@ -0,0 +1,54 @@ +iD.svg.Multipolygons = function(projection) { + return function(surface, graph, entities, filter) { + var multipolygons = []; + + for (var i = 0; i < entities.length; i++) { + var entity = entities[i]; + if (entity.geometry() === 'relation' && entity.tags.type === 'multipolygon') { + multipolygons.push(entity); + } + } + + var lineStrings = {}; + + function lineString(entity) { + if (lineStrings[entity.id] !== undefined) { + return lineStrings[entity.id]; + } + + var multipolygon = entity.multipolygon(graph); + if (entity.members.length == 0 || !multipolygon) { + return (lineStrings[entity.id] = null); + } + + multipolygon = _.flatten(multipolygon, true); + return (lineStrings[entity.id] = + multipolygon.map(function (ring) { + return 'M' + ring.map(function (node) { return projection(node.loc); }).join('L'); + }).join("")); + } + + function drawPaths(group, multipolygons, filter, classes) { + var paths = group.selectAll('path.multipolygon') + .filter(filter) + .data(multipolygons, iD.Entity.key); + + paths.enter() + .append('path') + .attr('class', classes); + + paths + .order() + .attr('d', lineString) + .call(iD.svg.TagClasses()); + + paths.exit() + .remove(); + + return paths; + } + + var fill = surface.select('.layer-fill'), + paths = drawPaths(fill, multipolygons, filter, 'relation multipolygon'); + }; +}; diff --git a/js/id/svg/tag_classes.js b/js/id/svg/tag_classes.js index 43562fd5c..0295ca7e6 100644 --- a/js/id/svg/tag_classes.js +++ b/js/id/svg/tag_classes.js @@ -1,7 +1,7 @@ iD.svg.TagClasses = function() { var keys = iD.util.trueObj([ 'highway', 'railway', 'motorway', 'amenity', 'natural', - 'landuse', 'building', 'oneway', 'bridge' + 'landuse', 'building', 'oneway', 'bridge', 'boundary' ]), tagClassRe = /^tag-/; return function tagClassesSelection(selection) { diff --git a/test/index.html b/test/index.html index 96095a244..ab7b521cd 100644 --- a/test/index.html +++ b/test/index.html @@ -43,6 +43,7 @@ + @@ -153,6 +154,7 @@ + diff --git a/test/index_packaged.html b/test/index_packaged.html index cf333b416..9044adf66 100644 --- a/test/index_packaged.html +++ b/test/index_packaged.html @@ -62,6 +62,7 @@ + diff --git a/test/spec/svg/multipolygons.js b/test/spec/svg/multipolygons.js new file mode 100644 index 000000000..67f44ebae --- /dev/null +++ b/test/spec/svg/multipolygons.js @@ -0,0 +1,43 @@ +describe("iD.svg.Multipolygons", function () { + var surface, + projection = Object, + filter = d3.functor(true); + + beforeEach(function () { + surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg')) + .call(iD.svg.Surface()); + }); + + it("adds relation and multipolygon classes", function () { + var relation = iD.Relation({tags: {type: 'multipolygon'}}), + graph = iD.Graph([relation]); + + surface.call(iD.svg.Multipolygons(projection), graph, [relation], filter); + + expect(surface.select('path')).to.be.classed('relation'); + expect(surface.select('path')).to.be.classed('multipolygon'); + }); + + it("adds tag classes", function () { + var relation = iD.Relation({tags: {type: 'multipolygon', boundary: "administrative"}}), + graph = iD.Graph([relation]); + + surface.call(iD.svg.Multipolygons(projection), graph, [relation], filter); + + expect(surface.select('.relation')).to.be.classed('tag-boundary'); + expect(surface.select('.relation')).to.be.classed('tag-boundary-administrative'); + }); + + it("preserves non-multipolygon paths", function () { + var relation = iD.Relation({tags: {type: 'multipolygon'}}), + graph = iD.Graph([relation]); + + surface.select('.layer-fill') + .append('path') + .attr('class', 'other'); + + surface.call(iD.svg.Multipolygons(projection), graph, [relation], filter); + + expect(surface.selectAll('.other')[0].length).to.equal(1); + }); +});