diff --git a/index.html b/index.html
index 38a17504b..9cf8c269f 100644
--- a/index.html
+++ b/index.html
@@ -20,6 +20,7 @@
+
diff --git a/js/id/modes/browse.js b/js/id/modes/browse.js
index 0e6789f77..01eae38c9 100644
--- a/js/id/modes/browse.js
+++ b/js/id/modes/browse.js
@@ -6,7 +6,41 @@ iD.modes.Browse = function() {
description: 'Pan and zoom the map'
};
+ var dragging;
+
+ var dragbehavior = d3.behavior.drag()
+ .origin(function(entity) {
+ var p = mode.map.projection(entity.loc);
+ return { x: p[0], y: p[1] };
+ })
+ .on('drag', function(entity) {
+ d3.event.sourceEvent.stopPropagation();
+ if (!dragging) {
+ if (entity.accuracy) {
+ var way = history.graph().entity(entity.way),
+ index = entity.index;
+ entity = iD.Node(entity);
+ mode.history.perform(iD.actions.AddWayNode(way, entity, index));
+ }
+ dragging = iD.util.trueObj([entity.id].concat(
+ _.pluck(mode.history.graph().parentWays(entity.id), 'id')));
+ mode.history.perform(iD.actions.Noop());
+ }
+ var to = mode.map.projection.invert([d3.event.x, d3.event.y]);
+ mode.history.replace(iD.actions.Move(entity, to));
+ })
+ .on('dragend', function () {
+ if (!dragging) return;
+ dragging = undefined;
+ });
+
mode.enter = function() {
+ mode.map.surface
+ .call(dragbehavior)
+ .call(d3.latedrag()
+ .filter(function(d) {
+ return d.type === 'node';
+ }));
mode.map.surface.on('click.browse', function () {
var datum = d3.select(d3.event.target).datum();
if (datum instanceof iD.Entity) {
diff --git a/js/id/modes/select.js b/js/id/modes/select.js
index fe18dba6d..d4ad71c74 100644
--- a/js/id/modes/select.js
+++ b/js/id/modes/select.js
@@ -23,7 +23,9 @@ iD.modes.Select = function (entity) {
entity.nodes.forEach(function(node) {
var start = mode.map.projection(node.loc);
- var end = mode.map.projection.invert([start[0] + d3.event.dx, start[1] + d3.event.dy]);
+ var end = mode.map.projection.invert([
+ start[0] + d3.event.dx,
+ start[1] + d3.event.dy]);
node.loc = end;
mode.history.replace(iD.actions.Move(node, end));
});
diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js
index 4e678aefa..545c5db89 100644
--- a/js/id/renderer/map.js
+++ b/js/id/renderer/map.js
@@ -13,37 +13,8 @@ iD.Map = function() {
.on('zoom', zoomPan),
dblclickEnabled = true,
dragEnabled = true,
+ dragging = false,
fastEnabled = true,
- dragging,
- dragbehavior = d3.behavior.drag()
- .origin(function(entity) {
- if (!dragEnabled) return { x: 0, y: 0 };
- var p = projection(entity.loc);
- return { x: p[0], y: p[1] };
- })
- .on('drag', function(entity) {
- d3.event.sourceEvent.stopPropagation();
-
- if (!dragging) {
- if (entity.accuracy) {
- var way = history.graph().entity(entity.way),
- index = entity.index;
- entity = iD.Node(entity);
- history.perform(iD.actions.AddWayNode(way, entity, index));
- }
-
- dragging = iD.util.trueObj([entity.id].concat(
- _.pluck(history.graph().parentWays(entity.id), 'id')));
- history.perform(iD.actions.Noop());
- }
-
- var to = projection.invert([d3.event.x, d3.event.y]);
- history.replace(iD.actions.Move(entity, to));
- })
- .on('dragend', function () {
- if (!dragEnabled || !dragging) return;
- dragging = undefined;
- }),
background = iD.Background()
.projection(projection),
class_stroke = iD.Style.styleClasses('stroke'),
@@ -90,7 +61,7 @@ iD.Map = function() {
.attr('clip-path', 'url(#clip)');
g = ['fill', 'casing', 'stroke', 'text', 'hit', 'temp'].reduce(function(mem, i) {
- return (mem[i] = r.append('g').attr('class', 'layer-g')) && mem;
+ return (mem[i] = r.append('g').attr('class', 'layer-g layer-' + i)) && mem;
}, {});
var arrow = surface.append('text').text('►----');
@@ -175,10 +146,11 @@ iD.Map = function() {
}
handles.exit().remove();
handles.enter().append('image')
- .attr({ width: 6, height: 6, 'class': 'handle', 'xlink:href': 'css/handle.png' })
- .each(function(d) {
- if (d.tags && d.tags.elastic) return;
- d3.select(this).call(dragbehavior);
+ .attr({
+ width: 6,
+ height: 6,
+ 'class': 'handle',
+ 'xlink:href': 'css/handle.png'
});
handles.attr('transform', function(entity) {
var p = projection(entity.loc);
@@ -193,8 +165,7 @@ iD.Map = function() {
.data(waynodes, key);
handles.exit().remove();
handles.enter().append('circle')
- .attr({ r: 2, 'class': 'accuracy-handle' })
- .call(dragbehavior);
+ .attr({ r: 2, 'class': 'accuracy-handle' });
handles.attr('transform', function(entity) {
var p = projection(entity.loc);
return 'translate(' + [~~p[0], ~~p[1]] + ')';
@@ -236,8 +207,7 @@ iD.Map = function() {
.data(points, key);
markers.exit().remove();
var marker = markers.enter().append('g')
- .attr('class', 'marker')
- .call(dragbehavior);
+ .attr('class', 'marker');
marker.append('circle')
.attr({ r: 10, cx: 8, cy: 8 });
marker.append('image')
diff --git a/js/lib/d3.latedrag.js b/js/lib/d3.latedrag.js
new file mode 100644
index 000000000..06970bca1
--- /dev/null
+++ b/js/lib/d3.latedrag.js
@@ -0,0 +1,22 @@
+d3.latedrag = function() {
+ var filter = d3.functor(true);
+
+ function latedrag(selection) {
+ var mousedown = selection.on('mousedown.drag');
+ selection.on('mousedown.drag', null);
+ selection.on('mousedown.latedrag', function() {
+ var datum = d3.select(d3.event.target).datum();
+ if (datum && filter(datum)) {
+ mousedown.apply(d3.event.target, [datum]);
+ }
+ });
+ }
+
+ latedrag.filter = function(_) {
+ if (!arguments.length) return filter;
+ filter = _;
+ return latedrag;
+ };
+
+ return latedrag;
+};