mirror of
https://github.com/FoggedLens/iD.git
synced 2026-05-20 07:25:15 +02:00
All touch targets are GeoJSON now
This makes the code a bit more consistent and lets us avoid some hacky and probably non-performant things: - abusing CSS classes in the draw/drag datum functions (classed `.target`) (is this thing target? just check d.properties) - regexing the id for `-nope$` (is this thing a nope target? just check d.properties) - using context.hasEntity to get a the real entity (is this thing a real osmEntity? just check d.properties) - fixes code like the restriction editor which uses fake ids for split ways
This commit is contained in:
@@ -240,6 +240,7 @@ g.turn circle {
|
||||
|
||||
.form-field-restrictions .vertex {
|
||||
cursor: auto !important;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.lasso #map {
|
||||
|
||||
@@ -36,7 +36,6 @@ export function behaviorDrag() {
|
||||
var dispatch = d3_dispatch('start', 'move', 'end');
|
||||
var _origin = null;
|
||||
var _selector = '';
|
||||
var _filter = null;
|
||||
var _event;
|
||||
var _target;
|
||||
var _surface;
|
||||
@@ -162,9 +161,10 @@ export function behaviorDrag() {
|
||||
var root = this;
|
||||
var target = d3_event.target;
|
||||
for (; target && target !== root; target = target.parentNode) {
|
||||
if (target[matchesSelector](_selector) &&
|
||||
(!_filter || _filter(target.__data__))) {
|
||||
return dragstart.call(target, target.__data__);
|
||||
var datum = target.__data__;
|
||||
var entity = datum && datum.properties && datum.properties.entity;
|
||||
if (entity && target[matchesSelector](_selector)) {
|
||||
return dragstart.call(target, entity);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -190,13 +190,6 @@ export function behaviorDrag() {
|
||||
};
|
||||
|
||||
|
||||
drag.filter = function(_) {
|
||||
if (!arguments.length) return _filter;
|
||||
_filter = _;
|
||||
return drag;
|
||||
};
|
||||
|
||||
|
||||
drag.origin = function (_) {
|
||||
if (!arguments.length) return _origin;
|
||||
_origin = _;
|
||||
|
||||
@@ -44,6 +44,8 @@ export function behaviorDraw(context) {
|
||||
var _lastMouse = null;
|
||||
|
||||
|
||||
// related code
|
||||
// - `mode/drag_node.js` `datum()`
|
||||
function datum() {
|
||||
if (d3_event.altKey) return {};
|
||||
|
||||
@@ -54,11 +56,10 @@ export function behaviorDraw(context) {
|
||||
element = d3_event.target;
|
||||
}
|
||||
|
||||
// When drawing, connect only to things classed as targets..
|
||||
// When drawing, snap only to touch targets..
|
||||
// (this excludes area fills and active drawing elements)
|
||||
var selection = d3_select(element);
|
||||
if (!selection.classed('target')) return {};
|
||||
return selection.datum();
|
||||
var d = element.__data__;
|
||||
return (d && d.properties && d.properties.target) ? d : {};
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -39,13 +39,14 @@ export function behaviorDrawWay(context, wayId, index, mode, startGraph) {
|
||||
// - `behavior/draw.js` `click()`
|
||||
// - `behavior/draw_way.js` `move()`
|
||||
function move(datum) {
|
||||
var nodeLoc = datum && datum.properties && datum.properties.entity && datum.properties.entity.loc;
|
||||
var nodeGroups = datum && datum.properties && datum.properties.nodes;
|
||||
var loc = context.map().mouseCoordinates();
|
||||
|
||||
if (datum.loc) { // snap to node/vertex - a real entity or a nope target with a `loc`
|
||||
loc = datum.loc;
|
||||
if (nodeLoc) { // snap to node/vertex - a point target with `.loc`
|
||||
loc = nodeLoc;
|
||||
|
||||
} else if (nodeGroups) { // snap to way - a line touch target or nope target with nodes
|
||||
} else if (nodeGroups) { // snap to way - a line target with `.nodes`
|
||||
var best = Infinity;
|
||||
for (var i = 0; i < nodeGroups.length; i++) {
|
||||
var childNodes = nodeGroups[i].map(function(id) { return context.entity(id); });
|
||||
@@ -169,9 +170,8 @@ export function behaviorDrawWay(context, wayId, index, mode, startGraph) {
|
||||
|
||||
|
||||
// Accept the current position of the drawing node and continue drawing.
|
||||
drawWay.add = function(loc, datum) {
|
||||
if ((datum && datum.id && /-nope$/.test(datum.id)) ||
|
||||
context.surface().classed('nope')) {
|
||||
drawWay.add = function(loc, d) {
|
||||
if ((d && d.properties && d.properties.nope) || context.surface().classed('nope')) {
|
||||
return; // can't click here
|
||||
}
|
||||
|
||||
|
||||
@@ -71,15 +71,15 @@ export function behaviorHover(context) {
|
||||
|
||||
function mouseover() {
|
||||
if (_buttonDown) return;
|
||||
var _target = d3_event.target;
|
||||
enter(_target ? _target.__data__ : null);
|
||||
var target = d3_event.target;
|
||||
enter(target ? target.__data__ : null);
|
||||
}
|
||||
|
||||
|
||||
function mouseout() {
|
||||
if (_buttonDown) return;
|
||||
var _target = d3_event.relatedTarget;
|
||||
enter(_target ? _target.__data__ : null);
|
||||
var target = d3_event.relatedTarget;
|
||||
enter(target ? target.__data__ : null);
|
||||
}
|
||||
|
||||
|
||||
@@ -97,16 +97,16 @@ export function behaviorHover(context) {
|
||||
}
|
||||
|
||||
|
||||
function enter(d) {
|
||||
if (d === _target) return;
|
||||
_target = d;
|
||||
function enter(datum) {
|
||||
if (datum === _target) return;
|
||||
_target = datum;
|
||||
|
||||
_selection.selectAll('.hover')
|
||||
.classed('hover', false);
|
||||
_selection.selectAll('.hover-suppressed')
|
||||
.classed('hover-suppressed', false);
|
||||
|
||||
var entity = _target && _target.id && context.hasEntity(_target.id);
|
||||
var entity = datum && datum.properties && datum.properties.entity;
|
||||
if (entity && entity.id !== _newId) {
|
||||
|
||||
// If drawing a way, don't hover on a node that was just placed. #3974
|
||||
|
||||
@@ -115,7 +115,7 @@ export function behaviorSelect(context) {
|
||||
var datum = d3_event.target.__data__ || (lastMouse && lastMouse.target.__data__);
|
||||
var mode = context.mode();
|
||||
|
||||
var entity = datum && datum.id && context.hasEntity(datum.id);
|
||||
var entity = datum && datum.properties && datum.properties.entity;
|
||||
if (entity) datum = entity;
|
||||
|
||||
if (datum && datum.type === 'midpoint') {
|
||||
|
||||
@@ -100,7 +100,7 @@ export function modeDragNode(context) {
|
||||
var midpoint = entity;
|
||||
entity = osmNode();
|
||||
context.perform(actionAddMidpoint(midpoint, entity));
|
||||
entity = context.entity(entity.id); // get post-action entity
|
||||
entity = context.entity(entity.id); // get post-action entity
|
||||
|
||||
var vertex = context.surface().selectAll('.' + entity.id);
|
||||
drag.target(vertex.node(), entity);
|
||||
@@ -119,12 +119,17 @@ export function modeDragNode(context) {
|
||||
}
|
||||
|
||||
|
||||
// related code
|
||||
// - `behavior/draw.js` `datum()`
|
||||
function datum() {
|
||||
var event = d3_event && d3_event.sourceEvent;
|
||||
if (!event || event.altKey || !d3_select(event.target).classed('target')) {
|
||||
if (!event || event.altKey) {
|
||||
return {};
|
||||
} else {
|
||||
return event.target.__data__ || {};
|
||||
// When dragging, snap only to touch targets..
|
||||
// (this excludes area fills and active drawing elements)
|
||||
var d = event.target.__data__;
|
||||
return (d && d.properties && d.properties.target) ? d : {};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,12 +147,13 @@ export function modeDragNode(context) {
|
||||
// - `behavior/draw.js` `click()`
|
||||
// - `behavior/draw_way.js` `move()`
|
||||
var d = datum();
|
||||
var nodeLoc = d && d.properties && d.properties.entity && d.properties.entity.loc;
|
||||
var nodeGroups = d && d.properties && d.properties.nodes;
|
||||
|
||||
if (d.loc) { // snap to node/vertex - a real entity or a nope target with a `loc`
|
||||
loc = d.loc;
|
||||
if (nodeLoc) { // snap to node/vertex - a point target with `.loc`
|
||||
loc = nodeLoc;
|
||||
|
||||
} else if (nodeGroups) { // snap to way - a line touch target or nope target with nodes
|
||||
} else if (nodeGroups) { // snap to way - a line target with `.nodes`
|
||||
var best = Infinity;
|
||||
for (var i = 0; i < nodeGroups.length; i++) {
|
||||
var childNodes = nodeGroups[i].map(function(id) { return context.entity(id); });
|
||||
@@ -250,8 +256,8 @@ export function modeDragNode(context) {
|
||||
if (_isCancelled) return;
|
||||
|
||||
var d = datum();
|
||||
var nope = (d && d.id && /-nope$/.test(d.id)) || context.surface().classed('nope');
|
||||
var target = d && d.id && context.hasEntity(d.id); // entity to snap to
|
||||
var nope = (d && d.properties && d.properties.nope) || context.surface().classed('nope');
|
||||
var target = d && d.properties && d.properties.entity; // entity to snap to
|
||||
|
||||
if (nope) { // bounce back
|
||||
context.perform(
|
||||
|
||||
@@ -59,7 +59,7 @@ export function svgAreas(projection, context) {
|
||||
|
||||
// Targets allow hover and vertex snapping
|
||||
var targets = selection.selectAll('.area.target-allowed')
|
||||
.filter(filter)
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data.targets, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
@@ -76,7 +76,7 @@ export function svgAreas(projection, context) {
|
||||
|
||||
// NOPE
|
||||
var nopes = selection.selectAll('.area.target-nope')
|
||||
.filter(function(d) { return filter({ id: d.properties.originalID }); })
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data.nopes, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
|
||||
+28
-17
@@ -155,11 +155,17 @@ export function svgPath(projection, graph, isArea) {
|
||||
|
||||
|
||||
export function svgPointTransform(projection) {
|
||||
return function(entity) {
|
||||
var svgpoint = function(entity) {
|
||||
// http://jsperf.com/short-array-join
|
||||
var pt = projection(entity.loc);
|
||||
return 'translate(' + pt[0] + ',' + pt[1] + ')';
|
||||
};
|
||||
|
||||
svgpoint.geojson = function(d) {
|
||||
return svgpoint(d.properties.entity);
|
||||
};
|
||||
|
||||
return svgpoint;
|
||||
}
|
||||
|
||||
|
||||
@@ -184,7 +190,7 @@ export function svgSegmentWay(way, graph, activeID) {
|
||||
var coords = [];
|
||||
var nodes = [];
|
||||
var startType = null; // 0 = active, 1 = passive, 2 = adjacent
|
||||
var currType = null;
|
||||
var currType = null; // 0 = active, 1 = passive, 2 = adjacent
|
||||
var node;
|
||||
|
||||
for (var i = 0; i < way.nodes.length; i++) {
|
||||
@@ -244,29 +250,34 @@ export function svgSegmentWay(way, graph, activeID) {
|
||||
|
||||
if (coordGroups.passive.length) {
|
||||
features.passive.push({
|
||||
'type': 'Feature',
|
||||
'id': way.id,
|
||||
'properties': {
|
||||
'nodes': nodeGroups.passive
|
||||
type: 'Feature',
|
||||
id: way.id,
|
||||
properties: {
|
||||
target: true,
|
||||
entity: way,
|
||||
nodes: nodeGroups.passive
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'MultiLineString',
|
||||
'coordinates': coordGroups.passive
|
||||
geometry: {
|
||||
type: 'MultiLineString',
|
||||
coordinates: coordGroups.passive
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (coordGroups.active.length) {
|
||||
features.active.push({
|
||||
'type': 'Feature',
|
||||
'id': way.id + '-nope', // break the ids on purpose
|
||||
'properties': {
|
||||
'originalID': way.id,
|
||||
'nodes': nodeGroups.active
|
||||
type: 'Feature',
|
||||
id: way.id + '-nope', // break the ids on purpose
|
||||
properties: {
|
||||
target: true,
|
||||
entity: way,
|
||||
nodes: nodeGroups.active,
|
||||
nope: true,
|
||||
originalID: way.id
|
||||
},
|
||||
'geometry': {
|
||||
'type': 'MultiLineString',
|
||||
'coordinates': coordGroups.active
|
||||
geometry: {
|
||||
type: 'MultiLineString',
|
||||
coordinates: coordGroups.active
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ export function svgLines(projection, context) {
|
||||
|
||||
// Targets allow hover and vertex snapping
|
||||
var targets = selection.selectAll('.line.target-allowed')
|
||||
.filter(filter)
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data.targets, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
@@ -72,7 +72,7 @@ export function svgLines(projection, context) {
|
||||
|
||||
// NOPE
|
||||
var nopes = selection.selectAll('.line.target-nope')
|
||||
.filter(function(d) { return filter({ id: d.properties.originalID }); })
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data.nopes, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
|
||||
@@ -18,9 +18,26 @@ export function svgMidpoints(projection, context) {
|
||||
|
||||
function drawTargets(selection, graph, entities, filter) {
|
||||
var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
|
||||
var getTransform = svgPointTransform(projection).geojson;
|
||||
|
||||
var data = entities.map(function(midpoint) {
|
||||
return {
|
||||
type: 'Feature',
|
||||
id: midpoint.id,
|
||||
properties: {
|
||||
target: true,
|
||||
entity: midpoint
|
||||
},
|
||||
geometry: {
|
||||
type: 'Point',
|
||||
coordinates: midpoint.loc
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
var targets = selection.selectAll('.midpoint.target')
|
||||
.filter(filter)
|
||||
.data(entities, function key(d) { return d.id; });
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
targets.exit()
|
||||
@@ -32,7 +49,7 @@ export function svgMidpoints(projection, context) {
|
||||
.attr('r', targetRadius)
|
||||
.merge(targets)
|
||||
.attr('class', function(d) { return 'node midpoint target ' + fillClass + d.id; })
|
||||
.attr('transform', svgPointTransform(projection));
|
||||
.attr('transform', getTransform);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+19
-5
@@ -29,13 +29,27 @@ export function svgPoints(projection, context) {
|
||||
|
||||
function drawTargets(selection, graph, entities, filter) {
|
||||
var fillClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
|
||||
var passive = entities.filter(function(d) {
|
||||
return d.id !== context.activeID();
|
||||
var getTransform = svgPointTransform(projection).geojson;
|
||||
var activeID = context.activeID();
|
||||
var data = [];
|
||||
|
||||
entities.forEach(function(node) {
|
||||
if (activeID === node.id) return; // draw no target on the activeID
|
||||
|
||||
data.push({
|
||||
type: 'Feature',
|
||||
id: node.id,
|
||||
properties: {
|
||||
target: true,
|
||||
entity: node
|
||||
},
|
||||
geometry: node.asGeoJSON()
|
||||
});
|
||||
});
|
||||
|
||||
var targets = selection.selectAll('.point.target')
|
||||
.filter(filter)
|
||||
.data(passive, function key(d) { return d.id; });
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
targets.exit()
|
||||
@@ -50,7 +64,7 @@ export function svgPoints(projection, context) {
|
||||
.attr('height', 30)
|
||||
.merge(targets)
|
||||
.attr('class', function(d) { return 'node point target ' + fillClass + d.id; })
|
||||
.attr('transform', svgPointTransform(projection));
|
||||
.attr('transform', getTransform);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+26
-11
@@ -184,20 +184,35 @@ export function svgVertices(projection, context) {
|
||||
function drawTargets(selection, graph, entities, filter) {
|
||||
var targetClass = context.getDebug('target') ? 'pink ' : 'nocolor ';
|
||||
var nopeClass = context.getDebug('target') ? 'red ' : 'nocolor ';
|
||||
var getTransform = svgPointTransform(projection).geojson;
|
||||
var activeID = context.activeID();
|
||||
var data = { targets: [], nopes: [] };
|
||||
|
||||
entities.forEach(function(node) {
|
||||
if (activeID === node.id) return; // draw no target on the activeID
|
||||
|
||||
var currType = svgPassiveVertex(node, graph, activeID);
|
||||
if (currType !== 0) {
|
||||
data.targets.push(node); // passive or adjacent - allow to connect
|
||||
var vertexType = svgPassiveVertex(node, graph, activeID);
|
||||
if (vertexType !== 0) { // passive or adjacent - allow to connect
|
||||
data.targets.push({
|
||||
type: 'Feature',
|
||||
id: node.id,
|
||||
properties: {
|
||||
target: true,
|
||||
entity: node
|
||||
},
|
||||
geometry: node.asGeoJSON()
|
||||
});
|
||||
} else {
|
||||
data.nopes.push({
|
||||
id: node.id + '-nope', // not a real osmNode, break the id on purpose
|
||||
originalID: node.id,
|
||||
loc: node.loc
|
||||
type: 'Feature',
|
||||
id: node.id + '-nope', // break the ids on purpose
|
||||
properties: {
|
||||
target: true,
|
||||
entity: node,
|
||||
nope: true,
|
||||
originalID: node.id
|
||||
},
|
||||
geometry: node.asGeoJSON()
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -205,7 +220,7 @@ export function svgVertices(projection, context) {
|
||||
|
||||
// Targets allow hover and vertex snapping
|
||||
var targets = selection.selectAll('.vertex.target-allowed')
|
||||
.filter(filter)
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data.targets, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
@@ -218,12 +233,12 @@ export function svgVertices(projection, context) {
|
||||
.attr('r', function(d) { return (_radii[d.id] || radiuses.shadow[3]); })
|
||||
.merge(targets)
|
||||
.attr('class', function(d) { return 'node vertex target target-allowed ' + targetClass + d.id; })
|
||||
.attr('transform', svgPointTransform(projection));
|
||||
.attr('transform', getTransform);
|
||||
|
||||
|
||||
// NOPE
|
||||
var nopes = selection.selectAll('.vertex.target-nope')
|
||||
.filter(function(d) { return filter({ id: d.originalID }); })
|
||||
.filter(function(d) { return filter(d.properties.entity); })
|
||||
.data(data.nopes, function key(d) { return d.id; });
|
||||
|
||||
// exit
|
||||
@@ -233,10 +248,10 @@ export function svgVertices(projection, context) {
|
||||
// enter/update
|
||||
nopes.enter()
|
||||
.append('circle')
|
||||
.attr('r', function(d) { return (_radii[d.id.replace('-nope','')] || radiuses.shadow[3]); })
|
||||
.attr('r', function(d) { return (_radii[d.properties.originalID] || radiuses.shadow[3]); })
|
||||
.merge(nopes)
|
||||
.attr('class', function(d) { return 'node vertex target target-nope ' + nopeClass + d.id; })
|
||||
.attr('transform', svgPointTransform(projection));
|
||||
.attr('transform', getTransform);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -154,9 +154,13 @@ export function uiFieldRestrictions(field, context) {
|
||||
.call(breathe);
|
||||
|
||||
var datum = d3_event.target.__data__;
|
||||
var entity = datum && datum.properties && datum.properties.entity;
|
||||
if (entity) datum = entity;
|
||||
|
||||
if (datum instanceof osmEntity) {
|
||||
fromNodeID = intersection.adjacentNodeId(datum.id);
|
||||
render();
|
||||
|
||||
} else if (datum instanceof osmTurn) {
|
||||
if (datum.restriction) {
|
||||
context.perform(
|
||||
|
||||
Reference in New Issue
Block a user