mirror of
https://github.com/FoggedLens/iD.git
synced 2026-02-14 09:42:56 +00:00
Merge branch 'perfect-resampling'
Conflicts: js/id/renderer/map.js
This commit is contained in:
@@ -823,11 +823,8 @@ marker#oneway-marker path {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
text.tag-oneway {
|
||||
fill:#91CFFF;
|
||||
stroke:#2C6B9B;
|
||||
stroke-width:1;
|
||||
pointer-events:none;
|
||||
path.oneway {
|
||||
stroke-width: 6px;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -123,7 +123,7 @@ iD.Map = function(context) {
|
||||
surface
|
||||
.call(points, graph, all, filter)
|
||||
.call(vertices, graph, all, filter, map.zoom())
|
||||
.call(lines, graph, all, filter, dimensions)
|
||||
.call(lines, graph, all, filter)
|
||||
.call(areas, graph, all, filter)
|
||||
.call(midpoints, graph, all, filter, extent)
|
||||
.call(labels, graph, all, filter, dimensions, !difference);
|
||||
|
||||
85
js/id/svg.js
85
js/id/svg.js
@@ -13,18 +13,23 @@ iD.svg = {
|
||||
};
|
||||
},
|
||||
|
||||
LineString: function(projection, graph, dimensions, dx) {
|
||||
var cache = {};
|
||||
LineString: function(projection, graph) {
|
||||
var cache = {},
|
||||
path = d3.geo.path().projection(projection);
|
||||
|
||||
return function(entity) {
|
||||
if (cache[entity.id] !== undefined) {
|
||||
return cache[entity.id];
|
||||
}
|
||||
if (entity.id in cache) return cache[entity.id];
|
||||
return cache[entity.id] = path(entity.asGeoJSON(graph));
|
||||
};
|
||||
},
|
||||
|
||||
var last,
|
||||
next,
|
||||
started = false,
|
||||
d = '';
|
||||
OneWaySegments: function(projection, graph, dt) {
|
||||
return function(entity) {
|
||||
var a,
|
||||
b,
|
||||
i = 0,
|
||||
offset = dt,
|
||||
segments = [];
|
||||
|
||||
d3.geo.stream({
|
||||
type: 'LineString',
|
||||
@@ -32,40 +37,46 @@ iD.svg = {
|
||||
return n.loc;
|
||||
})
|
||||
}, projection.stream({
|
||||
lineStart: function() { last = null; started = false; },
|
||||
lineEnd: function() { },
|
||||
lineStart: function() {},
|
||||
lineEnd: function() {},
|
||||
point: function(x, y) {
|
||||
if (!started) d += 'M';
|
||||
next = [Math.floor(x), Math.floor(y)];
|
||||
if (dx && last && iD.geo.dist(last, next) > dx) {
|
||||
var span = iD.geo.dist(last, next),
|
||||
angle = Math.atan2(next[1] - last[1], next[0] - last[0]),
|
||||
to = last.slice();
|
||||
to[0] += Math.cos(angle) * dx;
|
||||
to[1] += Math.sin(angle) * dx;
|
||||
while (iD.geo.dist(last, to) < (span)) {
|
||||
// a dx-length line segment in that angle
|
||||
if (started) d += 'L';
|
||||
d += Math.floor(to[0]) + ',' + Math.floor(to[1]);
|
||||
started = started || true;
|
||||
to[0] += Math.cos(angle) * dx;
|
||||
to[1] += Math.sin(angle) * dx;
|
||||
b = [x, y];
|
||||
|
||||
if (a) {
|
||||
var segment = 'M' + a[0] + ',' + a[1];
|
||||
|
||||
var span = iD.geo.dist(a, b),
|
||||
angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
|
||||
dx = dt * Math.cos(angle),
|
||||
dy = dt * Math.sin(angle),
|
||||
p;
|
||||
|
||||
if (offset < span) {
|
||||
p = [a[0] + offset * Math.cos(angle),
|
||||
a[1] + offset * Math.sin(angle)];
|
||||
|
||||
segment += 'L' + p[0] + ',' + p[1];
|
||||
}
|
||||
|
||||
while ((offset + dt) < span) {
|
||||
offset += dt;
|
||||
p[0] += dx;
|
||||
p[1] += dy;
|
||||
segment += 'L' + p[0] + ',' + p[1];
|
||||
}
|
||||
|
||||
offset = dt - (span - offset);
|
||||
|
||||
segment += 'L' + b[0] + ',' + b[1];
|
||||
segments.push({id: entity.id, index: i, d: segment});
|
||||
i++;
|
||||
}
|
||||
if (started) d += 'L';
|
||||
d += next[0] + ',' + next[1];
|
||||
started = started || true;
|
||||
last = next;
|
||||
|
||||
a = b;
|
||||
}
|
||||
}));
|
||||
|
||||
if (d === '') {
|
||||
cache[entity.id] = null;
|
||||
return cache[entity.id];
|
||||
} else {
|
||||
cache[entity.id] = d;
|
||||
return cache[entity.id];
|
||||
}
|
||||
return segments;
|
||||
};
|
||||
},
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ iD.svg.Lines = function(projection) {
|
||||
return outer;
|
||||
}
|
||||
|
||||
return function drawLines(surface, graph, entities, filter, dimensions) {
|
||||
return function drawLines(surface, graph, entities, filter) {
|
||||
function drawPaths(group, lines, filter, klass, lineString) {
|
||||
lines = lines.filter(function(line) {
|
||||
return lineString(line);
|
||||
@@ -105,21 +105,35 @@ iD.svg.Lines = function(projection) {
|
||||
|
||||
lines.sort(waystack);
|
||||
|
||||
var lineString = iD.svg.LineString(projection, graph, dimensions);
|
||||
var lineStringResampled = iD.svg.LineString(projection, graph, dimensions, 35);
|
||||
var lineString = iD.svg.LineString(projection, graph);
|
||||
|
||||
var shadow = surface.select('.layer-shadow'),
|
||||
casing = surface.select('.layer-casing'),
|
||||
stroke = surface.select('.layer-stroke'),
|
||||
defs = surface.select('defs'),
|
||||
text = surface.select('.layer-text'),
|
||||
shadows = drawPaths(shadow, lines, filter, 'shadow', lineString),
|
||||
casings = drawPaths(casing, lines, filter, 'casing', lineString),
|
||||
strokes = drawPaths(stroke, lines, filter, 'stroke', lineString);
|
||||
oneway = surface.select('.layer-oneway');
|
||||
|
||||
strokes
|
||||
.filter(function(d) { return d.isOneWay(); })
|
||||
.attr('marker-mid', 'url(#oneway-marker)')
|
||||
.attr('d', lineStringResampled);
|
||||
drawPaths(shadow, lines, filter, 'shadow', lineString);
|
||||
drawPaths(casing, lines, filter, 'casing', lineString);
|
||||
drawPaths(stroke, lines, filter, 'stroke', lineString);
|
||||
|
||||
var segments = _.flatten(lines
|
||||
.filter(function(d) { return d.isOneWay(); })
|
||||
.map(iD.svg.OneWaySegments(projection, graph, 35)));
|
||||
|
||||
var oneways = oneway.selectAll('path.oneway')
|
||||
.data(segments, function(d) { return [d.id, d.index]; });
|
||||
|
||||
oneways.enter()
|
||||
.append('path')
|
||||
.attr('class', 'oneway')
|
||||
.attr('marker-mid', 'url(#oneway-marker)');
|
||||
|
||||
oneways
|
||||
.order()
|
||||
.attr('d', function(d) { return d.d; });
|
||||
|
||||
oneways.exit()
|
||||
.remove();
|
||||
};
|
||||
};
|
||||
|
||||
@@ -34,12 +34,13 @@ iD.svg.Surface = function(context) {
|
||||
id: 'oneway-marker',
|
||||
viewBox: '0 0 10 10',
|
||||
refY: 2.5,
|
||||
refX: 5,
|
||||
markerWidth: 2,
|
||||
markerHeight: 2,
|
||||
orient: 'auto'
|
||||
})
|
||||
.append('path')
|
||||
.attr('d', 'M 0 0 L 5 2.5 L 0 5 z');
|
||||
.attr('d', 'M 5 3 L 0 3 L 0 2 L 5 2 L 5 0 L 10 2.5 L 5 5 z');
|
||||
|
||||
var patterns = defs.selectAll('pattern')
|
||||
.data([
|
||||
@@ -109,7 +110,7 @@ iD.svg.Surface = function(context) {
|
||||
maki));
|
||||
|
||||
var layers = selection.selectAll('.layer')
|
||||
.data(['fill', 'shadow', 'casing', 'stroke', 'text', 'hit', 'halo', 'label']);
|
||||
.data(['fill', 'shadow', 'casing', 'stroke', 'oneway', 'hit', 'halo', 'label']);
|
||||
|
||||
layers.enter().append('g')
|
||||
.attr('class', function(d) { return 'layer layer-' + d; });
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
describe("iD.svg.LineString", function () {
|
||||
var projection = d3.geo.mercator().scale(250 / Math.PI);
|
||||
|
||||
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.id, b.id]}),
|
||||
graph = iD.Graph([a, b, way]);
|
||||
|
||||
expect(iD.svg.LineString(projection, graph, [10, 10])(way)).to.equal('M480,250L482,245');
|
||||
});
|
||||
|
||||
describe('resampling', function() {
|
||||
it("resamples a linestring", function () {
|
||||
var a = iD.Node({loc: [0, 0]}),
|
||||
b = iD.Node({loc: [10, 0]}),
|
||||
way = iD.Way({nodes: [a.id, b.id]}),
|
||||
graph = iD.Graph([a, b, way]);
|
||||
|
||||
expect(iD.svg.LineString(projection, graph, [10, 10], 2)(way)).to.equal('M480,250L482,250L484,250L486,250L488,250L490,250L492,250L493,250');
|
||||
});
|
||||
|
||||
it("does not resmample when no steps are possible", function () {
|
||||
var a = iD.Node({loc: [0, 0]}),
|
||||
b = iD.Node({loc: [10, 0]}),
|
||||
way = iD.Way({nodes: [a.id, b.id]}),
|
||||
graph = iD.Graph([a, b, way]);
|
||||
|
||||
expect(iD.svg.LineString(projection, graph, [10, 10], 20)(way)).to.equal('M480,250L493,250');
|
||||
});
|
||||
});
|
||||
|
||||
it("returns null for an entity with no nodes", function () {
|
||||
var way = iD.Way(),
|
||||
graph = iD.Graph([way]);
|
||||
|
||||
expect(iD.svg.LineString(projection, graph, [10, 10])(way)).to.be.null;
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,7 +15,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, dimensions);
|
||||
surface.call(iD.svg.Lines(projection), graph, [line], filter);
|
||||
|
||||
expect(surface.select('path.way')).to.be.classed('way');
|
||||
expect(surface.select('path.line')).to.be.classed('line');
|
||||
@@ -27,7 +27,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, dimensions);
|
||||
surface.call(iD.svg.Lines(projection), graph, [line], filter);
|
||||
|
||||
expect(surface.select('.line')).to.be.classed('tag-highway');
|
||||
expect(surface.select('.line')).to.be.classed('tag-highway-residential');
|
||||
@@ -40,7 +40,7 @@ describe("iD.svg.Lines", function () {
|
||||
relation = iD.Relation({members: [{id: line.id}], tags: {type: 'route'}}),
|
||||
graph = iD.Graph([a, b, line, relation]);
|
||||
|
||||
surface.call(iD.svg.Lines(projection), graph, [line], filter, dimensions);
|
||||
surface.call(iD.svg.Lines(projection), graph, [line], filter);
|
||||
|
||||
expect(surface.select('.line')).to.be.classed('member');
|
||||
expect(surface.select('.line')).to.be.classed('member-type-route');
|
||||
@@ -53,7 +53,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, dimensions);
|
||||
surface.call(iD.svg.Lines(projection), graph, [line], filter);
|
||||
|
||||
expect(surface.select('.stroke')).to.be.classed('tag-natural-wood');
|
||||
});
|
||||
@@ -66,7 +66,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, dimensions);
|
||||
surface.call(iD.svg.Lines(projection), graph, [w], filter);
|
||||
|
||||
expect(surface.select('.stroke')).to.be.classed('tag-natural-wood');
|
||||
});
|
||||
@@ -80,7 +80,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, dimensions);
|
||||
surface.call(iD.svg.Lines(projection), graph, [i], filter);
|
||||
|
||||
expect(surface.select('.stroke')).to.be.classed('tag-natural-wood');
|
||||
});
|
||||
@@ -93,7 +93,7 @@ describe("iD.svg.Lines", function () {
|
||||
.append('path')
|
||||
.attr('class', 'other');
|
||||
|
||||
surface.call(iD.svg.Lines(projection), graph, [line], filter, dimensions);
|
||||
surface.call(iD.svg.Lines(projection), graph, [line], filter);
|
||||
|
||||
expect(surface.selectAll('.other')[0].length).to.equal(1);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user