Merge pull request #918 from systemed/resample-oneway

Resample oneway paths to produce markers.
This commit is contained in:
Tom MacWright
2013-03-07 11:37:26 -08:00
6 changed files with 54 additions and 69 deletions
+4 -7
View File
@@ -695,17 +695,14 @@ text {
opacity: 1;
}
.oneway .textpath {
pointer-events: none;
font-size: 7px;
baseline-shift: 2px;
opacity: .7;
}
.oneway .textpath.tag-waterway {
fill: #002F35;
}
marker#oneway-marker path {
fill:#000;
}
text.tag-oneway {
fill:#91CFFF;
stroke:#2C6B9B;
+29 -2
View File
@@ -13,8 +13,34 @@ iD.svg = {
};
},
LineString: function(projection, graph, dimensions) {
var cache = {};
resample: function(points, dx) {
var o = [];
for (var i = 0; i < points.length - 1; i++) {
var a = points[i], b = points[i + 1],
span = iD.geo.dist(a, b);
o.push(a);
// if there is space to fit one or more oneway mark
// in this segment
if (span > dx) {
// the angle from a to b
var angle = Math.atan2(b[1] - a[1], b[0] - a[0]),
to = points[i].slice();
while (iD.geo.dist(a, to) < (span - dx)) {
// a dx-length line segment in that angle
to[0] += Math.cos(angle) * dx;
to[1] += Math.sin(angle) * dx;
o.push(to.slice());
}
}
o.push(b);
}
return o;
},
LineString: function(projection, graph, dimensions, dx) {
var cache = {},
resample = this.resample;
return function(entity) {
if (cache[entity.id] !== undefined) {
return cache[entity.id];
@@ -34,6 +60,7 @@ iD.svg = {
cache[entity.id] =
segments.map(function(points) {
if (dx) points = resample(points, dx);
return 'M' + points.map(function(p) {
return p[0] + ',' + p[1];
}).join('L');
+5 -55
View File
@@ -1,8 +1,5 @@
iD.svg.Lines = function(projection) {
var arrowtext = '►\u3000\u3000\u3000',
alength;
var highway_stack = {
motorway: 0,
motorway_link: 1,
@@ -92,16 +89,6 @@ iD.svg.Lines = function(projection) {
return paths;
}
if (!alength) {
var container = surface.append('g')
.attr('class', 'oneway'),
arrow = container.append('text')
.attr('class', 'textpath')
.text(arrowtext);
alength = arrow.node().getComputedTextLength();
container.remove();
}
var lines = [];
for (var i = 0; i < entities.length; i++) {
@@ -117,6 +104,7 @@ 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 shadow = surface.select('.layer-shadow'),
casing = surface.select('.layer-casing'),
@@ -127,47 +115,9 @@ iD.svg.Lines = function(projection) {
casings = drawPaths(casing, lines, filter, 'casing', lineString),
strokes = drawPaths(stroke, lines, filter, 'stroke', lineString);
// Determine the lengths of oneway paths
var lengths = {},
oneways = strokes.filter(function(d) { return d.isOneWay(); }).each(function(d) {
lengths[d.id] = Math.floor(this.getTotalLength() / alength);
}).data();
var uses = defs.selectAll('path')
.filter(filter)
.data(oneways, iD.Entity.key);
uses.enter()
.append('path');
uses
.attr('id', function(d) { return 'shadow-' + d.id; })
.attr('d', lineString);
uses.exit()
.remove();
var labels = text.selectAll('text')
.filter(filter)
.data(oneways, iD.Entity.key);
var tagClasses = iD.svg.TagClasses();
var tp = labels.enter()
.append('text')
.attr({ 'class': 'oneway', dy: 4 })
.append('textPath')
.attr('class', 'textpath')
.call(tagClasses);
labels.exit().remove();
text.selectAll('.textpath')
.filter(filter)
.attr('xlink:href', function(d) { return '#shadow-' + d.id; })
.text(function(d) {
// adding longer text than necessary, since overflow is hidden
return (new Array(Math.floor(lengths[d.id] * 1.1))).join(arrowtext);
});
strokes
.filter(function(d) { return d.isOneWay(); })
.attr('marker-mid', 'url(#oneway-marker)')
.attr('d', lineStringResampled);
};
};
+12 -1
View File
@@ -1,6 +1,17 @@
iD.svg.Surface = function() {
return function drawSurface(selection) {
selection.append('defs');
var defs = selection.append('defs');
defs.append('marker')
.attr({
id: 'oneway-marker',
viewBox: '0 0 10 10',
refY: 2.5,
markerWidth: 2,
markerHeight: 2,
orient: 'auto'
})
.append('path')
.attr('d', 'M 0 0 L 5 2.5 L 0 5 z');
var layers = selection.selectAll('.layer')
.data(['fill', 'shadow', 'casing', 'stroke', 'text', 'hit', 'halo', 'label']);
+2 -2
View File
@@ -14,8 +14,8 @@ describe("iD.svg.Areas", function () {
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');
expect(surface.select('path.way')).to.be.classed('way');
expect(surface.select('path.area')).to.be.classed('area');
});
it("adds tag classes", function () {
+2 -2
View File
@@ -17,8 +17,8 @@ describe("iD.svg.Lines", function () {
surface.call(iD.svg.Lines(projection), graph, [line], filter, dimensions);
expect(surface.select('path')).to.be.classed('way');
expect(surface.select('path')).to.be.classed('line');
expect(surface.select('path.way')).to.be.classed('way');
expect(surface.select('path.line')).to.be.classed('line');
});
it("adds tag classes", function () {