diff --git a/index.html b/index.html index e44acbd39..2b9aa6fad 100644 --- a/index.html +++ b/index.html @@ -103,7 +103,7 @@
diff --git a/js/id/actions/delete_node.js b/js/id/actions/delete_node.js index e8b6d34da..5207d190a 100644 --- a/js/id/actions/delete_node.js +++ b/js/id/actions/delete_node.js @@ -3,7 +3,7 @@ iD.actions.DeleteNode = function(nodeId) { return function(graph) { var node = graph.entity(nodeId); - graph.parentWays(nodeId) + graph.parentWays(node) .forEach(function(parent) { graph = iD.actions.RemoveWayNode(parent.id, nodeId)(graph); }); diff --git a/js/id/actions/delete_way.js b/js/id/actions/delete_way.js index 120ac17f5..c2065a756 100644 --- a/js/id/actions/delete_way.js +++ b/js/id/actions/delete_way.js @@ -3,7 +3,7 @@ iD.actions.DeleteWay = function(wayId) { return function(graph) { var way = graph.entity(wayId); - graph.parentRelations(wayId) + graph.parentRelations(way) .forEach(function(parent) { graph = iD.actions.RemoveRelationMember(parent.id, wayId)(graph); }); @@ -17,7 +17,8 @@ iD.actions.DeleteWay = function(wayId) { graph = iD.actions.RemoveWayNode(wayId, nodeId)(graph); - if (!graph.parentWays(nodeId).length && !graph.parentRelations(nodeId).length) { + if (!graph.parentWays(node).length && + !graph.parentRelations(node).length) { if (!node.hasInterestingTags()) { graph = graph.remove(node); } else { diff --git a/js/id/actions/reverse_way.js b/js/id/actions/reverse_way.js index ca3bd03e3..37ac53f10 100644 --- a/js/id/actions/reverse_way.js +++ b/js/id/actions/reverse_way.js @@ -62,7 +62,7 @@ iD.actions.ReverseWay = function(wayId) { tags[reverseKey(key)] = reverseValue(key, way.tags[key]); } - graph.parentRelations(way.id).forEach(function (relation) { + graph.parentRelations(way).forEach(function (relation) { relation.members.forEach(function (member, index) { if (member.id === way.id && (role = {forward: 'backward', backward: 'forward'}[member.role])) { graph = iD.actions.UpdateRelationMember(relation.id, index, {role: role})(graph); diff --git a/js/id/connection.js b/js/id/connection.js index 3e7857da7..2ac1ffe7f 100644 --- a/js/id/connection.js +++ b/js/id/connection.js @@ -86,17 +86,53 @@ iD.Connection = function() { var root = dom.childNodes[0]; var entities = {}; refNodes = {}; + var rparentsOf = {}, + wparentsOf = {}; function addEntity(obj) { var o = objectData(obj); entities[o.id] = o; + + var i; + if (o.type === 'relation') { + for (i = 0; i < o.members.length; i++) { + if (o.members[i].id) { + if (rparentsOf[o.members[i].id] === undefined) { + rparentsOf[o.members[i].id] = []; + } + rparentsOf[o.members[i].id].push(o.id); + } + } + } + if (o.type === 'way') { + for (i = 0; i < o.nodes.length; i++) { + if (o.nodes[i]) { + if (wparentsOf[o.nodes[i]] === undefined) { + wparentsOf[o.nodes[i]] = []; + } + wparentsOf[o.nodes[i]].push(o.id); + } + } + } } _.forEach(root.getElementsByTagName('way'), addEntity); _.forEach(root.getElementsByTagName('node'), addEntity); _.forEach(root.getElementsByTagName('relation'), addEntity); - return iD.Graph(entities); + var g = iD.Graph(entities); + + for (var i in wparentsOf) { + if (entities[i]) g.transient(entities[i], + 'parentWays', d3.functor(wparentsOf[i])); + } + + for (i in rparentsOf) { + if (entities[i]) g.transient(entities[i], + 'parentRelations', d3.functor(rparentsOf[i])); + } + + return g; } function authenticated() { diff --git a/js/id/graph/graph.js b/js/id/graph/graph.js index 0fb618627..86fa337a4 100644 --- a/js/id/graph/graph.js +++ b/js/id/graph/graph.js @@ -25,7 +25,8 @@ iD.Graph.prototype = { transient: function(entity, key, fn) { var id = entity.id, - transients = this.transients[id] || (this.transients[id] = {}); + transients = this.transients[id] || + (this.transients[id] = {}); if (transients[key]) { return transients[key]; @@ -45,23 +46,38 @@ iD.Graph.prototype = { return nodes; }, - parentWays: function(id) { - var o = []; - for (var i in this.entities) { - if (this.entities[i] && - this.entities[i].type === 'way' && - this.entities[i].nodes.indexOf(id) !== -1) { - o.push(this.entities[i]); + parentWays: function(entity) { + var graph = this; + return this.transient(entity, 'parentWays', + function generateParentWays() { + var o = []; + for (var i in graph.entities) { + if (graph.entities[i] && + graph.entities[i].type === 'way' && + graph.entities[i].nodes.indexOf(this.id) !== -1) { + o.push(graph.entities[i]); + } } - } - return o; + return o; + }); }, - parentRelations: function(id) { + parentRelations: function(entity) { // This is slow and a bad hack. - return _.filter(this.entities, function buildParentRelations(e) { - return e && e.type === 'relation' && - _.pluck(e.members, 'id').indexOf(id) !== -1; + var graph = this; + return this.transient(entity, 'parentRelations', + function generateParentRelations() { + var o = [], id = this.id; + for (var i in graph.entities) { + if (graph.entities[i] && + graph.entities[i].type === 'relation' && + _.find(graph.entities[i].members, function(e) { + return e.id === id; + })) { + o.push(graph.entities[i]); + } + } + return o; }); }, diff --git a/js/id/renderer/map.js b/js/id/renderer/map.js index 1f15507d0..65bbe269d 100644 --- a/js/id/renderer/map.js +++ b/js/id/renderer/map.js @@ -79,7 +79,7 @@ iD.Map = function() { var id = difference[j]; only[id] = graph.fetch(id); if (only[id] && only[id].type === 'node') { - var parents = graph.parentWays(id); + var parents = graph.parentWays(only[id]); for (var k = 0; k < parents.length; k++) { // Don't re-fetch parents if (only[parents[k].id] === undefined) { diff --git a/test/spec/graph/graph.js b/test/spec/graph/graph.js index 20e1d0777..5cd57e617 100644 --- a/test/spec/graph/graph.js +++ b/test/spec/graph/graph.js @@ -69,18 +69,19 @@ describe('iD.Graph', function() { var node = iD.Node({id: "n1"}), way = iD.Way({id: "w1", nodes: ["n1"]}), graph = iD.Graph({n1: node, w1: way}); - expect(graph.parentWays("n1")).to.eql([way]); - expect(graph.parentWays("n2")).to.eql([]); + expect(graph.parentWays(node)).to.eql([way]); + expect(graph.parentWays(way)).to.eql([]); }); }); describe("#parentRelations", function() { it("returns an array of relations that contain the given entity id", function () { var node = iD.Node({id: "n1"}), + nonnode = iD.Node({id: "n2"}), relation = iD.Relation({id: "r1", members: [{ id: "n1", role: 'from' }]}), graph = iD.Graph({n1: node, r1: relation}); - expect(graph.parentRelations("n1")).to.eql([relation]); - expect(graph.parentRelations("n2")).to.eql([]); + expect(graph.parentRelations(node)).to.eql([relation]); + expect(graph.parentRelations(nonnode)).to.eql([]); }); });