diff --git a/index.html b/index.html
index fae1fc940..5f62b0f8f 100644
--- a/index.html
+++ b/index.html
@@ -73,6 +73,7 @@
+
diff --git a/js/id/actions/add_midpoint.js b/js/id/actions/add_midpoint.js
new file mode 100644
index 000000000..c0cb97f59
--- /dev/null
+++ b/js/id/actions/add_midpoint.js
@@ -0,0 +1,11 @@
+iD.actions.AddMidpoint = function(midpoint, node) {
+ return function(graph) {
+ graph = graph.replace(node.move(midpoint.loc));
+
+ midpoint.ways.forEach(function(way) {
+ graph = graph.replace(graph.entity(way.id).addNode(node.id, way.index));
+ });
+
+ return graph;
+ };
+};
diff --git a/js/id/behavior/drag_midpoint.js b/js/id/behavior/drag_midpoint.js
index 9f73a7115..72691a512 100644
--- a/js/id/behavior/drag_midpoint.js
+++ b/js/id/behavior/drag_midpoint.js
@@ -1,29 +1,21 @@
iD.behavior.DragMidpoint = function(mode) {
var history = mode.history,
- projection = mode.map.projection,
- behavior = iD.behavior.drag()
+ projection = mode.map.projection;
+
+ var behavior = iD.behavior.drag()
.delegate(".midpoint")
.origin(function(d) {
return projection(d.loc);
})
.on('start', function(d) {
- var w, nds;
- d.node = iD.Node({loc: d.loc});
- var args = [iD.actions.AddNode(d.node)];
- for (var i = 0; i < d.ways.length; i++) {
- w = d.ways[i], nds = w.nodes;
- for (var j = 0; j < nds.length; j++) {
- if ((nds[j] === d.nodes[0] && nds[j + 1] === d.nodes[1]) ||
- (nds[j] === d.nodes[1] && nds[j + 1] === d.nodes[0])) {
- args.push(iD.actions.AddWayNode(w.id, d.node.id, j + 1));
- }
- }
- }
- history.perform.apply(history, args);
- var node = d3.selectAll('.node.vertex')
- .filter(function(data) { return data.id === d.node.id; });
- behavior.target(node.node(), node.datum());
+ var node = iD.Node();
+ history.perform(iD.actions.AddMidpoint(d, node));
+
+ var vertex = d3.selectAll('.vertex')
+ .filter(function(data) { return data.id === node.id; });
+
+ behavior.target(vertex.node(), vertex.datum());
})
.on('move', function(d) {
d3.event.sourceEvent.stopPropagation();
@@ -35,5 +27,6 @@ iD.behavior.DragMidpoint = function(mode) {
iD.actions.Noop(),
'added a node to a way');
});
+
return behavior;
};
diff --git a/js/id/svg/midpoints.js b/js/id/svg/midpoints.js
index 655e35013..da4af659c 100644
--- a/js/id/svg/midpoints.js
+++ b/js/id/svg/midpoints.js
@@ -15,19 +15,17 @@ iD.svg.Midpoints = function(projection) {
b = nodes[j + 1],
id = [a.id, b.id].sort().join('-');
- if (!midpoints[id] &&
- iD.geo.dist(projection(a.loc), projection(b.loc)) > 40) {
-
- var midpoint_loc = iD.geo.interp(a.loc, b.loc, 0.5),
- parents = _.intersection(graph.parentWays(a),
- graph.parentWays(b));
+ if (midpoints[id]) {
+ midpoints[id].ways.push({id: entity.id, index: j + 1});
+ } else if (iD.geo.dist(projection(a.loc), projection(b.loc)) > 40) {
midpoints[id] = {
- loc: midpoint_loc,
- ways: parents,
- nodes: [a.id, b.id],
+ midpoint: true,
id: id,
- midpoint: true
+ loc: iD.geo.interp(a.loc, b.loc, 0.5),
+ a: a.id,
+ b: b.id,
+ ways: [{id: entity.id, index: j + 1}]
};
}
}
@@ -35,7 +33,7 @@ iD.svg.Midpoints = function(projection) {
var groups = surface.select('.layer-hit').selectAll('g.midpoint')
.filter(filter)
- .data(_.values(midpoints), function (d) { return [d.parents, d.id].join(","); });
+ .data(_.values(midpoints), function (d) { return d.id; });
var group = groups.enter()
.insert('g', ':first-child')
diff --git a/test/index.html b/test/index.html
index 4bdd4b5ba..731800f62 100644
--- a/test/index.html
+++ b/test/index.html
@@ -68,6 +68,7 @@
+
@@ -137,6 +138,7 @@
+
@@ -170,6 +172,7 @@
+
diff --git a/test/index_packaged.html b/test/index_packaged.html
index 7ae72a056..aba99ba04 100644
--- a/test/index_packaged.html
+++ b/test/index_packaged.html
@@ -32,6 +32,7 @@
+
@@ -65,6 +66,7 @@
+
diff --git a/test/spec/actions/add_midpoint.js b/test/spec/actions/add_midpoint.js
new file mode 100644
index 000000000..1f749217e
--- /dev/null
+++ b/test/spec/actions/add_midpoint.js
@@ -0,0 +1,22 @@
+describe("iD.actions.AddMidpoint", function () {
+ it("adds the node at the midpoint location", function () {
+ var node = iD.Node(),
+ midpoint = {loc: [1, 2], ways: []},
+ graph = iD.actions.AddMidpoint(midpoint, node)(iD.Graph());
+
+ expect(graph.entity(node.id).loc).to.eql([1, 2]);
+ });
+
+ it("adds the node to all ways at the respective indexes", function () {
+ var node = iD.Node(),
+ a = iD.Node(),
+ b = iD.Node(),
+ w1 = iD.Way(),
+ w2 = iD.Way({nodes: [a.id, b.id]}),
+ midpoint = {loc: [1, 2], ways: [{id: w1.id, index: 0}, {id: w2.id, index: 1}]},
+ graph = iD.actions.AddMidpoint(midpoint, node)(iD.Graph([a, b, w1, w2]));
+
+ expect(graph.entity(w1.id).nodes).to.eql([node.id]);
+ expect(graph.entity(w2.id).nodes).to.eql([a.id, node.id, b.id]);
+ });
+});
diff --git a/test/spec/svg/midpoints.js b/test/spec/svg/midpoints.js
new file mode 100644
index 000000000..c34ac0350
--- /dev/null
+++ b/test/spec/svg/midpoints.js
@@ -0,0 +1,52 @@
+describe("iD.svg.Midpoints", function () {
+ var surface,
+ projection = Object,
+ filter = d3.functor(true);
+
+ beforeEach(function () {
+ surface = d3.select(document.createElementNS('http://www.w3.org/2000/svg', 'svg'))
+ .call(iD.svg.Surface());
+ });
+
+ it("finds the location of the midpoints", function () {
+ var a = iD.Node({loc: [0, 0]}),
+ b = iD.Node({loc: [50, 0]}),
+ line = iD.Way({nodes: [a.id, b.id]}),
+ graph = iD.Graph([a, b, line]);
+
+ surface.call(iD.svg.Midpoints(projection), graph, [line], filter);
+
+ expect(surface.select('.midpoint').datum().loc).to.eql([25, 0]);
+ });
+
+ it("doesn't create midpoints on segments with pixel length less than 40", function () {
+ var a = iD.Node({loc: [0, 0]}),
+ b = iD.Node({loc: [39, 0]}),
+ line = iD.Way({nodes: [a.id, b.id]}),
+ graph = iD.Graph([a, b, line]);
+
+ surface.call(iD.svg.Midpoints(projection), graph, [line], filter);
+
+ expect(surface.selectAll('.midpoint')[0]).to.have.length(0);
+ });
+
+ it("binds a datum whose 'ways' property lists ways which include the segement", function () {
+ var a = iD.Node({loc: [0, 0]}),
+ b = iD.Node({loc: [50, 0]}),
+ c = iD.Node({loc: [1, 1]}),
+ d = iD.Node({loc: [2, 2]}),
+ l1 = iD.Way({nodes: [a.id, b.id]}),
+ l2 = iD.Way({nodes: [b.id, a.id]}),
+ l3 = iD.Way({nodes: [c.id, a.id, b.id, d.id]}),
+ l4 = iD.Way({nodes: [a.id, d.id, b.id]}),
+ graph = iD.Graph([a, b, c, d, l1, l2, l3, l4]),
+ ab = function (d) { return d.id === [a.id, b.id].sort().join("-"); };
+
+ surface.call(iD.svg.Midpoints(projection), graph, [l1, l2, l3, l4], filter);
+
+ expect(surface.selectAll('.midpoint').filter(ab).datum().ways).to.eql([
+ {id: l1.id, index: 1},
+ {id: l2.id, index: 1},
+ {id: l3.id, index: 2}]);
+ });
+});