Use scope and don't bind in connection.

This commit is contained in:
Tom MacWright
2012-10-18 16:13:57 -04:00
parent 361549368c
commit d8169ddb14
3 changed files with 151 additions and 178 deletions
-1
View File
@@ -53,7 +53,6 @@ require(["dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/dom","dojo/Evented
width: dom.byId('map').offsetWidth,
height: dom.byId('map').offsetHeight
});
conn.registerMap(map);
map.ruleset = ruleset;
// Initialise controller
+147 -173
View File
@@ -7,68 +7,65 @@
if (typeof iD === 'undefined') iD = {};
iD.Connection = function(apiURL) {
// summary: The data store, including methods to fetch data from (and, eventually, save data to)
// an OSM API server.
this.nextNode = -1; // next negative ids
this.nextWay = -1; // |
this.nextRelation = -1; // |
this.nodes={};
this.ways={};
this.relations= {};
this.pois = {};
this.maps=[];
this.modified=false;
this.apiBaseURL=apiURL;
this.callback = null;
};
// summary: The data store, including methods to fetch data from (and, eventually, save data to)
// an OSM API server.
var nextNode = -1, // next negative ids
nextWay = -1, // |
nextRelation = -1, // |
nodes = {},
ways = {},
relations = {},
pois = {},
modified = false,
apiBaseURL = apiURL;
iD.Connection.prototype = {
_assign:function(obj) {
// summary: Save an entity to the data store.
switch (obj.entityType) {
case "node": this.nodes[obj.id]=obj; break;
case "way": this.ways[obj.id]=obj; break;
case "relation": this.relations[obj.id]=obj; break;
}
},
var connection = {};
_getOrCreate:function(id,type) {
// summary: Return an entity if it exists: if not, create an empty one with the given id, and return that.
switch (type) {
case "node":
if (!this.nodes[id]) this._assign(new iD.Node(this, id, NaN, NaN, {}, false));
return this.nodes[id];
case "way":
if (!this.ways[id]) this._assign(new iD.Way(this, id, [], {}, false));
return this.ways[id];
case "relation":
if (!this.relations[id]) this._assign(new iD.Relation(this, id, [], {}, false));
return this.relations[id];
}
},
function assign(obj) {
// summary: Save an entity to the data store.
switch (obj.entityType) {
case "node": nodes[obj.id]=obj; break;
case "way": ways[obj.id]=obj; break;
case "relation": relations[obj.id]=obj; break;
}
}
doCreateNode:function(tags, lat, lon, perform) {
// summary: Create a new node and save it in the data store, using an undo stack.
var node = new iD.Node(this, this.nextNode--, lat, lon, tags, true);
perform(new iD.actions.CreateEntityAction(node, _.bind(this._assign, this) ));
return node; // iD.Node
},
function getOrCreate(id, type) {
// summary: Return an entity if it exists: if not, create an empty one with the given id, and return that.
if (type === 'node') {
if (!nodes[id]) assign(new iD.Node(connection, id, NaN, NaN, {}, false));
return nodes[id];
} else if (type === 'way') {
if (!ways[id]) assign(new iD.Way(connection, id, [], {}, false));
return ways[id];
} else if (type === 'relation') {
if (!relations[id]) assign(new iD.Relation(connection, id, [], {}, false));
return relations[id];
}
}
doCreateWay:function(tags, nodes, perform) {
// summary: Create a new way and save it in the data store, using an undo stack.
var way = new iD.Way(this, this.nextWay--, nodes.concat(), tags, true);
perform(new iD.actions.CreateEntityAction(way, _.bind(this._assign, this) ));
return way;
},
function doCreateNode(tags, lat, lon, perform) {
// summary: Create a new node and save it in the data store, using an undo stack.
var node = new iD.Node(connection, nextNode--, lat, lon, tags, true);
perform(new iD.actions.CreateEntityAction(node, assign));
return node; // iD.Node
}
doCreateRelation:function(tags, members, perform) {
// summary: Create a new relation and save it in the data store, using an undo stack.
var relation = new iD.Relation(this, this.nextRelation--, members.concat(), tags, true);
perform(new iD.actions.CreateEntityAction(relation, _.bind(this._assign, this) ));
return relation;
},
function doCreateWay(tags, nodes, perform) {
// summary: Create a new way and save it in the data store, using an undo stack.
var way = new iD.Way(connection, nextWay--, nodes.concat(), tags, true);
perform(new iD.actions.CreateEntityAction(way, assign));
return way;
}
getObjectsByBbox:function(left,right,top,bottom) {
function doCreateRelation(tags, members, perform) {
// summary: Create a new relation and save it in the data store, using an undo stack.
var relation = new iD.Relation(connection, nextRelation--, members.concat(), tags, true);
perform(new iD.actions.CreateEntityAction(relation, assign));
return relation;
}
function getObjectsByBbox(left,right,top,bottom) {
// summary: Find all drawable entities that are within a given bounding box.
// returns: Object An object with four properties: .poisInside, .poisOutside, .waysInside, .waysOutside.
// Each one is an array of entities.
@@ -78,162 +75,139 @@ iD.Connection.prototype = {
waysInside: [],
waysOutside: []
};
for (var id in this.ways) {
var way = this.ways[id];
for (var id in ways) {
var way = ways[id];
if (way.within(left,right,top,bottom)) { o.waysInside.push(way); }
else { o.waysOutside.push(way); }
}
_.each(this.pois, function(node) {
_.each(pois, function(node) {
if (node.within(left,right,top,bottom)) { o.poisInside.push(node); }
else { o.poisOutside.push(node); }
});
return o;
},
}
// ---------------
// Redraw handling
// ------------
// POI handling
function updatePOIs(nodelist) {
// summary: Update the list of POIs (nodes not in ways) from a supplied array of nodes.
_.each(nodelist, function(node) {
if (node.entity.hasParentWays()) {
delete pois[node._id];
} else {
pois[node._id] = node;
}
});
}
registerMap:function(map) {
// summary: Record that a Map object wants updates from this Connection.
this.maps.push(map);
},
function getPOIs() {
// summary: Return a list of all the POIs in connection Connection.
return _.values(pois);
}
refreshMaps:function() {
// summary: Redraw all the Map objects that take data from this Connection.
_.each(this.maps, function(map) {
map.updateUIs(false,true);
});
},
function registerPOI(node) {
// summary: Register a node as a POI (not in a way).
pois[node._id] = node;
}
refreshEntity: function(entity) {
// summary: Redraw a particular entity on all the Map objects that take data from this Connection.
_.each(this.maps, function(map) {
map.refreshUI(entity);
});
},
function unregisterPOI(node) {
// summary: Mark a node as no longer being a POI (it's now in a way).
delete pois[node._id];
}
// ------------
// POI handling
updatePOIs:function(nodelist) {
// summary: Update the list of POIs (nodes not in ways) from a supplied array of nodes.
for (var i in nodelist) {
if (nodelist[i].entity.hasParentWays()) {
delete this.pois[nodelist[i]._id];
} else {
this.pois[nodelist[i]._id] = nodelist[i];
}
}
},
// ----------
// OSM parser
getPOIs:function() {
// summary: Return a list of all the POIs in this Connection.
return _.values(this.pois);
},
registerPOI:function(node) {
// summary: Register a node as a POI (not in a way).
this.pois[node._id] = node;
},
unregisterPOI:function(node) {
// summary: Mark a node as no longer being a POI (it's now in a way).
delete this.pois[node._id];
},
// ----------
// OSM parser
loadFromAPI: function(box) {
function loadFromAPI(box, callback) {
// summary: Request data within the bbox from an external OSM server. Currently hardcoded
// to use Overpass API (which has the relevant CORS headers).
this.loadFromURL("http://www.overpass-api.de/api/xapi?map?bbox=" + [box.west, box.south, box.east, box.north]);
},
loadFromURL("http://www.overpass-api.de/api/xapi?map?bbox=" +
[box.west, box.south, box.east, box.north], callback);
}
loadFromURL: function(url) {
// summary: Load all data from a given URL.
$.ajax({
function loadFromURL(url, callback) {
// summary: Load all data from a given URL.
$.ajax({
url: url,
context: this,
headers: { "X-Requested-With": null },
success: this._processOSM
success: parse(callback)
});
},
}
_processOSM:function(dom) {
var nodelist = [];
for (var i in dom.childNodes[0].childNodes) {
var obj = dom.childNodes[0].childNodes[i];
switch(obj.nodeName) {
case "node":
var node = new iD.Node(this,
function parse(callback) {
return function(dom) {
var nodelist = _.compact(_.map(dom.childNodes[0].childNodes, function(obj) {
if (obj.nodeName === 'node') {
var node = new iD.Node(connection,
+getAttribute(obj, 'id'),
+getAttribute(obj, 'lat'),
+getAttribute(obj, 'lon'),
getTags(obj));
this._assign(node);
nodelist.push(node);
break;
case "way":
var way = new iD.Way(this,
getAttribute(obj,'id'),
getNodes(obj, this),
assign(node);
return node;
} else if (obj.nodeName === 'way') {
var way = new iD.Way(connection,
getAttribute(obj, 'id'),
getNodes(obj, connection),
getTags(obj));
this._assign(way);
break;
case "relation":
var relation = new iD.Relation(this,
getAttribute(obj,'id'),
getMembers(obj, this),
assign(way);
} else if (obj.nodeName === 'relation') {
var relation = new iD.Relation(connection,
getAttribute(obj, 'id'),
getMembers(obj, connection),
getTags(obj));
this._assign(relation);
break;
}
}
this.updatePOIs(nodelist);
this.refreshMaps();
if (this.callback) { this.callback(); }
assign(relation);
}
}));
updatePOIs(nodelist);
if (callback) { callback(nodelist); }
// Private functions to parse DOM created from XML file
function filterNodeName(n) {
return function(item) {
return item.nodeName === n;
};
}
// Private functions to parse DOM created from XML file
function filterNodeName(n) {
return function(item) { return item.nodeName === n; };
}
function getAttribute(obj, name) {
return _.find(obj.attributes, filterNodeName(name)).nodeValue;
}
function getAttribute(obj, name) {
return _.find(obj.attributes, filterNodeName(name)).nodeValue;
}
function getTags(obj) {
return _(obj.childNodes).chain()
function getTags(obj) {
return _(obj.childNodes).chain()
.filter(filterNodeName('tag'))
.map(function(item) {
return [getAttribute(item,'k'), getAttribute(item,'v')];
}).object().value();
}
}
function getNodes(obj,conn) {
return _(obj.childNodes).chain()
function getNodes(obj,conn) {
return _(obj.childNodes).chain()
.filter(filterNodeName('nd'))
.map(function(item) {
return conn.nodes[getAttribute(item,'ref')];
return nodes[getAttribute(item,'ref')];
}).value();
}
}
function getMembers(obj,conn) {
return _(obj.childNodes).chain()
.filter(filterNodeName('member'))
.map(function(item) {
var id = getAttribute(item,'ref'),
function getMembers(obj,conn) {
return _(obj.childNodes).chain()
.filter(filterNodeName('member'))
.map(function(item) {
var id = getAttribute(item,'ref'),
type = getAttribute(item,'type'),
role = getAttribute(item,'role');
var obj = conn._getOrCreate(id,type);
return new iD.RelationMember(obj,role);
}).value();
}
}
var obj = getOrCreate(id,type);
return new iD.RelationMember(obj,role);
}).value();
}
};
}
connection.nodes = nodes;
connection.ways = ways;
connection.relations = relations;
connection.loadFromAPI = loadFromAPI;
connection.loadFromURL = loadFromURL;
connection.getObjectsByBbox = getObjectsByBbox;
return connection;
};
+4 -4
View File
@@ -224,10 +224,10 @@ declare("iD.renderer.Map", null, {
download:function() {
// summary: Ask the connection to download data for the current viewport.
this.conn.loadFromAPI(this.extent);
this.conn.loadFromAPI(this.extent, _.bind(this.updateUIs, this));
},
updateUIs:function(redraw,remove) {
updateUIs: function(redraw, remove) {
// summary: Draw/refresh all EntityUIs within the bbox, and remove any others.
// redraw: Boolean Should we redraw any UIs that are already present?
// remove: Boolean Should we delete any UIs that are no longer in the bbox?
@@ -243,7 +243,7 @@ declare("iD.renderer.Map", null, {
else if (redraw) { m.wayuis[way.id].recalculate(); m.wayuis[way.id].redraw(); }
});
if (remove) {
if (remove !== false) {
array.forEach(o.waysOutside, function(way) {
if (m.wayuis[way.id]) { // && !m.wayuis[way.id].purgable
if (redraw) { m.wayuis[way.id].recalculate(); m.wayuis[way.id].redraw(); }
@@ -257,7 +257,7 @@ declare("iD.renderer.Map", null, {
else if (redraw) { m.nodeuis[poi.id].redraw(); }
});
if (remove) {
if (remove !== false) {
array.forEach(o.poisOutside, function(poi) {
if (m.nodeuis[poi.id]) { // && !m.nodeuis[poi.id].purgable
if (redraw) { m.nodeuis[poi.id].redraw(); }