From 1612326ffab460ffc3ffcadaa244a8e8b11e83d6 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 13 Feb 2018 17:25:49 -0500 Subject: [PATCH] Move dist/via sliders to bottom, add imperial/metric conversion --- css/80_app.css | 35 +++++- modules/osm/intersection.js | 29 ++--- modules/ui/fields/restrictions.js | 182 +++++++++++++++++++++--------- 3 files changed, 170 insertions(+), 76 deletions(-) diff --git a/css/80_app.css b/css/80_app.css index 234a4c7f3..0a9ddb54d 100644 --- a/css/80_app.css +++ b/css/80_app.css @@ -1834,21 +1834,44 @@ input[type=number] { /* Restrictions editor */ -.form-field-restrictions .restriction-detail { - padding: 5px 10px; +.form-field-restrictions .restriction-controls-container { background-color: #fff; - height: 30px; + border-top: 1px solid #ccc; + width: 100%; + padding: 5px; } -.restriction-detail input { +.restriction-controls-container .restriction-controls { + display: table; +} + +.restriction-controls .restriction-control { + display: table-row; + padding: 5px 10px; + height: 25px; +} + +.restriction-control input, +.restriction-control span { + display: table-cell; + text-align: start; + padding: 0px 5px; +} + +.restriction-control span.restriction-control-label { + text-align: end; +} + +.restriction-control input { width: 60px; - margin: 0px 10px; + padding: 0; + margin: 0px 5px; vertical-align: middle; } .form-field-restrictions .restriction-container { position: relative; - height: 400px; + height: 370px; } .form-field-restrictions svg.surface { diff --git a/modules/osm/intersection.js b/modules/osm/intersection.js index 4f91320e9..c728e500f 100644 --- a/modules/osm/intersection.js +++ b/modules/osm/intersection.js @@ -29,8 +29,9 @@ export function osmTurn(turn) { } -export function osmIntersection(graph, startVertexId) { - var vgraph = coreGraph(); // virtual graph +export function osmIntersection(graph, startVertexId, maxDistance) { + maxDistance = maxDistance || 30; // in meters + var vgraph = coreGraph(); // virtual graph var i, j, k; @@ -63,7 +64,6 @@ export function osmIntersection(graph, startVertexId) { } - var distCutoff = 30; // meters var startNode = graph.entity(startVertexId); var checkVertices = [startNode]; var checkWays; @@ -109,7 +109,7 @@ export function osmIntersection(graph, startVertexId) { if (node === vertex) continue; // same thing if (vertices.indexOf(node) !== -1) continue; // seen it already if (node.loc && startNode.loc && - geoSphericalDistance(node.loc, startNode.loc) > distCutoff) continue; // too far from start + geoSphericalDistance(node.loc, startNode.loc) > maxDistance) continue; // too far from start // a key vertex will have parents that are also roads var hasParents = false; @@ -355,7 +355,6 @@ export function osmIntersection(graph, startVertexId) { }); - // OK! Here is our intersection.. var intersection = { graph: vgraph, @@ -374,13 +373,9 @@ export function osmIntersection(graph, startVertexId) { // // For each path found, generate and return a `osmTurn` datastructure. // - // detail = 0 - via node only - // detail = 1 - via node / 1 via way - // detail = 2 - via node / up to 2 via ways - // - intersection.turns = function(fromWayId, detail) { + intersection.turns = function(fromWayId, maxViaWay) { if (!fromWayId) return []; - if (!detail) detail = 0; + if (!maxViaWay) maxViaWay = 0; var vgraph = intersection.graph; var keyVertexIds = intersection.vertices.map(function(v) { return v.id; }); @@ -389,11 +384,11 @@ export function osmIntersection(graph, startVertexId) { var start = vgraph.entity(fromWayId); if (!start || !(start.__from || start.__via)) return []; - // detail=0 from-*-to (0 vias) - // detail=1 from-*-via-*-to (1 via max) - // detail=2 from-*-via-*-via-*-to (2 vias max) - var maxPathLength = (detail * 2) + 3; - var maxStepDist = 30; // meters + // maxViaWay=0 from-*-to (0 vias) + // maxViaWay=1 from-*-via-*-to (1 via max) + // maxViaWay=2 from-*-via-*-via-*-to (2 vias max) + var maxPathLength = (maxViaWay * 2) + 3; + var maxDistance = 30; // meters var turns = []; step(start); @@ -499,7 +494,7 @@ export function osmIntersection(graph, startVertexId) { nextNodes = []; if (currPath.length > 1) { - if (dist > maxStepDist) return; // the next node is too far + if (dist > maxDistance) return; // the next node is too far if (!entity.__via) return; // this way is a leaf / can't be a via } diff --git a/modules/ui/fields/restrictions.js b/modules/ui/fields/restrictions.js index 2317c2f5b..acb2c5295 100644 --- a/modules/ui/fields/restrictions.js +++ b/modules/ui/fields/restrictions.js @@ -41,6 +41,8 @@ import { utilRebind } from '../../util'; +import { utilDetect } from '../../util/detect'; + import { utilGetDimensions, utilSetDimensions @@ -51,11 +53,15 @@ export function uiFieldRestrictions(field, context) { var dispatch = d3_dispatch('change'); var breathe = behaviorBreathe(context); var hover = behaviorHover(context); - var storedDetail = context.storage('turn-restriction-detail'); + var storedViaWay = context.storage('turn-restriction-via-way'); + var storedDistance = context.storage('turn-restriction-distance'); + var isImperial = (utilDetect().locale.toLowerCase() === 'en-us'); - var _detail = storedDetail !== null ? (+storedDetail) : 0; + var _maxViaWay = storedViaWay !== null ? (+storedViaWay) : 1; + var _maxDistance = storedDistance ? (+storedDistance) : 30; var _initialized = false; - var _container = d3_select(null); + var _parent = d3_select(null); // the entire field + var _container = d3_select(null); // just the map var _graph; var _vertexID; var _intersection; @@ -63,10 +69,12 @@ export function uiFieldRestrictions(field, context) { function restrictions(selection) { + _parent = selection; + // try to reuse the intersection, but always rebuild it if the graph has changed if (_vertexID && (context.graph() !== _graph || !_intersection)) { _graph = context.graph(); - _intersection = osmIntersection(_graph, _vertexID); + _intersection = osmIntersection(_graph, _vertexID, _maxDistance); } // It's possible for there to be no actual intersection here. @@ -95,52 +103,10 @@ export function uiFieldRestrictions(field, context) { var isComplex = (isOK && _intersection.vertices.length > 1); - var detailControl = wrap.selectAll('.restriction-detail') - .data(isComplex ? [0]: []); - - detailControl.exit() - .remove(); - - var detailControlEnter = detailControl.enter() - .append('div') - .attr('class', 'restriction-detail'); - - detailControlEnter - .append('span') - .attr('class', 'restriction-detail-label') - .text('Max Detail: '); - - detailControlEnter - .append('input') - .attr('class', 'restriction-detail-input') - .attr('type', 'range') - .attr('min', '0') - .attr('max', '2') - .attr('step', '1') - .on('input', function() { - var val = d3_select(this).property('value'); - _detail = +val; - _container.selectAll('.layer-osm .layer-turns *').remove(); - context.storage('turn-restriction-detail', _detail); - selection.call(restrictions); - }); - - detailControlEnter - .append('span') - .attr('class', 'restriction-detail-text'); - - // update - wrap.selectAll('.restriction-detail-input') - .property('value', _detail); - - var t = ['via node only', 'via 1 way', 'via 2 ways']; - wrap.selectAll('.restriction-detail-text') - .text(t[_detail]); - - var container = wrap.selectAll('.restriction-container') .data([0]); + // enter var containerEnter = container.enter() .append('div') .attr('class', 'restriction-container'); @@ -149,11 +115,121 @@ export function uiFieldRestrictions(field, context) { .append('div') .attr('class', 'restriction-help'); + // update _container = containerEnter - .merge(container); - - _container + .merge(container) .call(renderViewer); + + + var controls = wrap.selectAll('.restriction-controls') + .data([0]); + + // enter/update + controls.enter() + .append('div') + .attr('class', 'restriction-controls-container') + .append('div') + .attr('class', 'restriction-controls') + .merge(controls) + .call(renderControls); + } + + + function renderControls(selection) { + var distControl = selection.selectAll('.restriction-distance') + .data([0]); + + distControl.exit() + .remove(); + + var distControlEnter = distControl.enter() + .append('div') + .attr('class', 'restriction-control restriction-distance'); + + distControlEnter + .append('span') + .attr('class', 'restriction-control-label restriction-distance-label') + .text('Distance:'); + + distControlEnter + .append('input') + .attr('class', 'restriction-distance-input') + .attr('type', 'range') + .attr('min', '20') + .attr('max', '50') + .attr('step', '5') + .on('input', function() { + var val = d3_select(this).property('value'); + _maxDistance = +val; + _intersection = null; + _container.selectAll('.layer-osm .layer-turns *').remove(); + context.storage('turn-restriction-distance', _maxDistance); + _parent.call(restrictions); + }); + + distControlEnter + .append('span') + .attr('class', 'restriction-distance-text'); + + // update + selection.selectAll('.restriction-distance-input') + .property('value', _maxDistance); + + var distDisplay; + if (isImperial) { // imprecise conversion for prettier display + var distToFeet = { + 20: 70, 25: 85, 30: 100, 35: 115, 40: 130, 45: 145, 50: 160 + }[_maxDistance]; + distDisplay = 'Up to ' + distToFeet + ' feet'; + } else { + distDisplay = 'Up to ' + _maxDistance + ' meters'; + } + + selection.selectAll('.restriction-distance-text') + .text(distDisplay); + + + var viaControl = selection.selectAll('.restriction-via-way') + .data([0]); + + viaControl.exit() + .remove(); + + var viaControlEnter = viaControl.enter() + .append('div') + .attr('class', 'restriction-control restriction-via-way'); + + viaControlEnter + .append('span') + .attr('class', 'restriction-control-label restriction-via-way-label') + .text('Via:'); + + viaControlEnter + .append('input') + .attr('class', 'restriction-via-way-input') + .attr('type', 'range') + .attr('min', '0') + .attr('max', '2') + .attr('step', '1') + .on('input', function() { + var val = d3_select(this).property('value'); + _maxViaWay = +val; + _container.selectAll('.layer-osm .layer-turns *').remove(); + context.storage('turn-restriction-via-way', _maxViaWay); + _parent.call(restrictions); + }); + + viaControlEnter + .append('span') + .attr('class', 'restriction-via-way-text'); + + // update + selection.selectAll('.restriction-via-way-input') + .property('value', _maxViaWay); + + var t = ['Node only', 'Up to 1 way', 'Up to 2 ways']; + selection.selectAll('.restriction-via-way-text') + .text(t[_maxViaWay]); } @@ -234,7 +310,7 @@ export function uiFieldRestrictions(field, context) { .call(utilSetDimensions, d) .call(drawVertices, vgraph, _intersection.vertices, filter, extent, z) .call(drawLines, vgraph, _intersection.ways, filter) - .call(drawTurns, vgraph, _intersection.turns(_fromWayID, _detail)); + .call(drawTurns, vgraph, _intersection.turns(_fromWayID, _maxViaWay)); surface .on('click.restrictions', click) @@ -455,11 +531,11 @@ export function uiFieldRestrictions(field, context) { restrictions.entity = function(_) { - if (!_vertexID || _vertexID !== _.id) { + // if (!_vertexID || _vertexID !== _.id) { _intersection = null; _fromWayID = null; _vertexID = _.id; - } + // } };