Fix specs, add new GeoJSON class with mappings, rename entityType to

type
This commit is contained in:
Tom MacWright
2012-10-31 17:51:43 -04:00
parent 40c63b6886
commit 303128df1c
21 changed files with 101 additions and 153 deletions

View File

@@ -12,6 +12,7 @@
<script type="text/javascript" src="js/lib/underscore-min.js"></script>
<script type="text/javascript" src="js/lib/d3.v2.js"></script>
<script type="text/javascript" src="js/iD/id.js"></script>
<script type="text/javascript" src="js/iD/actions/UndoStack.js"></script>
<script type="text/javascript" src="js/iD/Util.js"></script>
<script type="text/javascript" src="js/iD/Taginfo.js"></script>
@@ -29,6 +30,7 @@
<script type="text/javascript" src="js/iD/renderer/markers.js"></script>
<script type="text/javascript" src="js/iD/ui/Inspector.js"></script>
<script type="text/javascript" src="js/iD/GeoJSON.js"></script>
<script type="text/javascript" src="js/iD/Node.js"></script>
<script type="text/javascript" src="js/iD/Relation.js"></script>
<script type="text/javascript" src="js/iD/Entity.js"></script>
@@ -36,6 +38,7 @@
<script type="text/javascript" src="js/iD/Connection.js"></script>
<script type="text/javascript" src="js/iD/Controller.js"></script>
<script type="text/javascript" src="js/iD/controller/DrawWay.js"></script>
<script type="text/javascript" src="js/iD/Graph.js"></script>
<div id="map"></div>
<div id='modebuttons'>

View File

