WIP: Move layer-hit to layer-points with explict sublayers, update tests

This is more work to further isolate the layers that entities draw to.
It makes it easier to debug what is going on, and can eventually lead to
deferred drawing, if each draw function is in its own place and not dependant
on anything else.

I've started to replace the vertex-hover with an explicit layer for touch
targets.

Also had to change a lot of the svg tests, which are really brittle.
Things would happen like - the surface would be created, it would kick of a
deferred redraw, which would notice that the zoom was 0 and call
editOff, which would remove the osm layers that were just created and
that the tests were trying to draw to. These tests need proper zoom and
projection otherwise nothing works.
This commit is contained in:
Bryan Housel
2017-12-14 17:38:43 -05:00
parent bfaf17538e
commit b9e48d1682
17 changed files with 405 additions and 339 deletions
+73 -69
View File
@@ -1,17 +1,21 @@
describe('iD.svgAreas', function () {
var context, surface,
projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(180 / Math.PI)
.clipExtent([[0, 0], [Infinity, Infinity]]),
all = function() { return true; },
none = function() { return false; };
var TAU = 2 * Math.PI;
function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
var context, surface;
var all = function() { return true; };
var none = function() { return false; };
var projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(ztok(17))
.clipExtent([[0, 0], [Infinity, Infinity]]);
beforeEach(function () {
context = iD.Context();
context = iD.coreContext();
d3.select(document.createElement('div'))
.attr('id', 'map')
.call(context.map());
.call(context.map().centerZoom([0, 0], 17));
surface = context.surface();
iD.setAreaKeys({
@@ -22,13 +26,13 @@ describe('iD.svgAreas', function () {
});
it('adds way and area classes', function () {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0]}),
iD.Node({id: 'c', loc: [1, 1]}),
iD.Node({id: 'd', loc: [0, 1]}),
iD.Way({id: 'w', tags: {building: 'yes'}, nodes: ['a', 'b', 'c', 'a']})
]);
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0, 0]}),
iD.osmNode({id: 'b', loc: [1, 0]}),
iD.osmNode({id: 'c', loc: [1, 1]}),
iD.osmNode({id: 'd', loc: [0, 1]}),
iD.osmWay({id: 'w', tags: {building: 'yes'}, nodes: ['a', 'b', 'c', 'a']})
]);
surface.call(iD.svgAreas(projection, context), graph, [graph.entity('w')], none);
@@ -37,13 +41,13 @@ describe('iD.svgAreas', function () {
});
it('adds tag classes', function () {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0]}),
iD.Node({id: 'c', loc: [1, 1]}),
iD.Node({id: 'd', loc: [0, 1]}),
iD.Way({id: 'w', tags: {building: 'yes'}, nodes: ['a', 'b', 'c', 'a']})
]);
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0, 0]}),
iD.osmNode({id: 'b', loc: [1, 0]}),
iD.osmNode({id: 'c', loc: [1, 1]}),
iD.osmNode({id: 'd', loc: [0, 1]}),
iD.osmWay({id: 'w', tags: {building: 'yes'}, nodes: ['a', 'b', 'c', 'a']})
]);
surface.call(iD.svgAreas(projection, context), graph, [graph.entity('w')], none);
@@ -52,14 +56,14 @@ describe('iD.svgAreas', function () {
});
it('handles deletion of a way and a member vertex (#1903)', function () {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [0, 0]}),
iD.Node({id: 'b', loc: [1, 0]}),
iD.Node({id: 'c', loc: [1, 1]}),
iD.Node({id: 'd', loc: [1, 1]}),
iD.Way({id: 'w', tags: {area: 'yes'}, nodes: ['a', 'b', 'c', 'a']}),
iD.Way({id: 'x', tags: {area: 'yes'}, nodes: ['a', 'b', 'd', 'a']})
]);
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0, 0]}),
iD.osmNode({id: 'b', loc: [1, 0]}),
iD.osmNode({id: 'c', loc: [1, 1]}),
iD.osmNode({id: 'd', loc: [1, 1]}),
iD.osmWay({id: 'w', tags: {area: 'yes'}, nodes: ['a', 'b', 'c', 'a']}),
iD.osmWay({id: 'x', tags: {area: 'yes'}, nodes: ['a', 'b', 'd', 'a']})
]);
surface.call(iD.svgAreas(projection, context), graph, [graph.entity('x')], all);
graph = graph.remove(graph.entity('x')).remove(graph.entity('d'));
@@ -69,18 +73,18 @@ describe('iD.svgAreas', function () {
});
describe('z-indexing', function() {
var graph = iD.Graph([
iD.Node({id: 'a', loc: [-0.0002, 0.0001]}),
iD.Node({id: 'b', loc: [ 0.0002, 0.0001]}),
iD.Node({id: 'c', loc: [ 0.0002, -0.0001]}),
iD.Node({id: 'd', loc: [-0.0002, -0.0001]}),
iD.Node({id: 'e', loc: [-0.0004, 0.0002]}),
iD.Node({id: 'f', loc: [ 0.0004, 0.0002]}),
iD.Node({id: 'g', loc: [ 0.0004, -0.0002]}),
iD.Node({id: 'h', loc: [-0.0004, -0.0002]}),
iD.Way({id: 's', tags: {building: 'yes'}, nodes: ['a', 'b', 'c', 'd', 'a']}),
iD.Way({id: 'l', tags: {landuse: 'park'}, nodes: ['e', 'f', 'g', 'h', 'e']})
]);
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [-0.0002, 0.0001]}),
iD.osmNode({id: 'b', loc: [ 0.0002, 0.0001]}),
iD.osmNode({id: 'c', loc: [ 0.0002, -0.0001]}),
iD.osmNode({id: 'd', loc: [-0.0002, -0.0001]}),
iD.osmNode({id: 'e', loc: [-0.0004, 0.0002]}),
iD.osmNode({id: 'f', loc: [ 0.0004, 0.0002]}),
iD.osmNode({id: 'g', loc: [ 0.0004, -0.0002]}),
iD.osmNode({id: 'h', loc: [-0.0004, -0.0002]}),
iD.osmWay({id: 's', tags: {building: 'yes'}, nodes: ['a', 'b', 'c', 'd', 'a']}),
iD.osmWay({id: 'l', tags: {landuse: 'park'}, nodes: ['e', 'f', 'g', 'h', 'e']})
]);
it('stacks smaller areas above larger ones in a single render', function () {
surface.call(iD.svgAreas(projection, context), graph, [graph.entity('s'), graph.entity('l')], none);
@@ -114,13 +118,13 @@ describe('iD.svgAreas', function () {
});
it('renders fills for multipolygon areas', function () {
var a = iD.Node({loc: [1, 1]}),
b = iD.Node({loc: [2, 2]}),
c = iD.Node({loc: [3, 3]}),
w = iD.Way({nodes: [a.id, b.id, c.id, a.id]}),
r = iD.Relation({tags: {type: 'multipolygon'}, members: [{id: w.id, type: 'way'}]}),
graph = iD.Graph([a, b, c, w, r]),
areas = [w, r];
var a = iD.osmNode({loc: [1, 1]});
var b = iD.osmNode({loc: [2, 2]});
var c = iD.osmNode({loc: [3, 3]});
var w = iD.osmWay({nodes: [a.id, b.id, c.id, a.id]});
var r = iD.osmRelation({tags: {type: 'multipolygon'}, members: [{id: w.id, type: 'way'}]});
var graph = iD.coreGraph([a, b, c, w, r]);
var areas = [w, r];
surface.call(iD.svgAreas(projection, context), graph, areas, none);
@@ -128,13 +132,13 @@ describe('iD.svgAreas', function () {
});
it('renders no strokes for multipolygon areas', function () {
var a = iD.Node({loc: [1, 1]}),
b = iD.Node({loc: [2, 2]}),
c = iD.Node({loc: [3, 3]}),
w = iD.Way({nodes: [a.id, b.id, c.id, a.id]}),
r = iD.Relation({tags: {type: 'multipolygon'}, members: [{id: w.id, type: 'way'}]}),
graph = iD.Graph([a, b, c, w, r]),
areas = [w, r];
var a = iD.osmNode({loc: [1, 1]});
var b = iD.osmNode({loc: [2, 2]});
var c = iD.osmNode({loc: [3, 3]});
var w = iD.osmWay({nodes: [a.id, b.id, c.id, a.id]});
var r = iD.osmRelation({tags: {type: 'multipolygon'}, members: [{id: w.id, type: 'way'}]});
var graph = iD.coreGraph([a, b, c, w, r]);
var areas = [w, r];
surface.call(iD.svgAreas(projection, context), graph, areas, none);
@@ -142,12 +146,12 @@ describe('iD.svgAreas', function () {
});
it('renders fill for a multipolygon with tags on the outer way', function() {
var a = iD.Node({loc: [1, 1]}),
b = iD.Node({loc: [2, 2]}),
c = iD.Node({loc: [3, 3]}),
w = iD.Way({tags: {natural: 'wood'}, nodes: [a.id, b.id, c.id, a.id]}),
r = iD.Relation({members: [{id: w.id, type: 'way'}], tags: {type: 'multipolygon'}}),
graph = iD.Graph([a, b, c, w, r]);
var a = iD.osmNode({loc: [1, 1]});
var b = iD.osmNode({loc: [2, 2]});
var c = iD.osmNode({loc: [3, 3]});
var w = iD.osmWay({tags: {natural: 'wood'}, nodes: [a.id, b.id, c.id, a.id]});
var r = iD.osmRelation({members: [{id: w.id, type: 'way'}], tags: {type: 'multipolygon'}});
var graph = iD.coreGraph([a, b, c, w, r]);
surface.call(iD.svgAreas(projection, context), graph, [w, r], none);
@@ -157,12 +161,12 @@ describe('iD.svgAreas', function () {
});
it('renders no strokes for a multipolygon with tags on the outer way', function() {
var a = iD.Node({loc: [1, 1]}),
b = iD.Node({loc: [2, 2]}),
c = iD.Node({loc: [3, 3]}),
w = iD.Way({tags: {natural: 'wood'}, nodes: [a.id, b.id, c.id, a.id]}),
r = iD.Relation({members: [{id: w.id, type: 'way'}], tags: {type: 'multipolygon'}}),
graph = iD.Graph([a, b, c, w, r]);
var a = iD.osmNode({loc: [1, 1]});
var b = iD.osmNode({loc: [2, 2]});
var c = iD.osmNode({loc: [3, 3]});
var w = iD.osmWay({tags: {natural: 'wood'}, nodes: [a.id, b.id, c.id, a.id]});
var r = iD.osmRelation({members: [{id: w.id, type: 'way'}], tags: {type: 'multipolygon'}});
var graph = iD.coreGraph([a, b, c, w, r]);
surface.call(iD.svgAreas(projection, context), graph, [w, r], none);
+9 -6
View File
@@ -1,12 +1,15 @@
describe('iD.svgLayers', function () {
var context, container,
projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(180 / Math.PI)
.clipExtent([[0, 0], [Infinity, Infinity]]);
var TAU = 2 * Math.PI;
function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
var context, container;
var projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(ztok(17))
.clipExtent([[0, 0], [Infinity, Infinity]]);
beforeEach(function () {
context = iD.Context();
context = iD.coreContext();
container = d3.select(document.createElement('div'));
});
+47 -43
View File
@@ -1,26 +1,30 @@
describe('iD.svgLines', function () {
var context, surface,
projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(180 / Math.PI)
.clipExtent([[0, 0], [Infinity, Infinity]]),
all = function() { return true; },
none = function() { return false; };
var TAU = 2 * Math.PI;
function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
var context, surface;
var all = function() { return true; };
var none = function() { return false; };
var projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(ztok(17))
.clipExtent([[0, 0], [Infinity, Infinity]]);
beforeEach(function () {
context = iD.Context();
context = iD.coreContext();
d3.select(document.createElement('div'))
.attr('id', 'map')
.call(context.map());
.call(context.map().centerZoom([0, 0], 17));
surface = context.surface();
});
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]}),
graph = iD.Graph([a, b, line]);
var a = iD.osmNode({loc: [0, 0]});
var b = iD.osmNode({loc: [1, 1]});
var line = iD.osmWay({nodes: [a.id, b.id]});
var graph = iD.coreGraph([a, b, line]);
surface.call(iD.svgLines(projection, context), graph, [line], all);
@@ -29,10 +33,10 @@ describe('iD.svgLines', function () {
});
it('adds tag classes', function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [1, 1]}),
line = iD.Way({nodes: [a.id, b.id], tags: {highway: 'residential'}}),
graph = iD.Graph([a, b, line]);
var a = iD.osmNode({loc: [0, 0]});
var b = iD.osmNode({loc: [1, 1]});
var line = iD.osmWay({nodes: [a.id, b.id], tags: {highway: 'residential'}});
var graph = iD.coreGraph([a, b, line]);
surface.call(iD.svgLines(projection, context), graph, [line], all);
@@ -41,11 +45,11 @@ describe('iD.svgLines', function () {
});
it('adds stroke classes for the tags of the parent relation of multipolygon members', function() {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [1, 1]}),
line = iD.Way({nodes: [a.id, b.id]}),
relation = iD.Relation({members: [{id: line.id}], tags: {type: 'multipolygon', natural: 'wood'}}),
graph = iD.Graph([a, b, line, relation]);
var a = iD.osmNode({loc: [0, 0]});
var b = iD.osmNode({loc: [1, 1]});
var line = iD.osmWay({nodes: [a.id, b.id]});
var relation = iD.osmRelation({members: [{id: line.id}], tags: {type: 'multipolygon', natural: 'wood'}});
var graph = iD.coreGraph([a, b, line, relation]);
surface.call(iD.svgLines(projection, context), graph, [line], all);
@@ -53,12 +57,12 @@ describe('iD.svgLines', function () {
});
it('renders stroke for outer way of multipolygon with tags on the outer way', function() {
var a = iD.Node({loc: [1, 1]}),
b = iD.Node({loc: [2, 2]}),
c = iD.Node({loc: [3, 3]}),
w = iD.Way({id: 'w-1', tags: {natural: 'wood'}, nodes: [a.id, b.id, c.id, a.id]}),
r = iD.Relation({members: [{id: w.id}], tags: {type: 'multipolygon'}}),
graph = iD.Graph([a, b, c, w, r]);
var a = iD.osmNode({loc: [1, 1]});
var b = iD.osmNode({loc: [2, 2]});
var c = iD.osmNode({loc: [3, 3]});
var w = iD.osmWay({id: 'w-1', tags: {natural: 'wood'}, nodes: [a.id, b.id, c.id, a.id]});
var r = iD.osmRelation({members: [{id: w.id}], tags: {type: 'multipolygon'}});
var graph = iD.coreGraph([a, b, c, w, r]);
surface.call(iD.svgLines(projection, context), graph, [w], all);
@@ -67,13 +71,13 @@ describe('iD.svgLines', function () {
});
it('adds stroke classes for the tags of the outer way of multipolygon with tags on the outer way', function() {
var a = iD.Node({loc: [1, 1]}),
b = iD.Node({loc: [2, 2]}),
c = iD.Node({loc: [3, 3]}),
o = iD.Way({id: 'w-1', nodes: [a.id, b.id, c.id, a.id], tags: {natural: 'wood'}}),
i = iD.Way({id: 'w-2', nodes: [a.id, b.id, c.id, a.id]}),
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]);
var a = iD.osmNode({loc: [1, 1]});
var b = iD.osmNode({loc: [2, 2]});
var c = iD.osmNode({loc: [3, 3]});
var o = iD.osmWay({id: 'w-1', nodes: [a.id, b.id, c.id, a.id], tags: {natural: 'wood'}});
var i = iD.osmWay({id: 'w-2', nodes: [a.id, b.id, c.id, a.id]});
var r = iD.osmRelation({members: [{id: o.id, role: 'outer'}, {id: i.id, role: 'inner'}], tags: {type: 'multipolygon'}});
var graph = iD.coreGraph([a, b, c, o, i, r]);
surface.call(iD.svgLines(projection, context), graph, [i, o], all);
@@ -84,14 +88,14 @@ describe('iD.svgLines', function () {
});
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']})
]);
var graph = iD.coreGraph([
iD.osmNode({id: 'a', loc: [0, 0]}),
iD.osmNode({id: 'b', loc: [1, 1]}),
iD.osmNode({id: 'c', loc: [0, 0]}),
iD.osmNode({id: 'd', loc: [1, 1]}),
iD.osmWay({id: 'lo', tags: {highway: 'residential', tunnel: 'yes'}, nodes: ['a', 'b']}),
iD.osmWay({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.svgLines(projection, context), graph, [graph.entity('lo'), graph.entity('hi')], none);
+58 -58
View File
@@ -1,103 +1,103 @@
describe('iD.svgMidpoints', function () {
var context, surface,
selectedIDs = [],
projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(180 / Math.PI)
.clipExtent([[0, 0], [Infinity, Infinity]]),
filter = function() { return true; };
var TAU = 2 * Math.PI;
function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
var context, surface;
var _selectedIDs = [];
var filter = function() { return true; };
var projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(ztok(17))
.clipExtent([[0, 0], [Infinity, Infinity]]);
beforeEach(function () {
context = iD.Context();
context.mode = function() {
return {
id: 'select',
selectedIDs: function() { return selectedIDs; }
};
};
d3.select(document.createElement('div'))
context = iD.coreContext();
context.enter({
id: 'select',
enter: function() { },
exit: function() { },
selectedIDs: function() { return _selectedIDs; }
});
var map = d3.select(document.createElement('div'))
.attr('id', 'map')
.call(context.map());
.call(context.map().centerZoom([0, 0], 17));
surface = context.surface();
});
it('creates midpoint on segment completely within the extent', function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [50, 0]}),
line = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, line]),
extent = iD.geoExtent([0, 0], [100, 100]);
var a = iD.osmNode({loc: [0, 0]});
var b = iD.osmNode({loc: [1, 0]});
var line = iD.osmWay({nodes: [a.id, b.id]});
var graph = iD.coreGraph([a, b, line]);
var extent = iD.geoExtent([0, 0], [1, 1]);
selectedIDs = [line.id];
context.selectedIDs = function() { return selectedIDs; };
_selectedIDs = [line.id];
context.entity = function(id) { return graph.entity(id); };
context.hasEntity = context.entity;
context.hasEntity = function(id) { return graph.entities[id]; };
surface.call(iD.svgMidpoints(projection, context), graph, [line], filter, extent);
expect(surface.selectAll('.midpoint').datum().loc).to.eql([25, 0]);
expect(surface.selectAll('.midpoint').datum().loc).to.eql([0.5, 0]);
});
it('doesn\'t create midpoint on segment with pixel length less than 40', function () {
var a = iD.Node({loc: [0, 0]}),
b = iD.Node({loc: [39, 0]}),
line = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, line]),
extent = iD.geoExtent([0, 0], [100, 100]);
var a = iD.osmNode({loc: [0, 0]});
var b = iD.osmNode({loc: [0.0001, 0]});
var line = iD.osmWay({nodes: [a.id, b.id]});
var graph = iD.coreGraph([a, b, line]);
var extent = iD.geoExtent([0, 0], [1, 1]);
selectedIDs = [line.id];
context.selectedIDs = function() { return selectedIDs; };
_selectedIDs = [line.id];
context.entity = function(id) { return graph.entity(id); };
context.hasEntity = context.entity;
context.hasEntity = function(id) { return graph.entities[id]; };
surface.call(iD.svgMidpoints(projection, context), graph, [line], filter, extent);
expect(surface.selectAll('.midpoint').nodes()).to.have.length(0);
});
it('doesn\'t create midpoint on segment completely outside of the extent', function () {
var a = iD.Node({loc: [-100, 0]}),
b = iD.Node({loc: [-50, 0]}),
line = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, line]),
extent = iD.geoExtent([0, 0], [100, 100]);
var a = iD.osmNode({loc: [-1, 0]});
var b = iD.osmNode({loc: [-0.5, 0]});
var line = iD.osmWay({nodes: [a.id, b.id]});
var graph = iD.coreGraph([a, b, line]);
var extent = iD.geoExtent([0, 0], [1, 1]);
selectedIDs = [line.id];
context.selectedIDs = function() { return selectedIDs; };
_selectedIDs = [line.id];
context.entity = function(id) { return graph.entity(id); };
context.hasEntity = context.entity;
context.hasEntity = function(id) { return graph.entities[id]; };
surface.call(iD.svgMidpoints(projection, context), graph, [line], filter, extent);
expect(surface.selectAll('.midpoint').nodes()).to.have.length(0);
});
it('creates midpoint on extent edge for segment partially outside of the extent', function () {
var a = iD.Node({loc: [50, 0]}),
b = iD.Node({loc: [500, 0]}),
line = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, line]),
extent = iD.geoExtent([0, 0], [100, 100]);
var a = iD.osmNode({loc: [0.5, 0]});
var b = iD.osmNode({loc: [2, 0]});
var line = iD.osmWay({nodes: [a.id, b.id]});
var graph = iD.coreGraph([a, b, line]);
var extent = iD.geoExtent([0, 0], [1, 1]);
selectedIDs = [line.id];
context.selectedIDs = function() { return selectedIDs; };
_selectedIDs = [line.id];
context.entity = function(id) { return graph.entity(id); };
context.hasEntity = context.entity;
context.hasEntity = function(id) { return graph.entities[id]; };
surface.call(iD.svgMidpoints(projection, context), graph, [line], filter, extent);
expect(surface.selectAll('.midpoint').datum().loc).to.eql([100, 0]);
expect(surface.selectAll('.midpoint').datum().loc).to.eql([1, 0]);
});
it('doesn\'t create midpoint on extent edge for segment with pixel length less than 20', function () {
var a = iD.Node({loc: [81, 0]}),
b = iD.Node({loc: [500, 0]}),
line = iD.Way({nodes: [a.id, b.id]}),
graph = iD.Graph([a, b, line]),
extent = iD.geoExtent([0, 0], [100, 100]);
var a = iD.osmNode({loc: [0.9999, 0]});
var b = iD.osmNode({loc: [2, 0]});
var line = iD.osmWay({nodes: [a.id, b.id]});
var graph = iD.coreGraph([a, b, line]);
var extent = iD.geoExtent([0, 0], [1, 1]);
selectedIDs = [line.id];
context.selectedIDs = function() { return selectedIDs; };
_selectedIDs = [line.id];
context.entity = function(id) { return graph.entity(id); };
context.hasEntity = context.entity;
context.hasEntity = function(id) { return graph.entities[id]; };
surface.call(iD.svgMidpoints(projection, context), graph, [line], filter, extent);
expect(surface.selectAll('.midpoint').nodes()).to.have.length(0);
+26 -6
View File
@@ -7,12 +7,32 @@ describe('iD.svgOsm', function () {
it('creates default osm layers', function () {
container.call(iD.svgOsm());
var nodes = container.selectAll('.layer-osm').nodes();
expect(nodes.length).to.eql(4);
expect(d3.select(nodes[0]).classed('layer-areas')).to.be.true;
expect(d3.select(nodes[1]).classed('layer-lines')).to.be.true;
expect(d3.select(nodes[2]).classed('layer-hit')).to.be.true;
expect(d3.select(nodes[3]).classed('layer-labels')).to.be.true;
var layers = container.selectAll('g.layer-osm').nodes();
expect(layers.length).to.eql(4);
expect(d3.select(layers[0]).classed('layer-areas')).to.be.true;
expect(d3.select(layers[1]).classed('layer-lines')).to.be.true;
expect(d3.select(layers[2]).classed('layer-points')).to.be.true;
expect(d3.select(layers[3]).classed('layer-labels')).to.be.true;
});
it('creates default osm point layers', function () {
container.call(iD.svgOsm());
var layers = container.selectAll('g.layer-points g.layer-points-group').nodes();
expect(layers.length).to.eql(5);
expect(d3.select(layers[0]).classed('layer-points-points')).to.be.true;
expect(d3.select(layers[1]).classed('layer-points-midpoints')).to.be.true;
expect(d3.select(layers[2]).classed('layer-points-vertices')).to.be.true;
expect(d3.select(layers[3]).classed('layer-points-turns')).to.be.true;
expect(d3.select(layers[4]).classed('layer-points-targets')).to.be.true;
});
it('creates default osm label layers', function () {
container.call(iD.svgOsm());
var layers = container.selectAll('g.layer-labels g.layer-labels-group').nodes();
expect(layers.length).to.eql(3);
expect(d3.select(layers[0]).classed('layer-labels-halo')).to.be.true;
expect(d3.select(layers[1]).classed('layer-labels-label')).to.be.true;
expect(d3.select(layers[2]).classed('layer-labels-debug')).to.be.true;
});
});
+12 -9
View File
@@ -1,22 +1,25 @@
describe('iD.svgPoints', function () {
var context, surface,
projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(180 / Math.PI)
.clipExtent([[0, 0], [Infinity, Infinity]]);
var TAU = 2 * Math.PI;
function ztok(z) { return 256 * Math.pow(2, z) / TAU; }
var context, surface;
var projection = d3.geoProjection(function(x, y) { return [x, -y]; })
.translate([0, 0])
.scale(ztok(17))
.clipExtent([[0, 0], [Infinity, Infinity]]);
beforeEach(function () {
context = iD.Context();
context = iD.coreContext();
d3.select(document.createElement('div'))
.attr('id', 'map')
.call(context.map());
.call(context.map().centerZoom([0, 0], 17));
surface = context.surface();
});
it('adds tag classes', function () {
var point = iD.Node({tags: {amenity: 'cafe'}, loc: [0, 0]}),
graph = iD.Graph([point]);
var point = iD.osmNode({tags: {amenity: 'cafe'}, loc: [0, 0]});
var graph = iD.coreGraph([point]);
surface.call(iD.svgPoints(projection, context), graph, [point]);
+28 -28
View File
@@ -7,156 +7,156 @@ describe('iD.svgTagClasses', function () {
it('adds no classes to elements whose datum has no tags', function() {
selection
.datum(iD.Entity())
.datum(iD.osmEntity())
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal(null);
});
it('adds classes for primary tag key and key-value', function() {
selection
.datum(iD.Entity({tags: {highway: 'primary'}}))
.datum(iD.osmEntity({tags: {highway: 'primary'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-highway tag-highway-primary');
});
it('adds only one primary tag', function() {
selection
.datum(iD.Entity({tags: {highway: 'primary', railway: 'rail'}}))
.datum(iD.osmEntity({tags: {highway: 'primary', railway: 'rail'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-highway tag-highway-primary');
});
it('orders primary tags', function() {
selection
.datum(iD.Entity({tags: {railway: 'rail', highway: 'primary'}}))
.datum(iD.osmEntity({tags: {railway: 'rail', highway: 'primary'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-highway tag-highway-primary');
});
it('adds status tag when status in primary value (`railway=abandoned`)', function() {
selection
.datum(iD.Entity({tags: {railway: 'abandoned'}}))
.datum(iD.osmEntity({tags: {railway: 'abandoned'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-railway tag-status tag-status-abandoned');
});
it('adds status tag when status in key and value matches "yes" (railway=rail + abandoned=yes)', function() {
selection
.datum(iD.Entity({tags: {railway: 'rail', abandoned: 'yes'}}))
.datum(iD.osmEntity({tags: {railway: 'rail', abandoned: 'yes'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-railway tag-railway-rail tag-status tag-status-abandoned');
});
it('adds status tag when status in key and value matches primary (railway=rail + abandoned=railway)', function() {
selection
.datum(iD.Entity({tags: {railway: 'rail', abandoned: 'railway'}}))
.datum(iD.osmEntity({tags: {railway: 'rail', abandoned: 'railway'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-railway tag-railway-rail tag-status tag-status-abandoned');
});
it('adds primary and status tag when status in key and no primary (abandoned=railway)', function() {
selection
.datum(iD.Entity({tags: {abandoned: 'railway'}}))
.datum(iD.osmEntity({tags: {abandoned: 'railway'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-railway tag-status tag-status-abandoned');
});
it('does not add status tag for different primary tag (highway=path + abandoned=railway)', function() {
selection
.datum(iD.Entity({tags: {highway: 'path', abandoned: 'railway'}}))
.datum(iD.osmEntity({tags: {highway: 'path', abandoned: 'railway'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-highway tag-highway-path');
});
it('adds secondary tags', function() {
selection
.datum(iD.Entity({tags: {highway: 'primary', bridge: 'yes'}}))
.datum(iD.osmEntity({tags: {highway: 'primary', bridge: 'yes'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('tag-highway tag-highway-primary tag-bridge tag-bridge-yes');
});
it('adds no bridge=no tags', function() {
selection
.datum(iD.Entity({tags: {bridge: 'no'}}))
.datum(iD.osmEntity({tags: {bridge: 'no'}}))
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal(null);
});
it('adds tag-unpaved for highway=track with no surface tagging', function() {
selection
.datum(iD.Entity({tags: {highway: 'track'}}))
.datum(iD.osmEntity({tags: {highway: 'track'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.true;
});
it('does not add tag-unpaved for highway=track with explicit paved surface tagging', function() {
selection
.datum(iD.Entity({tags: {highway: 'track', surface: 'asphalt'}}))
.datum(iD.osmEntity({tags: {highway: 'track', surface: 'asphalt'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
selection
.datum(iD.Entity({tags: {highway: 'track', tracktype: 'grade1'}}))
.datum(iD.osmEntity({tags: {highway: 'track', tracktype: 'grade1'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
});
it('adds tag-unpaved for highway=track with explicit unpaved surface tagging', function() {
selection
.datum(iD.Entity({tags: {highway: 'track', surface: 'dirt'}}))
.datum(iD.osmEntity({tags: {highway: 'track', surface: 'dirt'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.true;
selection
.datum(iD.Entity({tags: {highway: 'track', tracktype: 'grade3'}}))
.datum(iD.osmEntity({tags: {highway: 'track', tracktype: 'grade3'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.true;
});
it('does not add tag-unpaved for other highway types with no surface tagging', function() {
selection
.datum(iD.Entity({tags: {highway: 'tertiary'}}))
.datum(iD.osmEntity({tags: {highway: 'tertiary'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
selection
.datum(iD.Entity({tags: {highway: 'foo'}}))
.datum(iD.osmEntity({tags: {highway: 'foo'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
});
it('does not add tag-unpaved for other highway types with explicit paved surface tagging', function() {
selection
.datum(iD.Entity({tags: {highway: 'tertiary', surface: 'asphalt'}}))
.datum(iD.osmEntity({tags: {highway: 'tertiary', surface: 'asphalt'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
selection
.datum(iD.Entity({tags: {highway: 'foo', tracktype: 'grade1'}}))
.datum(iD.osmEntity({tags: {highway: 'foo', tracktype: 'grade1'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
});
it('adds tag-unpaved for other highway types with explicit unpaved surface tagging', function() {
selection
.datum(iD.Entity({tags: {highway: 'tertiary', surface: 'dirt'}}))
.datum(iD.osmEntity({tags: {highway: 'tertiary', surface: 'dirt'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.true;
selection
.datum(iD.Entity({tags: {highway: 'foo', tracktype: 'grade3'}}))
.datum(iD.osmEntity({tags: {highway: 'foo', tracktype: 'grade3'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.true;
});
it('does not add tag-unpaved for non-highways', function() {
selection
.datum(iD.Entity({tags: {railway: 'abandoned', surface: 'gravel'}}))
.datum(iD.osmEntity({tags: {railway: 'abandoned', surface: 'gravel'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
selection
.datum(iD.Entity({tags: {amenity: 'parking', surface: 'dirt'}}))
.datum(iD.osmEntity({tags: {amenity: 'parking', surface: 'dirt'}}))
.call(iD.svgTagClasses());
expect(selection.classed('tag-unpaved')).to.be.false;
});
@@ -164,7 +164,7 @@ describe('iD.svgTagClasses', function () {
it('adds tags based on the result of the `tags` accessor', function() {
var primary = function () { return { highway: 'primary'}; };
selection
.datum(iD.Entity())
.datum(iD.osmEntity())
.call(iD.svgTagClasses().tags(primary));
expect(selection.attr('class')).to.equal('tag-highway tag-highway-primary');
});
@@ -172,7 +172,7 @@ describe('iD.svgTagClasses', function () {
it('removes classes for tags that are no longer present', function() {
selection
.attr('class', 'tag-highway tag-highway-primary')
.datum(iD.Entity())
.datum(iD.osmEntity())
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('');
});
@@ -180,7 +180,7 @@ describe('iD.svgTagClasses', function () {
it('preserves existing non-"tag-"-prefixed classes', function() {
selection
.attr('class', 'selected')
.datum(iD.Entity())
.datum(iD.osmEntity())
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal('selected');
});
@@ -188,7 +188,7 @@ describe('iD.svgTagClasses', function () {
it('works on SVG elements', function() {
selection = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'g'));
selection
.datum(iD.Entity())
.datum(iD.osmEntity())
.call(iD.svgTagClasses());
expect(selection.attr('class')).to.equal(null);
});
+6 -6
View File
@@ -11,19 +11,19 @@ describe('iD.svgVertices', function () {
beforeEach(function () {
context = iD.Context();
context = iD.coreContext();
d3.select(document.createElement('div'))
.attr('id', 'map')
.call(context.map());
.call(context.map().centerZoom([0, 0], 17));
surface = context.surface();
});
it('adds the .shared class to vertices that are members of two or more ways', function () {
var node = iD.Node({loc: [0, 0]});
var way1 = iD.Way({nodes: [node.id], tags: {highway: 'residential'}});
var way2 = iD.Way({nodes: [node.id], tags: {highway: 'residential'}});
var graph = iD.Graph([node, way1, way2]);
var node = iD.osmNode({loc: [0, 0]});
var way1 = iD.osmWay({nodes: [node.id], tags: {highway: 'residential'}});
var way2 = iD.osmWay({nodes: [node.id], tags: {highway: 'residential'}});
var graph = iD.coreGraph([node, way1, way2]);
surface.call(iD.svgVertices(projection, context), graph, [node]);
expect(surface.select('.vertex').classed('shared')).to.be.true;