From 899abc7ef524465bfd29553acc3cfc4b7a4ca94c Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Tue, 12 Dec 2017 17:39:36 -0500 Subject: [PATCH] WIP to render vertices while dragging (re: #3003 / #4602) For now, drawHover is commented out. Still not sure what I will do with it. This means that things flicker a bit when dragging, also connecting nodes (and closing lines) does not currently work. There was lot going on preventing the vertices from rendering while dragging. 1. `modeDragNode` needed a proper `selectedIDs()` function that works like other modes.. Many other places in iD (including the vertex renderer) call `context.selectedIDs()`.. This means that `modeDragNode` needs a new function `restoreSelectedIDs()` to do what `selectedIDs()` was previously doing (a place to store selectedIDs so that we can reselect those entities after the user is done dragging a node in select mode) 2. Just so many things in svg/vertices.js - siblingAndChildVertices was missing some things for points that we render as vertices (points in wireframe, points with directions) - the sibling vertices weren't being included in the `filter` function, so would disappear when doing differenced/extent redraws - probably some other things --- css/20_map.css | 6 +- css/70_fills.css | 4 +- modules/modes/drag_node.js | 88 ++++++++++--------- modules/modes/select.js | 2 +- modules/renderer/map.js | 49 +++++------ modules/svg/vertices.js | 172 ++++++++++++++++++++----------------- 6 files changed, 173 insertions(+), 148 deletions(-) diff --git a/css/20_map.css b/css/20_map.css index 6d3a39037..a29a1c85a 100644 --- a/css/20_map.css +++ b/css/20_map.css @@ -88,7 +88,7 @@ g.midpoint .shadow { fill-opacity: 0; } -g.vertex.vertex-hover { +/*g.vertex.vertex-hover { display: none; } @@ -109,7 +109,7 @@ g.vertex.vertex-hover { .mode-drag-node .hover-disabled g.vertex.vertex-hover { display: none; } - +*/ g.vertex.related:not(.selected) .shadow, g.vertex.hover:not(.selected) .shadow, g.midpoint.related:not(.selected) .shadow, @@ -126,7 +126,7 @@ g.vertex.selected .shadow { .mode-add-area g.midpoint, .mode-add-line g.midpoint, .mode-add-point g.midpoint { - display: none; + display: none; } /* lines */ diff --git a/css/70_fills.css b/css/70_fills.css index 9402eec5d..c0cb1b167 100644 --- a/css/70_fills.css +++ b/css/70_fills.css @@ -38,12 +38,12 @@ /* Modes */ -.mode-draw-line .vertex.active, +/*.mode-draw-line .vertex.active, .mode-draw-area .vertex.active, .mode-drag-node .vertex.active { display: none; } - +*/ .mode-draw-line .way.active, .mode-draw-area .way.active, .mode-drag-node .active { diff --git a/modules/modes/drag_node.js b/modules/modes/drag_node.js index baed024ae..50cd8231b 100644 --- a/modules/modes/drag_node.js +++ b/modules/modes/drag_node.js @@ -1,5 +1,3 @@ -import _map from 'lodash-es/map'; - import { event as d3_event, select as d3_select @@ -36,15 +34,16 @@ export function modeDragNode(context) { id: 'drag-node', button: 'browse' }; + var hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover); + var edit = behaviorEdit(context); - var nudgeInterval, - activeIDs, - wasMidpoint, - isCancelled, - lastLoc, - selectedIDs = [], - hover = behaviorHover(context).altDisables(true).on('hover', context.ui().sidebar.hover), - edit = behaviorEdit(context); + var _nudgeInterval; + var _restoreSelectedIDs = []; + var _activeIDs = []; + var _wasMidpoint = false; + var _isCancelled = false; + var _dragEntity; + var _lastLoc; function vecSub(a, b) { @@ -52,9 +51,9 @@ export function modeDragNode(context) { } function edge(point, size) { - var pad = [80, 20, 50, 20], // top, right, bottom, left - x = 0, - y = 0; + var pad = [80, 20, 50, 20]; // top, right, bottom, left + var x = 0; + var y = 0; if (point[0] > size[0] - pad[1]) x = -10; @@ -74,8 +73,8 @@ export function modeDragNode(context) { function startNudge(entity, nudge) { - if (nudgeInterval) window.clearInterval(nudgeInterval); - nudgeInterval = window.setInterval(function() { + if (_nudgeInterval) window.clearInterval(_nudgeInterval); + _nudgeInterval = window.setInterval(function() { context.pan(nudge); doMove(entity, nudge); }, 50); @@ -83,9 +82,9 @@ export function modeDragNode(context) { function stopNudge() { - if (nudgeInterval) { - window.clearInterval(nudgeInterval); - nudgeInterval = null; + if (_nudgeInterval) { + window.clearInterval(_nudgeInterval); + _nudgeInterval = null; } } @@ -106,19 +105,19 @@ export function modeDragNode(context) { function start(entity) { - wasMidpoint = entity.type === 'midpoint'; + _wasMidpoint = entity.type === 'midpoint'; var hasHidden = context.features().hasHiddenConnections(entity, context.graph()); - isCancelled = d3_event.sourceEvent.shiftKey || hasHidden; + _isCancelled = d3_event.sourceEvent.shiftKey || hasHidden; - if (isCancelled) { + if (_isCancelled) { if (hasHidden) { uiFlash().text(t('modes.drag_node.connected_to_hidden'))(); } return behavior.cancel(); } - if (wasMidpoint) { + if (_wasMidpoint) { var midpoint = entity; entity = osmNode(); context.perform(actionAddMidpoint(midpoint, entity)); @@ -130,10 +129,13 @@ export function modeDragNode(context) { context.perform(actionNoop()); } + _dragEntity = entity; + // activeIDs generate no pointer events. This prevents the node or vertex // being dragged from trying to connect to itself or its parent element. - activeIDs = _map(context.graph().parentWays(entity), 'id'); - activeIDs.push(entity.id); + _activeIDs = context.graph().parentWays(entity) + .map(function(parent) { return parent.id; }); + _activeIDs.push(entity.id); setActiveElements(); context.enter(mode); @@ -153,12 +155,12 @@ export function modeDragNode(context) { function doMove(entity, nudge) { nudge = nudge || [0, 0]; - var currPoint = (d3_event && d3_event.point) || context.projection(lastLoc), - currMouse = vecSub(currPoint, nudge), - loc = context.projection.invert(currMouse), - d = datum(); + var currPoint = (d3_event && d3_event.point) || context.projection(_lastLoc); + var currMouse = vecSub(currPoint, nudge); + var loc = context.projection.invert(currMouse); + var d = datum(); - if (!nudgeInterval) { + if (!_nudgeInterval) { if (d.type === 'node' && d.id !== entity.id) { loc = d.loc; } else if (d.type === 'way' && !d3_select(d3_event.sourceEvent.target).classed('fill')) { @@ -171,14 +173,15 @@ export function modeDragNode(context) { moveAnnotation(entity) ); - lastLoc = loc; + _lastLoc = loc; } function move(entity) { - if (isCancelled) return; + if (_isCancelled) return; + d3_event.sourceEvent.stopPropagation(); - lastLoc = context.projection.invert(d3_event.point); + _lastLoc = context.projection.invert(d3_event.point); doMove(entity); var nudge = edge(d3_event.point, context.map().dimensions()); @@ -191,7 +194,7 @@ export function modeDragNode(context) { function end(entity) { - if (isCancelled) return; + if (_isCancelled) return; var d = datum(); @@ -208,7 +211,7 @@ export function modeDragNode(context) { connectAnnotation(d) ); - } else if (wasMidpoint) { + } else if (_wasMidpoint) { context.replace( actionNoop(), t('operations.add.annotation.vertex') @@ -221,7 +224,7 @@ export function modeDragNode(context) { ); } - var reselection = selectedIDs.filter(function(id) { + var reselection = _restoreSelectedIDs.filter(function(id) { return context.graph().hasEntity(id); }); @@ -240,7 +243,7 @@ export function modeDragNode(context) { function setActiveElements() { - context.surface().selectAll(utilEntitySelector(activeIDs)) + context.surface().selectAll(utilEntitySelector(_activeIDs)) .classed('active', true); } @@ -287,9 +290,16 @@ export function modeDragNode(context) { }; - mode.selectedIDs = function(_) { - if (!arguments.length) return selectedIDs; - selectedIDs = _; + mode.selectedIDs = function() { + if (!arguments.length) return _dragEntity ? [_dragEntity.id] : []; + // no assign + return mode; + }; + + + mode.restoreSelectedIDs = function(_) { + if (!arguments.length) return _restoreSelectedIDs; + _restoreSelectedIDs = _; return mode; }; diff --git a/modules/modes/select.js b/modules/modes/select.js index 281e77709..fa5a3ddd9 100644 --- a/modules/modes/select.js +++ b/modules/modes/select.js @@ -63,7 +63,7 @@ export function modeSelect(context, selectedIDs) { behaviorHover(context), behaviorSelect(context), behaviorLasso(context), - modeDragNode(context).selectedIDs(selectedIDs).behavior + modeDragNode(context).restoreSelectedIDs(selectedIDs).behavior ], inspector, editMenu, diff --git a/modules/renderer/map.js b/modules/renderer/map.js index 1538f5a22..0240844df 100644 --- a/modules/renderer/map.js +++ b/modules/renderer/map.js @@ -178,38 +178,38 @@ export function rendererMap(context) { }) .on('mousemove.map', function() { mousemove = d3_event; - }) - .on('mouseover.vertices', function() { - if (map.editable() && !transformed) { - var hover = d3_event.target.__data__; - surface.selectAll('.data-layer-osm') - .call(drawVertices.drawHover, context.graph(), hover, map.extent()); - dispatch.call('drawn', this, {full: false}); - } - }) - .on('mouseout.vertices', function() { - if (map.editable() && !transformed) { - var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__; - surface.selectAll('.data-layer-osm') - .call(drawVertices.drawHover, context.graph(), hover, map.extent()); - dispatch.call('drawn', this, {full: false}); - } }); + // .on('mouseover.vertices', function() { + // if (map.editable() && !transformed) { + // var hover = d3_event.target.__data__; + // surface.selectAll('.data-layer-osm') + // .call(drawVertices.drawHover, context.graph(), hover, map.extent()); + // dispatch.call('drawn', this, { full: false }); + // } + // }) + // .on('mouseout.vertices', function() { + // if (map.editable() && !transformed) { + // var hover = d3_event.relatedTarget && d3_event.relatedTarget.__data__; + // surface.selectAll('.data-layer-osm') + // .call(drawVertices.drawHover, context.graph(), hover, map.extent()); + // dispatch.call('drawn', this, { full: false }); + // } + // }); supersurface .call(context.background()); context.on('enter.map', function() { if (map.editable() && !transformed) { - var all = context.intersects(map.extent()), - filter = utilFunctor(true), - graph = context.graph(); + var all = context.intersects(map.extent()); + var filter = utilFunctor(true); + var graph = context.graph(); all = context.features().filter(all, graph); surface.selectAll('.data-layer-osm') .call(drawVertices, graph, all, filter, map.extent()) .call(drawMidpoints, graph, all, filter, map.trimmedExtent()); - dispatch.call('drawn', this, {full: false}); + dispatch.call('drawn', this, { full: false }); } }); @@ -265,10 +265,11 @@ export function rendererMap(context) { function drawVector(difference, extent) { - var graph = context.graph(), - features = context.features(), - all = context.intersects(map.extent()), - data, filter; + var graph = context.graph(); + var features = context.features(); + var all = context.intersects(map.extent()); + var data; + var filter; if (difference) { var complete = difference.complete(map.extent()); diff --git a/modules/svg/vertices.js b/modules/svg/vertices.js index a26f9c08f..ad0c41786 100644 --- a/modules/svg/vertices.js +++ b/modules/svg/vertices.js @@ -1,3 +1,4 @@ +import _clone from 'lodash-es/clone'; import _values from 'lodash-es/values'; import { select as d3_select } from 'd3-selection'; @@ -13,55 +14,16 @@ function ktoz(k) { return Math.log(k * TAU) / Math.LN2 - 8; } export function svgVertices(projection, context) { var radiuses = { - // z16-, z17, z18+, tagged - shadow: [6, 7.5, 7.5, 11.5], - stroke: [2.5, 3.5, 3.5, 7], - fill: [1, 1.5, 1.5, 1.5] + // z16-, z17, z18+, tagged + shadow: [6, 7.5, 7.5, 11.5], + stroke: [2.5, 3.5, 3.5, 7], + fill: [1, 1.5, 1.5, 1.5] }; var _hover; - function siblingAndChildVertices(ids, graph, extent) { - var vertices = {}; - - function addChildVertices(entity) { - if (!context.features().isHiddenFeature(entity, graph, entity.geometry(graph))) { - var i; - if (entity.type === 'way') { - for (i = 0; i < entity.nodes.length; i++) { - addChildVertices(graph.entity(entity.nodes[i])); - } - } else if (entity.type === 'relation') { - for (i = 0; i < entity.members.length; i++) { - var member = context.hasEntity(entity.members[i].id); - if (member) { - addChildVertices(member); - } - } - } else if (entity.intersects(extent, graph)) { - vertices[entity.id] = entity; - } - } - } - - ids.forEach(function(id) { - var entity = context.hasEntity(id); - if (entity && entity.type === 'node') { - vertices[entity.id] = entity; - context.graph().parentWays(entity).forEach(function(entity) { - addChildVertices(entity); - }); - } else if (entity) { - addChildVertices(entity); - } - }); - - return vertices; - } - - - function draw(selection, vertices, klass, graph, siblings) { + function draw(selection, vertices, klass, graph, siblings, filter) { siblings = siblings || {}; var icons = {}; var directions = {}; @@ -127,7 +89,8 @@ export function svgVertices(projection, context) { } - var groups = selection + var groups = selection.selectAll('.vertex.' + klass) + .filter(filter) .data(vertices, osmEntity.key); // exit @@ -178,7 +141,7 @@ export function svgVertices(projection, context) { // Directional vertices get viewfields var dgroups = groups.filter(function(d) { return getDirections(d); }) .selectAll('.viewfieldgroup') - .data(function(d) { return klass === 'vertex-hover' ? [] : [d]; }, osmEntity.key); + .data(function(d) { return /*klass === 'vertex-hover' ? [] : */[d]; }, osmEntity.key); // exit dgroups.exit() @@ -209,53 +172,104 @@ export function svgVertices(projection, context) { function drawVertices(selection, graph, entities, filter, extent) { - var siblings = siblingAndChildVertices(context.selectedIDs(), graph, extent); var wireframe = context.surface().classed('fill-wireframe'); - var vertices = []; + var siblings = {}; + getSiblingAndChildVertices(context.selectedIDs(), graph, extent); + + // always render selected and sibling vertices.. + var vertices = _clone(siblings); + var filterWithSiblings = function(d) { return d.id in siblings || filter(d); }; + + // also render important vertices from the `entities` list.. for (var i = 0; i < entities.length; i++) { var entity = entities[i]; var geometry = entity.geometry(graph); - if ((geometry === 'point') && (wireframe || entity.directions(graph, projection).length)) { - vertices.push(entity); - continue; - } + if ((geometry === 'point') && renderAsVertex(entity)) { + vertices[entity.id] = entity; - if (geometry !== 'vertex') - continue; - - if (entity.id in siblings || - entity.hasInterestingTags() || - entity.isEndpoint(graph) || - entity.isConnected(graph)) { - vertices.push(entity); + } else if ((geometry === 'vertex') && + (entity.hasInterestingTags() || entity.isEndpoint(graph) || entity.isConnected(graph)) ) { + vertices[entity.id] = entity; } } - var layer = selection.selectAll('.layer-hit'); - layer.selectAll('g.vertex.vertex-persistent') - .filter(filter) - .call(draw, vertices, 'vertex-persistent', graph, siblings); - drawHover(selection, graph, extent); + selection.selectAll('.layer-hit') + .call(draw, _values(vertices), 'vertex-persistent', graph, siblings, filterWithSiblings); + +// drawHover(selection, graph, extent, true); + + + function renderAsVertex(entity) { + var geometry = entity.geometry(graph); + return (geometry === 'vertex') || + (geometry === 'point' && (wireframe || entity.directions(graph, projection).length)); + } + + + function getSiblingAndChildVertices(ids, graph, extent) { + + function addChildVertices(entity) { + var geometry = entity.geometry(graph); + if (!context.features().isHiddenFeature(entity, graph, geometry)) { + var i; + if (entity.type === 'way') { + for (i = 0; i < entity.nodes.length; i++) { + var child = context.hasEntity(entity.nodes[i]); + if (child) { + addChildVertices(child); + } + } + } else if (entity.type === 'relation') { + for (i = 0; i < entity.members.length; i++) { + var member = context.hasEntity(entity.members[i].id); + if (member) { + addChildVertices(member); + } + } + } else if (renderAsVertex(entity) && entity.intersects(extent, graph)) { + siblings[entity.id] = entity; + } + } + } + + ids.forEach(function(id) { + var entity = context.hasEntity(id); + if (!entity) return; + + if (entity.type === 'node') { + if (renderAsVertex(entity)) { + siblings[entity.id] = entity; + graph.parentWays(entity).forEach(function(entity) { + addChildVertices(entity); + }); + } + } else { // way, relation + addChildVertices(entity); + } + }); + + } } - function drawHover(selection, graph, extent) { - var hovered = _hover ? siblingAndChildVertices([_hover.id], graph, extent) : {}; - var layer = selection.selectAll('.layer-hit'); - - layer.selectAll('g.vertex.vertex-hover') - .call(draw, _values(hovered), 'vertex-hover', graph); - } - - - drawVertices.drawHover = function(selection, graph, target, extent) { - if (target === _hover) return; - _hover = target; - drawHover(selection, graph, extent); - }; +// function drawHover(selection, graph, extent, follow) { +// var hovered = _hover ? siblingAndChildVertices([_hover.id], graph, extent) : {}; +// var wireframe = context.surface().classed('fill-wireframe'); +// var layer = selection.selectAll('.layer-hit'); +// +// layer.selectAll('g.vertex.vertex-hover') +// .call(draw, _values(hovered), 'vertex-hover', graph, {}, false); +// } +// +// +// drawVertices.drawHover = function(selection, graph, target, extent) { +// if (target === _hover) return; +// _hover = target; +// drawHover(selection, graph, extent); +// }; return drawVertices; }