modules/svg/turns.js (91 lines of code) (raw):

import { geoAngle, geoPathLength } from '../geo'; export function svgTurns(projection, context) { function icon(turn) { var u = turn.u ? '-u' : ''; if (turn.no) return '#iD-turn-no' + u; if (turn.only) return '#iD-turn-only' + u; return '#iD-turn-yes' + u; } function drawTurns(selection, graph, turns) { function turnTransform(d) { var pxRadius = 50; var toWay = graph.entity(d.to.way); var toPoints = graph.childNodes(toWay) .map(function (n) { return n.loc; }) .map(projection); var toLength = geoPathLength(toPoints); var mid = toLength / 2; // midpoint of destination way var toNode = graph.entity(d.to.node); var toVertex = graph.entity(d.to.vertex); var a = geoAngle(toVertex, toNode, projection); var o = projection(toVertex.loc); var r = d.u ? 0 // u-turn: no radius : !toWay.__via ? pxRadius // leaf way: put marker at pxRadius : Math.min(mid, pxRadius); // via way: prefer pxRadius, fallback to mid for very short ways return 'translate(' + (r * Math.cos(a) + o[0]) + ',' + (r * Math.sin(a) + o[1]) + ') ' + 'rotate(' + a * 180 / Math.PI + ')'; } var drawLayer = selection.selectAll('.layer-osm.points .points-group.turns'); var touchLayer = selection.selectAll('.layer-touch.turns'); // Draw turns.. var groups = drawLayer.selectAll('g.turn') .data(turns, function(d) { return d.key; }); // exit groups.exit() .remove(); // enter var groupsEnter = groups.enter() .append('g') .attr('class', function(d) { return 'turn ' + d.key; }); var turnsEnter = groupsEnter .filter(function(d) { return !d.u; }); turnsEnter.append('rect') .attr('transform', 'translate(-22, -12)') .attr('width', '44') .attr('height', '24'); turnsEnter.append('use') .attr('transform', 'translate(-22, -12)') .attr('width', '44') .attr('height', '24'); var uEnter = groupsEnter .filter(function(d) { return d.u; }); uEnter.append('circle') .attr('r', '16'); uEnter.append('use') .attr('transform', 'translate(-16, -16)') .attr('width', '32') .attr('height', '32'); // update groups = groups .merge(groupsEnter) .attr('opacity', function(d) { return d.direct === false ? '0.7' : null; }) .attr('transform', turnTransform); groups.select('use') .attr('xlink:href', icon); groups.select('rect'); // propagate bound data groups.select('circle'); // propagate bound data // Draw touch targets.. var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor '; groups = touchLayer.selectAll('g.turn') .data(turns, function(d) { return d.key; }); // exit groups.exit() .remove(); // enter groupsEnter = groups.enter() .append('g') .attr('class', function(d) { return 'turn ' + d.key; }); turnsEnter = groupsEnter .filter(function(d) { return !d.u; }); turnsEnter.append('rect') .attr('class', 'target ' + fillClass) .attr('transform', 'translate(-22, -12)') .attr('width', '44') .attr('height', '24'); uEnter = groupsEnter .filter(function(d) { return d.u; }); uEnter.append('circle') .attr('class', 'target ' + fillClass) .attr('r', '16'); // update groups = groups .merge(groupsEnter) .attr('transform', turnTransform); groups.select('rect'); // propagate bound data groups.select('circle'); // propagate bound data return this; } return drawTurns; }