mirror of
https://github.com/FoggedLens/iD.git
synced 2026-03-30 08:50:32 +02:00
Snap to ways/vertices/midpoints when drawing (#240)
Also add anti-snapping behavior when option key is down.
This commit is contained in:
26
css/map.css
26
css/map.css
@@ -16,7 +16,7 @@ g.point .shadow {
|
||||
transition: transform 100ms linear;
|
||||
-moz-transition: fill 100ms linear;
|
||||
}
|
||||
g.point.hover .shadow {
|
||||
.behavior-hover g.point.hover .shadow {
|
||||
fill: #E96666;
|
||||
fill-opacity: 0.3;
|
||||
}
|
||||
@@ -106,7 +106,7 @@ g.vertex .shadow {
|
||||
transition: transform 100ms linear;
|
||||
-moz-transition: fill 100ms linear;
|
||||
}
|
||||
g.vertex.hover .shadow {
|
||||
.behavior-hover g.vertex.hover .shadow {
|
||||
fill: #E96666;
|
||||
fill-opacity: 0.3;
|
||||
}
|
||||
@@ -120,7 +120,7 @@ g.vertex.selected .shadow {
|
||||
g.midpoint .fill {
|
||||
fill:#aaa;
|
||||
}
|
||||
g.midpoint .fill.hover {
|
||||
.behavior-hover g.midpoint .fill.hover {
|
||||
fill:#fff;
|
||||
stroke:#000;
|
||||
}
|
||||
@@ -133,7 +133,7 @@ g.midpoint .shadow {
|
||||
transition: transform 100ms linear;
|
||||
-moz-transition: fill 100ms linear;
|
||||
}
|
||||
g.midpoint .shadow.hover {
|
||||
.behavior-hover g.midpoint .shadow.hover {
|
||||
fill:#E96666;
|
||||
fill-opacity: 0.3;
|
||||
}
|
||||
@@ -161,7 +161,7 @@ path.shadow {
|
||||
-webkit-transition: stroke 100ms linear;
|
||||
}
|
||||
|
||||
path.shadow.hover {
|
||||
.behavior-hover path.shadow.hover {
|
||||
stroke: #E96666;
|
||||
stroke-opacity: 0.3;
|
||||
}
|
||||
@@ -691,17 +691,17 @@ text.point.tag-amenity {
|
||||
cursor:url(../img/cursor-draw.png) 9 9, auto;
|
||||
}
|
||||
|
||||
.mode-draw-line .way,
|
||||
.mode-draw-area .way,
|
||||
.mode-add-line .way,
|
||||
.mode-add-area .way {
|
||||
.mode-draw-line .behavior-hover .way,
|
||||
.mode-draw-area .behavior-hover .way,
|
||||
.mode-add-line .behavior-hover .way,
|
||||
.mode-add-area .behavior-hover .way {
|
||||
cursor:url(../img/cursor-draw-connect-line.png) 9 9, auto;
|
||||
}
|
||||
|
||||
.mode-draw-line .vertex,
|
||||
.mode-draw-area .vertex,
|
||||
.mode-add-line .vertex,
|
||||
.mode-add-area .vertex {
|
||||
.mode-draw-line .behavior-hover .vertex,
|
||||
.mode-draw-area .behavior-hover .vertex,
|
||||
.mode-add-line .behavior-hover .vertex,
|
||||
.mode-add-area .behavior-hover .vertex {
|
||||
cursor:url(../img/cursor-draw-connect-vertex.png) 9 9, auto;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,9 @@ iD.behavior.AddWay = function(mode) {
|
||||
history = mode.history,
|
||||
controller = mode.controller,
|
||||
event = d3.dispatch('startFromNode', 'startFromWay', 'start'),
|
||||
hover, draw;
|
||||
|
||||
function add() {
|
||||
var datum = d3.select(d3.event.target).datum() || {};
|
||||
draw;
|
||||
|
||||
function add(datum) {
|
||||
if (datum.type === 'node') {
|
||||
event.startFromNode(datum);
|
||||
} else if (datum.type === 'way') {
|
||||
@@ -26,8 +24,7 @@ iD.behavior.AddWay = function(mode) {
|
||||
.minzoom(16)
|
||||
.dblclickEnable(false);
|
||||
|
||||
surface.call(hover)
|
||||
.call(draw);
|
||||
surface.call(draw);
|
||||
};
|
||||
|
||||
addWay.off = function(surface) {
|
||||
@@ -39,16 +36,13 @@ iD.behavior.AddWay = function(mode) {
|
||||
map.dblclickEnable(true);
|
||||
}, 1000);
|
||||
|
||||
surface.call(hover.off)
|
||||
.call(draw.off);
|
||||
surface.call(draw.off);
|
||||
};
|
||||
|
||||
addWay.cancel = function() {
|
||||
controller.exit();
|
||||
};
|
||||
|
||||
hover = iD.behavior.Hover();
|
||||
|
||||
draw = iD.behavior.Draw()
|
||||
.on('add', add)
|
||||
.on('cancel', addWay.cancel)
|
||||
|
||||
@@ -1,45 +1,64 @@
|
||||
iD.behavior.Draw = function () {
|
||||
var event = d3.dispatch('move', 'add', 'undo', 'cancel', 'finish'),
|
||||
keybinding = d3.keybinding('draw'),
|
||||
down;
|
||||
down, surface, hover;
|
||||
|
||||
function datum() {
|
||||
if (d3.event.altKey) {
|
||||
return {};
|
||||
} else {
|
||||
return d3.event.target.__data__ || {};
|
||||
}
|
||||
}
|
||||
|
||||
function mousedown() {
|
||||
down = true;
|
||||
}
|
||||
|
||||
function mouseup() {
|
||||
down = false;
|
||||
}
|
||||
|
||||
function mousemove() {
|
||||
if (!down) {
|
||||
event.move(datum());
|
||||
}
|
||||
}
|
||||
|
||||
function click() {
|
||||
event.add(datum());
|
||||
}
|
||||
|
||||
function keydown() {
|
||||
if (d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
|
||||
surface.call(hover.off);
|
||||
}
|
||||
}
|
||||
|
||||
function keyup() {
|
||||
if (d3.event.keyCode === d3.keybinding.modifierCodes.alt) {
|
||||
surface.call(hover);
|
||||
}
|
||||
}
|
||||
|
||||
function backspace() {
|
||||
d3.event.preventDefault();
|
||||
event.undo();
|
||||
}
|
||||
|
||||
function del() {
|
||||
d3.event.preventDefault();
|
||||
event.cancel();
|
||||
}
|
||||
|
||||
function ret() {
|
||||
d3.event.preventDefault();
|
||||
event.finish();
|
||||
}
|
||||
|
||||
function draw(selection) {
|
||||
function mousemove() {
|
||||
if (!down) event.move();
|
||||
}
|
||||
|
||||
function click() {
|
||||
event.add();
|
||||
}
|
||||
|
||||
function mousedown() {
|
||||
down = true;
|
||||
}
|
||||
|
||||
function mouseup() {
|
||||
down = false;
|
||||
}
|
||||
|
||||
function backspace() {
|
||||
d3.event.preventDefault();
|
||||
event.undo();
|
||||
}
|
||||
|
||||
function del() {
|
||||
d3.event.preventDefault();
|
||||
event.cancel();
|
||||
}
|
||||
|
||||
function ret() {
|
||||
d3.event.preventDefault();
|
||||
event.finish();
|
||||
}
|
||||
|
||||
selection
|
||||
.on('mousedown.draw', mousedown)
|
||||
.on('mouseup.draw', mouseup)
|
||||
.on('mousemove.draw', mousemove)
|
||||
.on('click.draw', click);
|
||||
surface = selection;
|
||||
hover = iD.behavior.Hover();
|
||||
|
||||
keybinding
|
||||
.on('⌫', backspace)
|
||||
@@ -47,18 +66,33 @@ iD.behavior.Draw = function () {
|
||||
.on('⎋', ret)
|
||||
.on('↩', ret);
|
||||
|
||||
selection
|
||||
.on('mousedown.draw', mousedown)
|
||||
.on('mouseup.draw', mouseup)
|
||||
.on('mousemove.draw', mousemove)
|
||||
.on('click.draw', click)
|
||||
.call(hover);
|
||||
|
||||
d3.select(document)
|
||||
.call(keybinding);
|
||||
.call(keybinding)
|
||||
.on('keydown.draw', keydown)
|
||||
.on('keyup.draw', keyup);
|
||||
|
||||
return draw;
|
||||
}
|
||||
|
||||
draw.off = function(selection) {
|
||||
selection
|
||||
.on('mousedown.draw', null)
|
||||
.on('mouseup.draw', null)
|
||||
.on('mousemove.draw', null)
|
||||
.on('click.draw', null);
|
||||
.on('click.draw', null)
|
||||
.call(hover.off);
|
||||
|
||||
keybinding.off();
|
||||
d3.select(document)
|
||||
.call(keybinding.off)
|
||||
.on('keydown.draw', null)
|
||||
.on('keyup.draw', null);
|
||||
};
|
||||
|
||||
return d3.rebind(draw, event, 'on');
|
||||
|
||||
@@ -5,7 +5,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode, baseGraph) {
|
||||
event = d3.dispatch('add', 'addHead', 'addTail', 'addNode', 'addWay'),
|
||||
way = mode.history.graph().entity(wayId),
|
||||
finished = false,
|
||||
hover, draw;
|
||||
draw;
|
||||
|
||||
var node = iD.Node({loc: map.mouseCoordinates()}),
|
||||
nodeId = node.id;
|
||||
@@ -14,13 +14,19 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode, baseGraph) {
|
||||
iD.actions.AddNode(node),
|
||||
iD.actions.AddWayNode(wayId, node.id, index));
|
||||
|
||||
function move() {
|
||||
history.replace(iD.actions.MoveNode(nodeId, map.mouseCoordinates()));
|
||||
function move(datum) {
|
||||
var loc = map.mouseCoordinates();
|
||||
|
||||
if (datum.type === 'node' || datum.midpoint) {
|
||||
loc = datum.loc;
|
||||
} else if (datum.type === 'way') {
|
||||
loc = iD.geo.chooseIndex(datum, d3.mouse(map.surface.node()), map).loc;
|
||||
}
|
||||
|
||||
history.replace(iD.actions.MoveNode(nodeId, loc));
|
||||
}
|
||||
|
||||
function add() {
|
||||
var datum = d3.select(d3.event.target).datum() || {};
|
||||
|
||||
function add(datum) {
|
||||
if (datum.id === headId) {
|
||||
event.addHead(datum);
|
||||
} else if (datum.id === tailId) {
|
||||
@@ -47,8 +53,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode, baseGraph) {
|
||||
.minzoom(16)
|
||||
.dblclickEnable(false);
|
||||
|
||||
surface.call(hover)
|
||||
.call(draw)
|
||||
surface.call(draw)
|
||||
.selectAll('.way, .node')
|
||||
.filter(function (d) { return d.id === wayId || d.id === nodeId; })
|
||||
.classed('active', true);
|
||||
@@ -68,8 +73,7 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode, baseGraph) {
|
||||
map.dblclickEnable(true);
|
||||
}, 1000);
|
||||
|
||||
surface.call(hover.off)
|
||||
.call(draw.off)
|
||||
surface.call(draw.off)
|
||||
.selectAll('.way, .node')
|
||||
.classed('active', false);
|
||||
|
||||
@@ -145,8 +149,6 @@ iD.behavior.DrawWay = function(wayId, headId, tailId, index, mode, baseGraph) {
|
||||
controller.enter(iD.modes.Browse());
|
||||
};
|
||||
|
||||
hover = iD.behavior.Hover();
|
||||
|
||||
draw = iD.behavior.Draw()
|
||||
.on('move', move)
|
||||
.on('add', add)
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
*/
|
||||
iD.behavior.Hover = function () {
|
||||
var hover = function(selection) {
|
||||
selection.classed('behavior-hover', true);
|
||||
|
||||
selection.on('mouseover.hover', function () {
|
||||
var datum = d3.event.target.__data__;
|
||||
if (datum) {
|
||||
@@ -25,7 +27,8 @@ iD.behavior.Hover = function () {
|
||||
};
|
||||
|
||||
hover.off = function(selection) {
|
||||
selection.on('mouseover.hover', null)
|
||||
selection.classed('behavior-hover', false)
|
||||
.on('mouseover.hover', null)
|
||||
.on('mouseout.hover', null);
|
||||
};
|
||||
|
||||
|
||||
@@ -9,8 +9,23 @@ describe("iD.behavior.Hover", function() {
|
||||
container.remove();
|
||||
});
|
||||
|
||||
describe("#on", function () {
|
||||
it("adds the .behavior-hover class to the selection", function () {
|
||||
container.call(iD.behavior.Hover());
|
||||
expect(container).to.be.classed('behavior-hover')
|
||||
});
|
||||
});
|
||||
|
||||
describe("#off", function () {
|
||||
it("removes the .behavior-hover class from the selection", function () {
|
||||
container.classed('behavior-hover', true);
|
||||
container.call(iD.behavior.Hover().off);
|
||||
expect(container).not.to.be.classed('behavior-hover')
|
||||
});
|
||||
});
|
||||
|
||||
describe("mouseover", function () {
|
||||
it("adds the 'hover' class to all elements to which the same datum is bound", function () {
|
||||
it("adds the .hover class to all elements to which the same datum is bound", function () {
|
||||
container.selectAll('span')
|
||||
.data(['a', 'b', 'a', 'b'])
|
||||
.enter().append('span').attr('class', Object);
|
||||
@@ -24,7 +39,7 @@ describe("iD.behavior.Hover", function() {
|
||||
});
|
||||
|
||||
describe("mouseout", function () {
|
||||
it("removes the 'hover' class from all elements", function () {
|
||||
it("removes the .hover class from all elements", function () {
|
||||
container.append('span').attr('class', 'hover');
|
||||
|
||||
container.call(iD.behavior.Hover());
|
||||
|
||||
Reference in New Issue
Block a user