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
This commit is contained in:
Bryan Housel
2017-12-12 17:39:36 -05:00
parent b394cb6dfa
commit 899abc7ef5
6 changed files with 173 additions and 148 deletions

View File

@@ -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 */

View File

@@ -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 {

View File

@@ -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;
};

View File

@@ -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,

View File

@@ -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());

View File

@@ -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;
}