@@ -1,15 +1,12 @@
if (typeof iD === 'undefined') iD = {};
iD.Connection = function() {
// summary: The data store, including methods to fetch data from (and, eventually, save data to)
// 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, // |
var nextNode = -1,
nextWay = -1,
nextRelation = -1,
entities = {},
relations = {},
pois = {},
apiURL = 'http://www.openstreetmap.org/api/0.6/map?bbox=',
apiURL = 'http://www.openstreetmap.org/api/0.6/',
modified = false;
var connection = {};
@@ -20,7 +17,7 @@ iD.Connection = function() {
function assign(obj) {
// summary: Save an entity to the data store.
if (obj.entityType === 'relation') {
if (obj.type === 'relation') {
if (!relations[obj.id]) relations[obj.id] = obj;
} else if (!entities[obj.id] || !entities[obj.id].loaded) {
entities[obj.id] = obj;
@@ -74,7 +71,7 @@ iD.Connection = function() {
// Request data within the bbox from an external OSM server.
function loadFromAPI(box, callback) {
loadFromURL(apiURL +
loadFromURL(apiURL + 'map?bbox=' +
[box[0][0], box[1][1], box[1][0], box[0][1]], callback);
}

View File

@@ -1,5 +1,3 @@
if (typeof iD === 'undefined') iD = {};
iD.Controller = function() {
var controller = {},
state = null;

View File

@@ -1,11 +1,9 @@
if (typeof iD === 'undefined') iD = {};
iD.Entity = function () {
this.parents = {};
this._id = iD.Util.id();
this.id = NaN;
this.loaded = false;
this.entityType = '';
this.type = '';
this.modified = false;
this.deleted = false;
};
@@ -36,7 +34,7 @@ iD.Entity.prototype = {
// summary: Does this entity have any parents which are ways?
var parentObjects = this.parentObjects();
for (var i = 0; i < parentObjects.length; i++) {
if (parentObjects[i].entityType === 'way') return true;
if (parentObjects[i].type === 'way') return true;
}
},
parentWays: function () {
@@ -49,7 +47,7 @@ iD.Entity.prototype = {
var poc = [];
var parentObjects = this.parentObjects();
for (var i = 0; i < parentObjects.length; i++) {
if (parentObjects[i].entityType === _class) {
if (parentObjects[i].type === _class) {
poc.push(parentObjects[i]);
}
}

31
js/iD/GeoJSON.js Normal file
View File

@@ -0,0 +1,31 @@
iD.GeoJSON = {
mapping: function(entity) {
if (this.mappings[entity.type]) {
return this.mappings[entity.type](entity);
}
},
mappings: {
node: function(entity) {
return {
type: 'Feature',
properties: entity.tags,
geometry: {
type: 'Point',
coordinates: [entity.lon, entity.lat]
}
};
},
way: function(entity) {
return {
type: 'Feature',
properties: entity.tags,
geometry: {
'type': 'LineString',
'coordinates': _.map(entity.nodes, function(node) {
return [node.lon, node.lat];
})
}
};
}
}
};

2
js/iD/Graph.js Normal file
View File

@@ -0,0 +1,2 @@
iD.Graph = function() {
};

View File

@@ -1,9 +1,7 @@
if (typeof iD === 'undefined') iD = {};
// [Node](http://wiki.openstreetmap.org/wiki/Node)
iD.Node = function(id, lat, lon, tags, loaded) {
// summary: An OSM node.
this.entityType = 'node';
this.type = 'node';
this.id = id;
this._id = iD.Util.id();
this.entity = new iD.Entity();
@@ -18,17 +16,6 @@ iD.Node = function(id, lat, lon, tags, loaded) {
};
iD.Node.prototype = {
toGeoJSON: function() {
return {
type: 'Feature',
properties: this.tags,
geometry: {
type: 'Point',
coordinates: [this.lon, this.lat]
}
};
},
intersects: function(extent) {
return (this.lon >= extent[0][0]) &&
(this.lon <= extent[1][0]) &&

View File

@@ -1,7 +1,5 @@
if (typeof iD === 'undefined') iD = {};
iD.Relation = function(id, members, tags, loaded) {
this.entityType = 'relation';
this.type = 'relation';
this.id = id;
this._id = iD.Util.id();
this.entity = new iD.Entity();

View File

@@ -1,5 +1,3 @@
if (typeof iD === 'undefined') iD = {};
// Taginfo service singleton
iD.Taginfo = (function() {

View File

@@ -1,5 +1,3 @@
if (typeof iD === 'undefined') iD = {};
iD.Util = {};
iD.Util._id = 0;

View File

@@ -1,5 +1,3 @@
if (typeof iD === 'undefined') iD = {};
// Way
// wiki: http://wiki.openstreetmap.org/wiki/Way
//
@@ -10,7 +8,7 @@ if (typeof iD === 'undefined') iD = {};
// `highway` or `barrier` tag and is not also tagged `area`.
iD.Way = function(id, nodes, tags, loaded) {
// summary: An OSM way.
this.entityType = 'way';
this.type = 'way';
this.id = id;
this._id = iD.Util.id();
this.deleted = false;
@@ -52,21 +50,8 @@ iD.Way.prototype = {
return false; // Boolean
},
toGeoJSON: function() {
return {
type: 'Feature',
properties: this.tags,
geometry: {
'type': 'LineString',
'coordinates': _.map(this.nodes, function(node) {
return [node.lon, node.lat];
})
}
};
},
updateBounds: function() {
this._bounds = d3.geo.bounds(this.toGeoJSON());
this._bounds = d3.geo.bounds(iD.GeoJSON.mapping(this));
},
bounds: function() {
@@ -91,69 +76,5 @@ iD.Way.prototype = {
// of the top-left
bounds[0][0] > extent[1][0] &&
bounds[0][1] > extent[1][1]);
},
// --------------
// Action callers
doAppendNode: function(node, performAction) {
// summary: Add a node to the end of the way, using an undo stack.
// returns: New length of the way.
if (node!=this.getLastNode()) performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, -1, true));
return this.nodes.length + 1; // int
},
doPrependNode: function(node, performAction) {
// summary: Add a node to the start of the way, using an undo stack.
// returns: New length of the way.
if (node!=this.nodes[0]) performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, 0, true));
return this.nodes.length + 1; // int
},
doInsertNode:function(index, node, performAction) {
// summary: Add a node at a given index within the way, using an undo stack.
if (index > 0 && this.nodes[index - 1]==node) return;
if (index < this.nodes.length - 1 && this.nodes[index]==node) return;
performAction(new iD.actions.AddNodeToWayAction(this, node, this.nodes, index, false));
},
doInsertNodeAtClosestPosition:function(newNode, isSnap, performAction) {
// summary: Add a node into whichever segment of the way is nearest, using an undo stack.
// isSnap: Boolean Should the node position be snapped to be exactly on the segment?
// returns: The index at which the node was inserted.
var closestProportion = 1,
newIndex = 0,
snapped;
for (var i = 0; i < this.nodes.length - 1; i++) {
var node1 = this.nodes[i],
node2 = this.nodes[i + 1],
directDist = this._pythagoras(node1, node2),
viaNewDist = this._pythagoras(node1, newNode) +
this._pythagoras(node2, newNode),
proportion = Math.abs(viaNewDist/directDist - 1);
if (proportion < closestProportion) {
newIndex = i+1;
closestProportion = proportion;
snapped = this._calculateSnappedPoint(node1, node2, newNode);
}
}
// splice in new node
if (isSnap) { newNode.doSetLonLatp(snapped.x, snapped.y, performAction); }
this.doInsertNode(newIndex, newNode, performAction);
return newIndex; // int
},
_pythagoras:function(node1, node2) {
return (Math.sqrt(Math.pow(node1.lon-node2.lon,2) +
Math.pow(node1.latp-node2.latp,2)));
},
_calculateSnappedPoint:function(node1, node2, newNode) {
var w = node2.lon - node1.lon;
var h = node2.latp - node1.latp;
var u = ((newNode.lon-node1.lon) * w + (newNode.latp-node1.latp) * h) / (w*w + h*h);
return { x: node1.lon + u*w, y: node1.latp + u*h };
}
};

View File

@@ -45,7 +45,7 @@ declare("iD.controller.shape.NoSelection", null, {
processMouseEvent: function(event, entityUI) {
var entity = entityUI ? entityUI.entity : null;
var entityType = entity ? entity.entityType : null;
var entityType = entity ? entity.type : null;
var map = this.controller.map;
var connection = map.connection;

View File

@@ -41,7 +41,7 @@ define(['dojo/_base/declare',
processMouseEvent: function(event, entityUI) {
var entity = entityUI ? entityUI.entity : null;
var entityType = entity ? entity.entityType : null;
var entityType = entity ? entity.type : null;
var way;
if (event.type === 'click') {

1
js/iD/id.js Normal file
View File

@@ -0,0 +1 @@
if (typeof iD === 'undefined') var iD = {};

View File

@@ -179,13 +179,13 @@ iD.Map = function(obj) {
var all = connection.intersects(extent());
var ways = all.filter(function(a) {
return a.entityType === 'way' && !a.isClosed();
return a.type === 'way' && !a.isClosed();
}).sort(waystack),
areas = all.filter(function(a) {
return a.entityType === 'way' && a.isClosed();
return a.type === 'way' && a.isClosed();
}),
points = all.filter(function(a) {
return a.entityType === 'node';
return a.type === 'node';
});
var fills = layers[0].fill.selectAll('path.area')

View File

@@ -17,7 +17,7 @@ iD.Inspector = function(selection) {
head.append('a')
.attr('class', 'permalink')
.attr('href', 'http://www.openstreetmap.org/browse/' +
d.entityType + '/' + d.id)
d.type + '/' + d.id)
.text('#' + d.id);
var table = d3.select(this)

View File

@@ -12,16 +12,21 @@
<!-- include source files here... -->
<script type="text/javascript" src="../js/lib/underscore-min.js"></script>
<script type="text/javascript" src="../js/lib/d3.v2.min.js"></script>
<script type="text/javascript" src="../js/iD/id.js"></script>
<script type="text/javascript" src="../js/iD/Util.js"></script>
<script type="text/javascript" src="../js/iD/Node.js"></script>
<script type="text/javascript" src="../js/iD/Relation.js"></script>
<script type="text/javascript" src="../js/iD/Entity.js"></script>
<script type="text/javascript" src="../js/iD/GeoJSON.js"></script>
<script type="text/javascript" src="../js/iD/Way.js"></script>
<script type="text/javascript" src="../js/iD/Connection.js"></script>
<script type="text/javascript" src="../js/iD/actions/UndoStack.js"></script>
<script type="text/javascript" src="../js/iD/ui/Inspector.js"></script>
<script type="text/javascript" src="../js/iD/Controller.js"></script>
<script type="text/javascript" src="../js/iD/renderer/markers.js"></script>
<script type="text/javascript" src="../js/iD/renderer/Map.js"></script>
<script type="text/javascript" src="../js/iD/renderer/tiles.js"></script>
<script type="text/javascript" src="../js/iD/Graph.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec/Util.js"></script>
@@ -31,6 +36,8 @@
<script type="text/javascript" src="spec/Way.js"></script>
<script type="text/javascript" src="spec/Map.js"></script>
<script type="text/javascript" src="spec/Connection.js"></script>
<script type="text/javascript" src="spec/Graph.js"></script>
<script type="text/javascript" src="spec/GeoJSON.js"></script>
<script type="text/javascript">
(function() {

15
test/spec/GeoJSON.js Normal file
View File

@@ -0,0 +1,15 @@
describe('GeoJSON', function() {
describe('#mapping', function() {
it('should be able to map a node to geojson', function() {
var node = new iD.Node(10, 38, -77);
expect(iD.GeoJSON.mapping(node).geometry.type).toEqual('Point');
});
it('should be able to map a way to geojson', function() {
var way = new iD.Way();
var gj = iD.GeoJSON.mapping(way);
expect(gj.type).toEqual('Feature');
expect(gj.geometry.type).toEqual('LineString');
});
});
});

View File

@@ -14,17 +14,21 @@ describe('Map', function() {
foo.parentNode.removeChild(foo);
});
it('can set and get its zoom level', function() {
expect(map.setZoom(4)).toEqual(map);
expect(map.getZoom()).toEqual(4);
describe('#getZoom', function() {
it('accurate reports zoom level', function() {
expect(map.setZoom(4)).toEqual(map);
expect(map.getZoom()).toEqual(4);
});
});
it('can zoom out and in', function() {
expect(map.setZoom(4)).toEqual(map);
expect(map.getZoom()).toEqual(4);
expect(map.zoomOut()).toEqual(map);
expect(map.getZoom()).toEqual(3);
expect(map.zoomIn()).toEqual(map);
expect(map.getZoom()).toEqual(4);
describe('#zoomIn', function() {
it('changes reported zoom level', function() {
expect(map.setZoom(4)).toEqual(map);
expect(map.getZoom()).toEqual(4);
expect(map.zoomOut()).toEqual(map);
expect(map.getZoom()).toEqual(3);
expect(map.zoomIn()).toEqual(map);
expect(map.getZoom()).toEqual(4);
});
});
});

View File

@@ -2,11 +2,11 @@ describe('Node', function() {
var node;
beforeEach(function() {
node = new iD.Node(null, 10, 38, -77);
node = new iD.Node(10, 38, -77);
});
it('is a node entity', function() {
expect(node.entityType).toEqual('node');
expect(node.type).toEqual('node');
});
it('should be initialized with a proper ID, lat, and lon', function() {
@@ -16,12 +16,6 @@ describe('Node', function() {
});
it('knows if it is within a bounding box', function() {
expect(node.within([[-90, 90], [90, -90]])).toBeTruthy();
});
it('can provide geojson', function() {
var gj = node.toGeoJSON();
expect(gj.type).toEqual('Feature');
expect(gj.geometry.type).toEqual('Point');
expect(node.intersects([[-90, 90], [90, -90]])).toBeTruthy();
});
});

View File

@@ -7,15 +7,17 @@ describe('Way', function() {
});
it('is a way', function() {
expect(way.entityType).toEqual('way');
expect(way.type).toEqual('way');
});
it('has zero nodes by default', function() {
expect(way.nodes.length).toEqual(0);
});
it('is closed by default', function() {
expect(way.isClosed()).toEqual(true);
describe('#isClosed', function() {
it('is closed by default', function() {
expect(way.isClosed()).toEqual(true);
});
});
it('is a way when it has no nodes', function() {
@@ -25,10 +27,4 @@ describe('Way', function() {
it('is also an area when it has no nodes', function() {
expect(way.isType('area')).toEqual(true);
});
it('can provide geojson', function() {
var gj = way.toGeoJSON();
expect(gj.type).toEqual('Feature');
expect(gj.geometry.type).toEqual('LineString');
});
});