diff --git a/index.html b/index.html index 0979fa558..25554ea27 100644 --- a/index.html +++ b/index.html @@ -87,6 +87,7 @@ + diff --git a/js/id/behavior/add_way.js b/js/id/behavior/add_way.js new file mode 100644 index 000000000..7c02355fb --- /dev/null +++ b/js/id/behavior/add_way.js @@ -0,0 +1,58 @@ +iD.behavior.AddWay = function(mode) { + var map = mode.map, + history = mode.history, + controller = mode.controller, + event = d3.dispatch('startFromNode', 'startFromWay', 'start'), + hover, draw; + + function add() { + var datum = d3.select(d3.event.target).datum() || {}; + + if (datum.type === 'node') { + event.startFromNode(datum); + } else if (datum.type === 'way') { + var choice = iD.geo.chooseIndex(datum, d3.mouse(map.surface.node()), map); + event.startFromWay(datum, choice.loc, choice.index); + } else if (datum.midpoint) { + var way = history.graph().entity(datum.way); + event.startFromWay(way, datum.loc, datum.index); + } else { + event.start(map.mouseCoordinates()); + } + } + + var addWay = function(surface) { + map.fastEnable(false) + .minzoom(16) + .dblclickEnable(false); + + surface.call(hover) + .call(draw); + }; + + addWay.off = function(surface) { + map.fastEnable(true) + .minzoom(0) + .tail(false); + + window.setTimeout(function() { + map.dblclickEnable(true); + }, 1000); + + surface.call(hover.off) + .call(draw.off); + }; + + addWay.cancel = function() { + controller.exit(); + }; + + hover = iD.behavior.Hover(); + + draw = iD.behavior.Draw() + .on('add', add) + .on('cancel', addWay.cancel) + .on('finish', addWay.cancel); + + return d3.rebind(addWay, event, 'on'); +}; diff --git a/js/id/modes/add_area.js b/js/id/modes/add_area.js index 9c5404232..a83ed20a1 100644 --- a/js/id/modes/add_area.js +++ b/js/id/modes/add_area.js @@ -6,82 +6,75 @@ iD.modes.AddArea = function() { description: 'Add parks, buildings, lakes, or other areas to the map.' }; - var behavior; + var behavior, + defaultTags = {area: 'yes'}; mode.enter = function() { var map = mode.map, - surface = map.surface, history = mode.history, controller = mode.controller; - map.dblclickEnable(false) - .tail('Click on the map to start drawing an area, like a park, lake, or building.', true); + function startFromNode(a) { + var way = iD.Way({tags: defaultTags}), + b = iD.Node({loc: a.loc}); - function add() { - var datum = d3.select(d3.event.target).datum() || {}, - way = iD.Way({tags: { area: 'yes' }}), - node; - - if (datum.type === 'node') { - // start from an existing node - node = datum; - history.perform( - iD.actions.AddWay(way), - iD.actions.AddWayNode(way.id, node.id), - iD.actions.AddWayNode(way.id, node.id)); - - } else if (datum.type === 'way') { - // begin a new way starting from an existing way - var choice = iD.geo.chooseIndex(datum, d3.mouse(map.surface.node()), map); - node = iD.Node({ loc: choice.loc }); - - history.perform( - iD.actions.AddWay(way), - iD.actions.AddNode(node), - iD.actions.AddWayNode(datum.id, node.id, choice.index), - iD.actions.AddWayNode(way.id, node.id), - iD.actions.AddWayNode(way.id, node.id)); - - } else { - // start from a new node - node = iD.Node({loc: map.mouseCoordinates()}); - history.perform( - iD.actions.AddWay(way), - iD.actions.AddNode(node), - iD.actions.AddWayNode(way.id, node.id), - iD.actions.AddWayNode(way.id, node.id)); - } - - node = iD.Node({loc: node.loc}); - - history.replace( - iD.actions.AddNode(node), - iD.actions.AddWayNode(way.id, node.id, -1), + history.perform( + iD.actions.AddNode(b), + iD.actions.AddWay(way), + iD.actions.AddWayNode(way.id, a.id), + iD.actions.AddWayNode(way.id, b.id), + iD.actions.AddWayNode(way.id, a.id), 'started an area'); controller.enter(iD.modes.DrawArea(way.id)); } - function cancel() { - controller.exit(); + function startFromWay(other, loc, index) { + var a = iD.Node({loc: loc}), + b = iD.Node({loc: loc}), + way = iD.Way({tags: defaultTags}); + + history.perform( + iD.actions.AddNode(a), + iD.actions.AddNode(b), + iD.actions.AddWay(way), + iD.actions.AddWayNode(way.id, a.id), + iD.actions.AddWayNode(way.id, b.id), + iD.actions.AddWayNode(way.id, a.id), + iD.actions.AddWayNode(other.id, a.id, index), + 'started an area'); + + controller.enter(iD.modes.DrawArea(way.id)); } - behavior = iD.behavior.Draw() - .on('add', add) - .on('cancel', cancel) - .on('finish', cancel) - (surface); + function start(loc) { + var a = iD.Node({loc: loc}), + b = iD.Node({loc: loc}), + way = iD.Way({tags: defaultTags}); + + history.perform( + iD.actions.AddNode(a), + iD.actions.AddNode(b), + iD.actions.AddWay(way), + iD.actions.AddWayNode(way.id, a.id), + iD.actions.AddWayNode(way.id, b.id), + iD.actions.AddWayNode(way.id, a.id), + 'started an area'); + + controller.enter(iD.modes.DrawArea(way.id)); + } + + behavior = iD.behavior.AddWay(mode) + .on('startFromNode', startFromNode) + .on('startFromWay', startFromWay) + .on('start', start); + + mode.map.surface.call(behavior); + mode.map.tail('Click on the map to start drawing an area, like a park, lake, or building.', true); }; mode.exit = function() { - var map = mode.map, - surface = map.surface; - - window.setTimeout(function() { - map.dblclickEnable(true); - }, 1000); - map.tail(false); - behavior.off(surface); + mode.map.surface.call(behavior.off); }; return mode; diff --git a/js/id/modes/add_line.js b/js/id/modes/add_line.js index e5ff5ee55..729c382f4 100644 --- a/js/id/modes/add_line.js +++ b/js/id/modes/add_line.js @@ -6,91 +6,94 @@ iD.modes.AddLine = function() { description: 'Lines can be highways, streets, pedestrian paths, or even canals.' }; - var behavior; + var behavior, + defaultTags = {highway: 'residential'}; mode.enter = function() { var map = mode.map, - surface = map.surface, - graph = map.history().graph(), history = mode.history, controller = mode.controller; - map.dblclickEnable(false) - .tail('Click on the map to start drawing an road, path, or route.', true); - - function add() { - var datum = d3.select(d3.event.target).datum() || {}, - way = iD.Way({ tags: { highway: 'residential' } }), - direction = 'forward', - node; - - if (datum.type === 'node') { - // continue an existing way - node = datum; - var parents = history.graph(graph).parentWays(node); - var isLine = parents.length && parents[0].geometry(graph) === 'line'; - if (isLine && parents[0].first() === node.id) { - way = parents[0]; - direction = 'backward'; - } else if (isLine && parents[0].last() === node.id) { - way = parents[0]; - } else { - history.perform( - iD.actions.AddWay(way), - iD.actions.AddWayNode(way.id, node.id)); - } - - } else if (datum.type === 'way') { - // begin a new way starting from an existing way - var choice = iD.geo.chooseIndex(datum, d3.mouse(map.surface.node()), map); - node = iD.Node({ loc: choice.loc }); + function startFromNode(a) { + var b = iD.Node({loc: a.loc}), + graph = history.graph(), + parent = graph.parentWays(a)[0], + isLine = parent && parent.geometry(graph) === 'line'; + if (isLine && parent.first() === a.id) { history.perform( - iD.actions.AddWay(way), - iD.actions.AddNode(node), - iD.actions.AddWayNode(datum.id, node.id, choice.index), - iD.actions.AddWayNode(way.id, node.id)); + iD.actions.AddNode(b), + iD.actions.AddWayNode(parent.id, b.id, 0), + 'continued a line'); + + controller.enter(iD.modes.DrawLine(parent.id, 'backward')); + + } else if (isLine && parent.last() === a.id) { + history.perform( + iD.actions.AddNode(b), + iD.actions.AddWayNode(parent.id, b.id), + 'continued a line'); + + controller.enter(iD.modes.DrawLine(parent.id, 'forward')); } else { - // begin a new way - node = iD.Node({loc: map.mouseCoordinates()}); + var way = iD.Way({tags: defaultTags}); history.perform( + iD.actions.AddNode(b), iD.actions.AddWay(way), - iD.actions.AddNode(node), - iD.actions.AddWayNode(way.id, node.id)); + iD.actions.AddWayNode(way.id, a.id), + iD.actions.AddWayNode(way.id, b.id), + 'continued a line'); + + controller.enter(iD.modes.DrawLine(way.id, 'forward')); } + } - var index = (direction === 'forward') ? way.nodes.length : 0, + function startFromWay(other, loc, index) { + var a = iD.Node({loc: loc}), + b = iD.Node({loc: loc}), + way = iD.Way({tags: defaultTags}); - node = iD.Node({loc: node.loc}); - - history.replace( - iD.actions.AddNode(node), - iD.actions.AddWayNode(way.id, node.id, index), + history.perform( + iD.actions.AddNode(a), + iD.actions.AddNode(b), + iD.actions.AddWay(way), + iD.actions.AddWayNode(way.id, a.id), + iD.actions.AddWayNode(way.id, b.id), + iD.actions.AddWayNode(other.id, a.id, index), 'started a line'); - controller.enter(iD.modes.DrawLine(way.id, direction, node)); + controller.enter(iD.modes.DrawLine(way.id, 'forward')); } - function cancel() { - controller.exit(); + function start(loc) { + var a = iD.Node({loc: loc}), + b = iD.Node({loc: loc}), + way = iD.Way({tags: defaultTags}); + + history.perform( + iD.actions.AddNode(a), + iD.actions.AddNode(b), + iD.actions.AddWay(way), + iD.actions.AddWayNode(way.id, a.id), + iD.actions.AddWayNode(way.id, b.id), + 'started a line'); + + controller.enter(iD.modes.DrawLine(way.id, 'forward')); } - behavior = iD.behavior.Draw() - .on('add', add) - .on('cancel', cancel) - .on('finish', cancel) - (surface); + behavior = iD.behavior.AddWay(mode) + .on('startFromNode', startFromNode) + .on('startFromWay', startFromWay) + .on('start', start); + + mode.map.surface.call(behavior); + mode.map.tail('Click on the map to start drawing an road, path, or route.', true); }; mode.exit = function() { - var map = mode.map, - surface = map.surface; - - map.dblclickEnable(true); - map.tail(false); - behavior.off(surface); + mode.map.surface.call(behavior.off); }; return mode; diff --git a/test/index.html b/test/index.html index 10bba28ea..b3505f903 100644 --- a/test/index.html +++ b/test/index.html @@ -82,6 +82,7 @@ +