From 6889bdea4d5c06157da9b4ec6da221d3425ca3cf Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Wed, 28 Nov 2012 17:10:39 -0500 Subject: [PATCH] Fix area drawing. --- js/id/actions/modes.js | 160 ++++++++++++++++++++++------------------- js/id/renderer/map.js | 8 ++- 2 files changed, 94 insertions(+), 74 deletions(-) diff --git a/js/id/actions/modes.js b/js/id/actions/modes.js index df618e7f1..5a62306df 100644 --- a/js/id/actions/modes.js +++ b/js/id/actions/modes.js @@ -15,13 +15,11 @@ iD.modes._node = function(ll) { iD.modes.AddPlace = { title: "+ Place", enter: function() { - var surface = this.map.surface; - var teaser = surface.selectAll('g#temp-g') + var surface = this.map.surface, + teaser = surface.selectAll('g#temp-g') .append('g').attr('id', 'addplace'); - teaser.append('circle') - .attr('class', 'handle') - .attr('r', 3); + teaser.append('circle').attr({ 'class': 'handle', r: 3 }); surface.on('mousemove.addplace', function() { teaser.attr('transform', function() { @@ -45,26 +43,25 @@ iD.modes.AddPlace = { }.bind(this)); }, exit: function() { - this.map.surface.on('mousemove.addplace', null); - this.map.surface.on('click.addplace', null); + this.map.surface + .on('mousemove.addplace', null) + .on('click.addplace', null); d3.select(document).on('keydown.addplace', null); d3.selectAll('#addplace').remove(); } }; +// user has clicked 'add road' or pressed a keybinding, and now has +// a teaser node and needs to click on the map to start a road iD.modes.AddRoad = { title: "+ Road", way: function() { - return iD.Way({ - tags: { - highway: 'residential' - } - }); + return iD.Way({ tags: { highway: 'residential' } }); }, enter: function() { this.map.dblclickEnable(false); - var surface = this.map.surface; - var teaser = surface.selectAll('g#temp-g') + var surface = this.map.surface, + teaser = surface.selectAll('g#temp-g') .append('g').attr('id', 'addroad'); teaser.append('circle') @@ -106,13 +103,15 @@ iD.modes.AddRoad = { }, exit: function() { this.map.dblclickEnable(true); - this.map.surface.on('click.addroad', null); - this.map.surface.on('mousemove.addroad', null); + this.map.surface.on('click.addroad', null) + .on('mousemove.addroad', null); d3.select(document).on('keydown.addroad', null); d3.selectAll('#addroad').remove(); } }; +// user has clicked on the map, started a road, and now needs to click more +// nodes to continue it. iD.modes.DrawRoad = function(way_id) { return { enter: function() { @@ -166,8 +165,8 @@ iD.modes.DrawRoad = function(way_id) { surface.on('click.drawroad', drawRoad.bind(this)); }, exit: function() { - this.map.surface.on('mousemove.drawroad', null); - this.map.surface.on('click.drawroad', null); + this.map.surface.on('mousemove.drawroad', null) + .on('click.drawroad', null); d3.select(document).on('.drawroad', null); d3.selectAll('#drawroad').remove(); window.setTimeout(function() { @@ -181,96 +180,113 @@ iD.modes.AddArea = { title: "+ Area", way: function() { return iD.Way({ - tags: { - building: 'yes' - } + tags: { building: 'yes', area: 'yes' } }); }, enter: function() { - var surface = this.map.surface; - var teaser = surface.selectAll('g#temp-g') - .append('g').attr('id', 'addroad'); + this.map.dblclickEnable(false); + + var surface = this.map.surface, + teaser = surface.selectAll('g#temp-g') + .append('g').attr('id', 'addarea'); teaser.append('circle') - .attr('class', 'handle') - .attr('r', 3); + .attr({ 'class': 'handle', r: 3 }) + .style('pointer-events', 'none'); - surface.on('mousemove.addroad', function() { + surface.on('mousemove.addarea', function() { teaser.attr('transform', function() { var off = d3.mouse(surface.node()); return 'translate(' + off + ')'; }); }); - surface.on('click.addroad', function() { - var ll = this.map.projection.invert( - d3.mouse(surface.node())); + function addArea() { + var t = d3.select(d3.event.target), + node, way = this.way(); - var way = this.way(); - var node = iD.modes._node(ll); + // connect a way to an existing way + if (t.data() && t.data()[0] && t.data()[0].type === 'node') { + node = t.data()[0]; + } else { + node = iD.modes._node(this.map.projection.invert( + d3.mouse(surface.node()))); + } + + this.map.perform(iD.actions.startWay(way)); way.nodes.push(node.id); - - this.map.perform(iD.actions.changeWayNodes(way, node)); + this.map.perform(iD.actions.addWayNode(way, node)); this.map.selectClick(way); - this.controller.enter(iD.modes.DrawArea(way)); - }.bind(this)); + this.controller.enter(iD.modes.DrawArea(way.id)); + } - d3.select(document).on('keydown.addroad', function() { + surface.on('click.addarea', addArea.bind(this)); + + d3.select(document).on('keydown.addarea', function() { if (d3.event.keyCode === 27) this.exit(); }.bind(this)); }, exit: function() { - this.map.surface.on('click.addarea', null); - this.map.surface.on('mousemove.addarea', null); + this.map.dblclickEnable(true); + this.map.surface.on('click.addarea', null) + .on('mousemove.addarea', null); d3.select(document).on('keydown.addarea', null); - d3.selectAll('#addroad').remove(); + d3.selectAll('#addarea').remove(); } }; -iD.modes.DrawArea = function(way) { +iD.modes.DrawArea = function(way_id) { return { enter: function() { - var surface = this.map.surface; + this.map.dblclickEnable(false); + var surface = this.map.surface, - var lastNode = this.map.history.graph().entity(way.nodes[way.nodes.length - 1]); - var firstNode = this.map.history.graph().entity(way.nodes[0]); + nextnode = iD.modes._node([NaN, NaN]); + var nextnode_id = nextnode.id; - this.nextnode = iD.modes._node([lastNode.lon, lastNode.lat]); - - way.nodes.push(this.nextnode.id); - way.nodes.push(firstNode.id); - this.map.perform(iD.actions.changeWayNodes(way, this.nextnode)); - this.map.perform(iD.actions.changeWayNodes(way, firstNode)); + var way = this.map.history.graph().entity(way_id); + var firstnode_id = _.first(way.nodes); + way.nodes.push(nextnode_id); + this.map.perform(iD.actions.addWayNode(way, nextnode)); surface.on('mousemove.drawarea', function() { var ll = this.map.projection.invert(d3.mouse(surface.node())); - this.map.history.replace(iD.actions.move(this.nextnode, ll)); - this.map.update(); + var way = this.map.history.graph().entity(way_id); + var node = iD.Entity(this.map.history.graph().entity(nextnode_id), { + lon: ll[0], + lat: ll[1] + }); + this.map.history.replace(iD.actions.addWayNode(way, node)); + var only = iD.Util.trueObj([way.id].concat(_.pluck(way.nodes, 'id'))); + this.map.redraw(only); }.bind(this)); - surface.on('click.drawarea', function() { + function drawArea() { + var t = d3.select(d3.event.target); d3.event.stopPropagation(); + if (t.data() && t.data()[0] && t.data()[0].type === 'node') { + if (t.data()[0].id == firstnode_id) { + var l = this.map.history.graph().entity(way.nodes.pop()); + this.map.perform(iD.actions.removeWayNode(way, l)); + way.nodes.push(way.nodes[0]); + this.map.perform(iD.actions.addWayNode(way, way.nodes[0])); + // End by clicking on own tail + return this.exit(); + } else { + // connect a way to an existing way + node = t.data()[0]; + } + } else { + node = iD.modes._node(this.map.projection.invert( + d3.mouse(surface.node()))); + } way.nodes.pop(); - way.nodes.pop(); - var ll = this.map.projection.invert(d3.mouse(surface.node())); - var node = iD.modes._node(ll); way.nodes.push(node.id); - this.map.perform(iD.actions.changeWayNodes(way, node)); - this.controller.enter(iD.modes.DrawRoad(way)); - }.bind(this)); - - surface.on('dblclick.drawarea', function() { - d3.event.stopPropagation(); - var a = this.map.history.graph().entity(way.nodes.pop()); - var b = this.map.history.graph().entity(way.nodes.pop()); - this.map.perform(iD.actions.changeWayNodes(way, a)); - this.map.perform(iD.actions.remove(a)); - this.map.perform(iD.actions.remove(b)); - way.nodes.push(way.nodes[0]); - var closeNode = this.map.history.graph().entity(way.nodes[0]); - this.map.perform(iD.actions.changeWayNodes(way, closeNode)); - this.exit(); - }.bind(this)); + this.map.perform(iD.actions.addWayNode(way, node)); + way.nodes = way.nodes.slice(); + this.controller.enter(iD.modes.DrawArea(way_id)); + } + surface.on('click.drawarea', drawArea.bind(this)); }, exit: function() { this.map.surface.on('mousemove.drawarea', null); diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index e4ee894cd..b45d63e2e 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -135,12 +135,16 @@ iD.Map = function(elem, connection) { var filter = only ? function(d) { return only[d.id]; } : function() { return true; }; + function isArea(way) { + return iD.Way.isClosed(a) || (a.tags.area && a.tags.area === 'yes'); + } + for (var i = 0; i < all.length; i++) { var a = all[i]; if (a.type === 'way') { a._line = nodeline(a); - if (!iD.Way.isClosed(a)) ways.push(a); - else areas.push(a); + if (isArea(a)) areas.push(a); + else ways.push(a); } else if (a._poi) { points.push(a); } else if (!a._poi && a.type === 'node' && nodeIntersect(a, extent)) {