mirror of
https://github.com/FoggedLens/iD.git
synced 2026-06-05 22:46:38 +02:00
Extract iD.Difference
iD.Difference represents the difference between two graphs. It knows how to calculate the set of entities that were created, modified, or deleted, and also contains the logic for recursively extending a difference to the complete set of entities that will require a redraw, taking into account child and parent relationships. Additionally, all history mutators now return a difference.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
iD.Difference represents the difference between two graphs.
|
||||
It knows how to calculate the set of entities that were
|
||||
created, modified, or deleted, and also contains the logic
|
||||
for recursively extending a difference to the complete set
|
||||
of entities that will require a redraw, taking into account
|
||||
child and parent relationships.
|
||||
*/
|
||||
iD.Difference = function (base, head) {
|
||||
var changes = {}, length = 0;
|
||||
|
||||
_.each(head.entities, function(h, id) {
|
||||
var b = base.entities[id];
|
||||
if (h !== b) {
|
||||
changes[id] = {base: b, head: h};
|
||||
length++;
|
||||
}
|
||||
});
|
||||
|
||||
_.each(base.entities, function(b, id) {
|
||||
var h = head.entities[id];
|
||||
if (!changes[id] && h !== b) {
|
||||
changes[id] = {base: b, head: h};
|
||||
length++;
|
||||
}
|
||||
});
|
||||
|
||||
var difference = {};
|
||||
|
||||
difference.length = function () {
|
||||
return length;
|
||||
};
|
||||
|
||||
difference.changes = function() {
|
||||
return changes;
|
||||
};
|
||||
|
||||
difference.modified = function() {
|
||||
var result = [];
|
||||
_.each(changes, function(change) {
|
||||
if (change.base && change.head) result.push(change.head);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.created = function() {
|
||||
var result = [];
|
||||
_.each(changes, function(change) {
|
||||
if (!change.base && change.head) result.push(change.head);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.deleted = function() {
|
||||
var result = [];
|
||||
_.each(changes, function(change) {
|
||||
if (change.base && !change.head) result.push(change.base);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
difference.complete = function(extent) {
|
||||
var result = {}, id, change;
|
||||
|
||||
function addParents(parents) {
|
||||
for (var i = 0; i < parents.length; i++) {
|
||||
var parent = parents[i];
|
||||
|
||||
if (parent.id in result)
|
||||
continue;
|
||||
|
||||
result[parent.id] = parent;
|
||||
addParents(head.parentRelations(parent));
|
||||
}
|
||||
}
|
||||
|
||||
for (id in changes) {
|
||||
change = changes[id];
|
||||
|
||||
var h = change.head,
|
||||
b = change.base,
|
||||
entity = h || b;
|
||||
|
||||
if (extent && !entity.intersects(extent, h ? head : base))
|
||||
continue;
|
||||
|
||||
result[id] = h;
|
||||
|
||||
if (entity.type === 'way') {
|
||||
var nh = h ? h.nodes : [],
|
||||
nb = b ? b.nodes : [],
|
||||
diff;
|
||||
|
||||
diff = _.difference(nh, nb);
|
||||
for (var i = 0; i < diff.length; i++) {
|
||||
result[diff[i]] = head.entity(diff[i]);
|
||||
}
|
||||
|
||||
diff = _.difference(nb, nh);
|
||||
for (var i = 0; i < diff.length; i++) {
|
||||
result[diff[i]] = head.entity(diff[i]);
|
||||
}
|
||||
}
|
||||
|
||||
addParents(head.parentWays(entity));
|
||||
addParents(head.parentRelations(entity));
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
return difference;
|
||||
};
|
||||
@@ -232,65 +232,5 @@ iD.Graph.prototype = {
|
||||
}
|
||||
}
|
||||
return items;
|
||||
},
|
||||
|
||||
difference: function (graph) {
|
||||
|
||||
function diff(a, b) {
|
||||
var result = [],
|
||||
keys = Object.keys(a.entities),
|
||||
entity, oldentity, id, i;
|
||||
|
||||
for (i = 0; i < keys.length; i++) {
|
||||
id = keys[i];
|
||||
entity = a.entities[id];
|
||||
oldentity = b.entities[id];
|
||||
if (entity !== oldentity) {
|
||||
|
||||
// maybe adding affected children better belongs in renderer/map.js?
|
||||
if (entity && entity.type === 'way' &&
|
||||
oldentity && oldentity.type === 'way') {
|
||||
result = result
|
||||
.concat(_.difference(entity.nodes, oldentity.nodes))
|
||||
.concat(_.difference(oldentity.nodes, entity.nodes));
|
||||
|
||||
} else if (entity && entity.type === 'way') {
|
||||
result = result.concat(entity.nodes);
|
||||
|
||||
} else if (oldentity && oldentity.type === 'way') {
|
||||
result = result.concat(oldentity.nodes);
|
||||
}
|
||||
|
||||
result.push(id);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return _.unique(diff(this, graph).concat(diff(graph, this)).sort());
|
||||
},
|
||||
|
||||
modified: function() {
|
||||
var result = [], base = this.base().entities;
|
||||
_.each(this.entities, function(entity, id) {
|
||||
if (entity && base[id]) result.push(id);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
created: function() {
|
||||
var result = [], base = this.base().entities;
|
||||
_.each(this.entities, function(entity, id) {
|
||||
if (entity && !base[id]) result.push(id);
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
deleted: function() {
|
||||
var result = [], base = this.base().entities;
|
||||
_.each(this.entities, function(entity, id) {
|
||||
if (!entity && base[id]) result.push(id);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
+21
-23
@@ -21,7 +21,9 @@ iD.History = function() {
|
||||
}
|
||||
|
||||
function change(previous) {
|
||||
dispatch.change(history.graph().difference(previous));
|
||||
var difference = iD.Difference(previous, history.graph());
|
||||
dispatch.change(difference);
|
||||
return difference;
|
||||
}
|
||||
|
||||
var history = {
|
||||
@@ -42,7 +44,7 @@ iD.History = function() {
|
||||
stack.push(perform(arguments));
|
||||
index++;
|
||||
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
replace: function () {
|
||||
@@ -51,7 +53,7 @@ iD.History = function() {
|
||||
// assert(index == stack.length - 1)
|
||||
stack[index] = perform(arguments);
|
||||
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
pop: function () {
|
||||
@@ -60,7 +62,7 @@ iD.History = function() {
|
||||
if (index > 0) {
|
||||
index--;
|
||||
stack.pop();
|
||||
change(previous);
|
||||
return change(previous);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -80,7 +82,7 @@ iD.History = function() {
|
||||
}
|
||||
|
||||
dispatch.undone();
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
redo: function () {
|
||||
@@ -92,7 +94,7 @@ iD.History = function() {
|
||||
}
|
||||
|
||||
dispatch.redone();
|
||||
change(previous);
|
||||
return change(previous);
|
||||
},
|
||||
|
||||
undoAnnotation: function () {
|
||||
@@ -111,31 +113,27 @@ iD.History = function() {
|
||||
}
|
||||
},
|
||||
|
||||
changes: function () {
|
||||
var initial = stack[0].graph,
|
||||
current = stack[index].graph;
|
||||
difference: function () {
|
||||
var base = stack[0].graph,
|
||||
head = stack[index].graph;
|
||||
return iD.Difference(base, head);
|
||||
},
|
||||
|
||||
changes: function () {
|
||||
var difference = history.difference();
|
||||
return {
|
||||
modified: current.modified().map(function (id) {
|
||||
return current.entity(id);
|
||||
}),
|
||||
created: current.created().map(function (id) {
|
||||
return current.entity(id);
|
||||
}),
|
||||
deleted: current.deleted().map(function (id) {
|
||||
return initial.entity(id);
|
||||
})
|
||||
};
|
||||
modified: difference.modified(),
|
||||
created: difference.created(),
|
||||
deleted: difference.deleted()
|
||||
}
|
||||
},
|
||||
|
||||
hasChanges: function() {
|
||||
return !!this.numChanges();
|
||||
return this.difference().length() > 0;
|
||||
},
|
||||
|
||||
numChanges: function() {
|
||||
return d3.sum(d3.values(this.changes()).map(function(c) {
|
||||
return c.length;
|
||||
}));
|
||||
return this.difference().length();
|
||||
},
|
||||
|
||||
imagery_used: function(source) {
|
||||
|
||||
+4
-29
@@ -64,44 +64,19 @@ iD.Map = function(context) {
|
||||
extent = map.extent(),
|
||||
graph = context.graph();
|
||||
|
||||
function addParents(parents) {
|
||||
for (var i = 0; i < parents.length; i++) {
|
||||
var parent = parents[i];
|
||||
if (only[parent.id] === undefined) {
|
||||
only[parent.id] = parent;
|
||||
addParents(graph.parentRelations(parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!difference) {
|
||||
all = graph.intersects(extent);
|
||||
filter = d3.functor(true);
|
||||
} else {
|
||||
var only = {};
|
||||
|
||||
for (var j = 0; j < difference.length; j++) {
|
||||
var id = difference[j],
|
||||
entity = graph.entity(id);
|
||||
|
||||
// Even if the entity is false (deleted), it needs to be
|
||||
// removed from the surface
|
||||
only[id] = entity;
|
||||
|
||||
if (entity && entity.intersects(extent, graph)) {
|
||||
addParents(graph.parentWays(only[id]));
|
||||
addParents(graph.parentRelations(only[id]));
|
||||
}
|
||||
}
|
||||
|
||||
all = _.compact(_.values(only));
|
||||
var complete = difference.complete(extent);
|
||||
all = _.compact(_.values(complete));
|
||||
filter = function(d) {
|
||||
if (d.type === 'midpoint') {
|
||||
for (var i = 0; i < d.ways.length; i++) {
|
||||
if (d.ways[i].id in only) return true;
|
||||
if (d.ways[i].id in complete) return true;
|
||||
}
|
||||
} else {
|
||||
return d.id in only;
|
||||
return d.id in complete;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user