Skip to content

Commit

Permalink
Support rendering direction on vertices (stop sign, traffic_signals…
Browse files Browse the repository at this point in the history
…, etc)

(closes #3815)
  • Loading branch information
bhousel committed Dec 7, 2017
1 parent 6cfe7a2 commit 67d7c5b
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 26 deletions.
4 changes: 2 additions & 2 deletions css/20_map.css
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,11 @@ text {
fill: #002F35;
}

path.oneway {
.directiongroup path.directional,
.onewaygroup path.oneway {
stroke-width: 6px;
}


text.arealabel-halo,
text.linelabel-halo,
text.pointlabel-halo,
Expand Down
26 changes: 22 additions & 4 deletions modules/svg/defs.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,42 @@ export function svgDefs(context) {
return function drawDefs(selection) {
var defs = selection.append('defs');

// marker
// oneway marker
defs.append('marker')
.attr('id', 'oneway-marker')
.attr('viewBox', '0 0 10 10')
.attr('refY', 2.5)
.attr('viewBox', '0 0 10 5')
.attr('refX', 5)
.attr('refY', 2.5)
.attr('markerWidth', 2)
.attr('markerHeight', 2)
.attr('markerUnits', 'strokeWidth')
.attr('orient', 'auto')

.append('path')
.attr('class', 'oneway')
.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')
.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')
.attr('stroke', 'none')
.attr('fill', '#000')
.attr('opacity', '0.75');

defs.append('marker')
.attr('id', 'directional-marker')
.attr('viewBox', '0 0 15 5')
.attr('refX', 5.5)
.attr('refY', 2.5)
.attr('markerWidth', 7)
.attr('markerHeight', 7)
.attr('markerUnits', 'strokeWidth')
.attr('orient', 'auto')

.append('path')
.attr('class', 'directional')
.attr('d', 'M 10,2.5 L 9,0 L 14,2.5 L 9,5 z')
.attr('stroke', '#fff')
.attr('fill', '#333')
.attr('stroke-width', '0.5px')
.attr('stroke-opacity', '0.75');

// patterns
var patterns = defs.selectAll('pattern')
.data([
Expand Down
87 changes: 67 additions & 20 deletions modules/svg/vertices.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import _values from 'lodash-es/values';

import { dataFeatureIcons } from '../../data';
import { geoAngle } from '../geo';
import { osmEntity } from '../osm';
import { svgPointTransform } from './index';

Expand Down Expand Up @@ -56,27 +57,64 @@ export function svgVertices(projection, context) {


function draw(selection, vertices, klass, graph, zoom, siblings) {
siblings = siblings || {};
var icons = {};
var directions = {};
var z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);


function icon(entity) {
function getIcon(entity) {
if (entity.id in icons) return icons[entity.id];

icons[entity.id] =
entity.hasInterestingTags() &&
context.presets().match(entity, graph).icon;
return icons[entity.id];
}

function getDirections(entity) {
if (entity.id in directions) return directions[entity.id];

var dir = (entity.tags['traffic_signals:direction'] || entity.tags.direction || '').toLowerCase();
var stop = (entity.tags.stop || '').toLowerCase();
var goBackward = (dir === 'backward' || dir === 'both' || stop === 'all');
var goForward = (dir === 'forward' || dir === 'both' || stop === 'all');
if (!goForward && !goBackward) return;

var nodeIds = {};
graph.parentWays(entity).forEach(function (parent) {
var nodes = parent.nodes;
for (var i = 0; i < nodes.length; i++) {
if (nodes[i] === entity.id) { // match current entity
if (goBackward && i > 0) {
nodeIds[nodes[i - 1]] = true;
}
if (goForward && i < nodes.length - 1) {
nodeIds[nodes[i + 1]] = true;
}
}
}
});

var dirAngles = Object.keys(nodeIds).map(function (nodeId) {
return geoAngle(entity, graph.entity(nodeId), projection) * (180 / Math.PI);
});
directions[entity.id] = dirAngles;
return directions[entity.id];
}

function setClass(klass) {
return function(entity) {
this.setAttribute('class', 'node vertex ' + klass + ' ' + entity.id);
};
}

function setAttributes(selection) {
function updateAttributes(selection) {
['shadow','stroke','fill'].forEach(function(klass) {
var rads = radiuses[klass];
selection.selectAll('.' + klass)
.each(function(entity) {
var i = z && icon(entity),
var i = z && getIcon(entity),
c = i ? 0.5 : 0,
r = rads[i ? 3 : z];

Expand All @@ -97,20 +135,12 @@ export function svgVertices(projection, context) {
});

selection.selectAll('use')
.each(function() {
if (z) {
this.removeAttribute('visibility');
} else {
this.setAttribute('visibility', 'hidden');
}
});
}

.attr('visibility', (z === 0 ? 'hidden' : null));

siblings = siblings || {};
selection.selectAll('.directiongroup')
.attr('visibility', (zoom < 18 ? 'hidden' : null));
}

var icons = {},
z = (zoom < 17 ? 0 : zoom < 18 ? 1 : 2);

var groups = selection
.data(vertices, osmEntity.key);
Expand All @@ -122,18 +152,34 @@ export function svgVertices(projection, context) {
.append('g')
.attr('class', function(d) { return 'node vertex ' + klass + ' ' + d.id; });

enter.append('circle')
// Directional vertices get arrows
var directionsEnter = enter.filter(function(d) { return getDirections(d); })
.append('g')
.each(setClass('directiongroup'));

directionsEnter.selectAll('.directional')
.data(function(d) { return getDirections(d); })
.enter()
.append('path')
.attr('class', 'directional')
.attr('transform', function(d) { return 'rotate(' + d + ')'; })
.attr('d', 'M0,0H0')
.attr('marker-start', 'url(#directional-marker)');

enter
.append('circle')
.each(setClass('shadow'));

enter.append('circle')
enter
.append('circle')
.each(setClass('stroke'));

// Vertices with icons get a `use`.
enter.filter(function(d) { return icon(d); })
enter.filter(function(d) { return getIcon(d); })
.append('use')
.attr('transform', 'translate(-5, -6)')
.attr('xlink:href', function(d) {
var picon = icon(d),
var picon = getIcon(d),
isMaki = dataFeatureIcons.indexOf(picon) !== -1;
return '#' + picon + (isMaki ? '-11' : '');
})
Expand All @@ -146,13 +192,14 @@ export function svgVertices(projection, context) {
.append('circle')
.each(setClass('fill'));

// Update
groups
.merge(enter)
.attr('transform', svgPointTransform(projection))
.classed('sibling', function(entity) { return entity.id in siblings; })
.classed('shared', function(entity) { return graph.isShared(entity); })
.classed('endpoint', function(entity) { return entity.isEndpoint(graph); })
.call(setAttributes);
.call(updateAttributes);
}


Expand Down

0 comments on commit 67d7c5b

Please sign in to comment.