Give map functions normal names, cache margin box

This commit is contained in:
Tom MacWright
2012-10-19 15:32:42 -04:00
parent 9c3bba4a5e
commit 7d58d661ff
14 changed files with 222 additions and 236 deletions

View File

@@ -16,6 +16,15 @@ a:visited, a {
color: black;
}
input[type=text] {
font:normal 13px/20px Helvetica, Arial, sans-serif;
padding:1px 2px;
}
input[type=text]:focus {
border-color:#222;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
@@ -144,16 +153,17 @@ polyline {
.edit-pane {
position:absolute;
display:none;
right:10px;
top:80px;
height:520px;
height:500px;
width:300px;
background:#fff;
overflow:auto;
box-shadow:#222 0px 0px 3px;
}
.edit-pane.active {
display:block;
right:0px;
}
.edit-pane h2 {
@@ -162,22 +172,6 @@ polyline {
background:#e4e4e4;
}
.tabs {
border-bottom:1px solid #ddd;
background:#e4e4e4;
}
.tabs a {
color:#888;
padding:5px;
text-decoration:none;
}
.tabs a.active {
color:#222;
background:#fff;
}
.edit-pane a.close {
position:absolute;
top:5px;
@@ -240,14 +234,6 @@ polyline {
0% { -moz-transform: rotate(0deg); }
100% { -moz-transform: rotate(360deg); }
}
@-ms-keyframes spinnerAnim {
0% { -ms-transform: rotate(0deg); }
100% { -ms-transform: rotate(360deg); }
}
@-o-keyframes spinnerAnim {
0% { -o-transform: rotate(0deg); }
100% { -o-transform: rotate(360deg); }
}
.spinner {
-webkit-animation-fill-mode: both;
-webkit-animation: spinnerAnim 1.5s infinite linear;
@@ -255,10 +241,4 @@ polyline {
-moz-animation-fill-mode: both;
-moz-animation: spinnerAnim 1.5s infinite linear;
-moz-transform-origin: 50% 50%;
-ms-animation-fill-mode: both;
-ms-animation: spinnerAnim 1.5s infinite linear;
-ms-transform-origin: 50% 50%;
-o-animation-fill-mode: both;
-o-animation: spinnerAnim 1.5s infinite linear;
-o-transform-origin: 50% 50%;
}

View File

@@ -140,11 +140,6 @@ require(["dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/dom","dojo/Evented
<div class='edit-pane'>
<h2>&nbsp;</h2>
<a class='close' href='#close'>&times;</a>
<div class='tabs'>
<a class='tab' href='#presets'>Presets</a>
<a class='tab' href='#tags'>Tags</a>
</div>
<div class='hud presets'></div>
<div class='hud tags'>
<table>
<thead>
@@ -157,6 +152,7 @@ require(["dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/dom","dojo/Evented
</tbody>
</table>
</div>
<div class='hud presets'></div>
</div>
</div>

View File

@@ -2,67 +2,67 @@
define(['dojo/_base/declare','iD/actions/UndoableAction'], function(declare){
// ----------------------------------------------------------------------
// AddNodeToWayAction class
// ----------------------------------------------------------------------
// AddNodeToWayAction class
declare("iD.actions.AddNodeToWayAction", [iD.actions.UndoableEntityAction], {
declare("iD.actions.AddNodeToWayAction", [iD.actions.UndoableEntityAction], {
node: null,
nodeList: null,
index: 0,
firstNode: null,
autoDelete: true,
constructor: function(way, node, nodeList, index, autoDelete) {
// summary: Add a node to a way at a specified index, or -1 for the end of the way.
this.entity = way;
this.node = node;
this.nodeList = nodeList;
this.index = index;
this.autoDelete = autoDelete;
},
node: null,
nodeList: null,
index: 0,
firstNode: null,
autoDelete: true,
doAction: function() {
var way = this.entity; // shorthand
constructor: function(way, node, nodeList, index, autoDelete) {
// summary: Add a node to a way at a specified index, or -1 for the end of the way.
this.entity = way;
this.node = node;
this.nodeList = nodeList;
this.index = index;
this.autoDelete = autoDelete;
},
// undelete way if it was deleted before (only happens on redo)
if (way.deleted) {
way.setDeletedState(false);
if (!this.firstNode.hasParentWays()) {
this.firstNode.connection.unregisterPOI(firstNode);
doAction: function() {
var way = this.entity; // shorthand
// undelete way if it was deleted before (only happens on redo)
if (way.deleted) {
way.setDeletedState(false);
if (!this.firstNode.hasParentWays()) {
this.firstNode.connection.unregisterPOI(firstNode);
}
this.firstNode.addParent(way);
}
this.firstNode.addParent(way);
}
// add the node
if (this.index === -1) this.index = this.nodeList.length;
this.node.entity.addParent(way);
this.node.connection.unregisterPOI(this.node);
this.nodeList.splice(this.index, 0, this.node);
this.markDirty();
way.expandBbox(this.node);
// add the node
if (this.index === -1) this.index = this.nodeList.length;
this.node.entity.addParent(way);
this.node.connection.unregisterPOI(this.node);
this.nodeList.splice(this.index, 0, this.node);
this.markDirty();
way.expandBbox(this.node);
return this.SUCCESS;
},
return this.SUCCESS;
},
undoAction: function() {
// summary: Remove the added node. Fixme: if the way is now 1-length, we should
// do something like deleting it and converting the remaining node to a POI.
var way=this.entity; // shorthand
if (this.autoDelete && way.length() === 2 &&
way.parentRelations().length()) return this.FAIL;
undoAction: function() {
// summary: Remove the added node. Fixme: if the way is now 1-length, we should
// do something like deleting it and converting the remaining node to a POI.
var way=this.entity; // shorthand
if (this.autoDelete && way.length() === 2 &&
way.parentRelations().length()) return this.FAIL;
// remove node
var removed=nodeList.splice(index, 1);
if (!_.contains(this.nodeList, removed[0])) {
removed[0].removeParent(way);
// remove node
var removed=nodeList.splice(index, 1);
if (!_.contains(this.nodeList, removed[0])) {
removed[0].removeParent(way);
}
this.markClean();
way.connection.refreshEntity(way);
return this.SUCCESS;
}
this.markClean();
way.connection.refreshEntity(way);
return this.SUCCESS;
}
});
});
// ----------------------------------------------------------------------
// End of module

View File

@@ -1,6 +1,6 @@
// iD/actions/UndoableAction.js
define(['dojo/_base/declare','iD/actions/UndoableAction'], function(declare){
define(['dojo/_base/declare','iD/actions/UndoableAction'], function(declare) {
// ----------------------------------------------------------------------
// CreateEntityAction class

View File

@@ -1,6 +1,7 @@
// iD/actions/CreatePOIAction.js
define(['dojo/_base/declare','dojo/_base/lang','iD/actions/UndoableAction'], function(declare,lang){
define(['dojo/_base/declare', 'iD/actions/UndoableAction'],
function(declare) {
// ----------------------------------------------------------------------
// CreatePOIAction class

View File

@@ -1,6 +1,7 @@
// iD/actions/MoveNodeAction.js
define(['dojo/_base/declare','iD/actions/UndoableAction'], function(declare){
define(['dojo/_base/declare','iD/actions/UndoableAction'],
function(declare) {
// ----------------------------------------------------------------------
// MoveNodeAction class

View File

@@ -1,6 +1,6 @@
// iD/controller/ControllerState.js
define(['dojo/_base/declare','dojo/_base/lang'], function(declare,lang) {
define(['dojo/_base/declare'], function(declare) {
// ----------------------------------------------------------------------
// ControllerState base class
@@ -51,7 +51,8 @@ declare("iD.controller.ControllerState", null, {
undoAdder:function() {
// summary: Shorthand for adding an action to the global undo stack, setting the scope correctly.
// return: Function
return lang.hitch(this.controller.undoStack, this.controller.undoStack.addAction);
return _.bind(this.controller.undoStack.addAction,
this.controller.undoStack);
}
});

View File

@@ -23,16 +23,7 @@ declare("iD.controller.edit.EditBaseState", [iD.controller.ControllerState], {
// entity: iD.Entity The entity to be edited.
$('.edit-pane h2').text(iD.Util.friendlyName(entity));
$('.edit-pane').show().addClass('active');
$('.edit-pane a.tab').click(function(e) {
$('.edit-pane a.tab').removeClass('active');
var hud = $(e.currentTarget).addClass('active')
.attr('href').split('#').pop();
$('.edit-pane .hud').hide();
$('.edit-pane .' + hud).show();
return e.preventDefault();
});
$('.edit-pane a.tab:first').click();
/*
var $presets = $('.edit-pane .presets');
// Build presets panel
iD.Util.presets(entity.entityType, function(presets) {
@@ -55,6 +46,7 @@ declare("iD.controller.edit.EditBaseState", [iD.controller.ControllerState], {
});
});
});
*/
// Build tag panel
$('.edit-pane .tags tbody').empty();

View File

@@ -126,7 +126,7 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
undo = new iD.actions.CompositeUndoableAction();
var node=this.appendNewNode(event, undo);
_.each(ways, function(w) {
w.doInsertNodeAtClosestPosition(node, true, lang.hitch(undo, undo.push));
w.doInsertNodeAtClosestPosition(node, true, _.bind(undo.push, this));
});
action = this.undoAdder();
action(undo);
@@ -167,16 +167,18 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
if (this.editEnd) {
this.way.doAppendNode(node, performAction);
this.controller.map.refreshUI(this.way);
} else {
this.way.doPrependNode(node, performAction);
}
else { this.way.doPrependNode(node, performAction); }
},
appendNewNode:function(event, undo) {
var map=this.controller.map;
var node=this.getConnection().doCreateNode({},
var map = this.controller.map;
var push = _.bind(undo.push, undo);
var node = this.getConnection().doCreateNode({},
map.coord2lat(map.mouseY(event)),
map.coord2lon(map.mouseX(event)), lang.hitch(undo,undo.push) );
this.appendNode(node, lang.hitch(undo,undo.push));
map.coord2lon(map.mouseX(event)), push);
this.appendNode(node, push);
return node;
}
});

View File

@@ -1,96 +1,94 @@
// iD/controller/shape/SelectedWay.js
/*
Add road or shape -> SelectedWay
// ## Add road or shape -> SelectedWay
//
// The user has clicked 'Add road or shape',
// then clicks an existing way that their new way will be connected
// to.
The user has clicked 'Add road or shape', then a way to start the new way at.
define(['dojo/_base/declare',
'iD/actions/UndoableAction',
'iD/controller/ControllerState'
], function(declare) {
*/
// ----------------------------------------------------------------------
// SelectedWayNode class
define(['dojo/_base/declare','dojo/_base/lang',
'iD/actions/UndoableAction',
'iD/controller/ControllerState'
], function(declare,lang){
declare("iD.controller.shape.SelectedWay", [iD.controller.ControllerState], {
// ----------------------------------------------------------------------
// SelectedWayNode class
way: null,
wayUI: null,
declare("iD.controller.shape.SelectedWay", [iD.controller.ControllerState], {
constructor: function(way) {
// summary: In 'Draw shape' mode, and a way is selected as the starting point of the new way.
this.way = way;
},
way: null,
wayUI: null,
enterState: function() {
this.wayUI = this.controller.map.getUI(this.way);
this.wayUI.setStateClass('selected')
.setStateClass('shownodes')
.redraw();
this.controller.stepper.message("Click the point on the way where you want to start your new way");
return this;
},
constructor: function(way) {
// summary: In 'Draw shape' mode, and a way is selected as the starting point of the new way.
this.way = way;
},
enterState:function() {
this.wayUI = this.controller.map.getUI(this.way);
this.wayUI.setStateClass('selected')
.setStateClass('shownodes')
.redraw();
this.controller.stepper.message("Click the point on the way where you want to start your new way");
return this;
},
exitState:function() {
this.wayUI.resetStateClass('selected')
exitState: function() {
this.wayUI.resetStateClass('selected')
.resetStateClass('shownodes')
.redraw();
return this;
},
return this;
},
processMouseEvent:function(event,entityUI) {
var entity=entityUI ? entityUI.entity : null;
var entityType=entity ? entity.entityType : null;
var way;
processMouseEvent: function(event, entityUI) {
var entity = entityUI ? entityUI.entity : null;
var entityType = entity ? entity.entityType : null;
var way;
if (event.type=='click') {
switch (entityType) {
case null:
return new iD.controller.shape.NoSelection();
case 'node':
var ways = entity.entity.parentWays();
if (entity.entity.hasParent(this.way)) {
// start a branching way from an existing point
way = this.getConnection().doCreateWay({}, [entity], lang.hitch(this, this.undoAdder));
this.controller.map.createUI(way);
return new iD.controller.shape.DrawWay(way);
} else if (ways.length===0) {
// convert POI into way
return this;
} else {
if (event.type === 'click') {
switch (entityType) {
case null:
return new iD.controller.shape.NoSelection();
case 'node':
var ways = entity.entity.parentWays();
if (entity.entity.hasParent(this.way)) {
// start a branching way from an existing point
way = this.getConnection().doCreateWay({}, [entity], _.bind(this.undoAdder, this));
this.controller.map.createUI(way);
return new iD.controller.shape.DrawWay(way);
} else if (ways.length===0) {
// convert POI into way
return this;
} else {
// select another way
return new iD.controller.shape.SelectedWay(entity.getParents()[0]);
}
break;
case 'way':
if (entity === this.way) {
// start a branching way from a new point
var map = this.controller.map;
var undo = new iD.actions.CompositeUndoableAction();
var startNode = this.getConnection().doCreateNode(
{},
map.coord2lat(map.mouseY(event)),
map.coord2lon(map.mouseX(event)), lang.hitch(undo,undo.push) );
entity.doInsertNodeAtClosestPosition(startNode, true, lang.hitch(undo,undo.push));
way = this.getConnection().doCreateWay({}, [startNode], lang.hitch(undo,undo.push) );
this.controller.undoStack.addAction(undo);
this.controller.map.createUI(way);
return new iD.controller.shape.DrawWay(way);
} else {
// select another way
return new iD.controller.shape.SelectedWay(entity);
}
}
} else {
}
return this;
}
});
case 'way':
if (entity === this.way) {
// start a branching way from a new point
var map = this.controller.map;
var undo = new iD.actions.CompositeUndoableAction();
var startNode = this.getConnection().doCreateNode({},
map.coord2lat(map.mouseY(event)),
map.coord2lon(map.mouseX(event)), _.bind(undo.push, undo));
entity.doInsertNodeAtClosestPosition(startNode, true, _.bind(undo.push, undo));
way = this.getConnection().doCreateWay({}, [startNode], _.bind(undo.push, undo) );
this.controller.undoStack.addAction(undo);
this.controller.map.createUI(way);
return new iD.controller.shape.DrawWay(way);
} else {
// select another way
return new iD.controller.shape.SelectedWay(entity);
}
}
} else {
}
return this;
}
// ----------------------------------------------------------------------
// End of module
});
// ----------------------------------------------------------------------
// End of module
});

View File

@@ -7,7 +7,8 @@
// fill images
// opacity
define(['dojo/_base/declare','dojo/_base/lang','iD/Entity','iD/renderer/Map'], function(declare,lang){
define(['dojo/_base/declare','iD/Entity','iD/renderer/Map'],
function(declare) {
// ----------------------------------------------------------------------
// EntityUI base class
@@ -69,7 +70,7 @@ declare("iD.renderer.EntityUI", null, {
},
getEnhancedTags:function() {
// summary: Return tags for this entity augmented by the EntityUI's state classes.
var tags = lang.clone(this.entity.tags);
var tags = _.clone(this.entity.tags);
// Apply stateClasses (hover, selected, hoverway, selectedway)
for (var i in this.stateClasses) {
tags[':'+this.stateClasses[i]] = 'yes';

View File

@@ -1,11 +1,11 @@
// iD/renderer/Map.js
// at present this combines P2's Map and MapPaint functionality
define(['dojo/_base/declare','dojo/_base/event','dojo/_base/lang',
define(['dojo/_base/declare','dojo/_base/event',
'dojo/dom-geometry',
'dojox/gfx','dojox/gfx/matrix',
'iD/Connection','iD/Entity','iD/renderer/EntityUI','iD/renderer/WayUI','iD/renderer/NodeUI'],
function(declare, Event, lang, domGeom, Gfx, Matrix){
function(declare, Event, domGeom, Gfx, Matrix){
// ----------------------------------------------------------------------
// Connection base class
@@ -59,7 +59,7 @@ declare("iD.renderer.Map", null, {
ruleset: null, // map style
constructor:function(obj) {
constructor: function(obj) {
// summary: The main map display, containing the individual sprites (UIs) for each entity.
// obj: Object An object containing .lat, .lon, .scale, .div (the name of the <div> to be used),
// .connection, .width (px) and .height (px) properties.
@@ -88,6 +88,9 @@ declare("iD.renderer.Map", null, {
this._setScaleFactor();
this.updateCoordsFromViewportPosition();
// Cache the margin box, since this is expensive.
this.marginBox = domGeom.getMarginBox(this.div);
// Initialise layers
this.layers={};
for (var l=this.minlayer; l<=this.maxlayer; l++) {
@@ -125,7 +128,7 @@ declare("iD.renderer.Map", null, {
var parent=group.getParent();
if (!parent) { return; }
this._moveChildToPosition(parent,group,position);
if (position==group.rawNode.parentNode.childNodes.length) {
if (position === group.rawNode.parentNode.childNodes.length) {
group.rawNode.parentNode.appendChild(group.rawNode);
} else {
group.rawNode.parentNode.insertBefore(group.rawNode, group.rawNode.parentNode.childNodes[position]);
@@ -278,30 +281,33 @@ declare("iD.renderer.Map", null, {
zoomIn: function() {
// summary: Zoom in by one level (unless maximum reached).
return this.changeScale(this.zoom + 1);
return this.setZoom(this.zoom + 1);
},
zoomOut: function() {
// summary: Zoom out by one level (unless minimum reached).
this.changeScale(this.zoom - 1);
this.setZoom(this.zoom - 1);
this.download();
return this;
},
changeScale: function(zoom) {
setZoom: function(zoom) {
if (zoom < this.MINSCALE || zoom > this.MAXSCALE) return this;
// summary: Redraw the map at a new zoom level.
this.zoom = zoom;
this._setScaleFactor();
this._blankTiles();
this.updateCoordsFromLatLon(this.centrelat, this.centrelon); // recentre
this.setCentre({
lat: this.centrelat,
lon: this.centrelon
});
this.updateUIs(true, true);
return this;
},
_setScaleFactor: function() {
// summary: Calculate the scaling factor for this zoom level.
this.zoomfactor = this.MASTERSCALE/Math.pow(2,13-this.zoom);
this.zoomfactor = this.MASTERSCALE/Math.pow(2, 13 - this.zoom);
},
// ----------------------
@@ -324,36 +330,38 @@ declare("iD.renderer.Map", null, {
});
},
// -------------
// Tile handling
// ** FIXME: see docs
loadTiles: function() {
// summary: Load all tiles for the current viewport. This is a bare-bones function
// at present: it needs configurable URLs (not just Bing), attribution/logo
// support, and to be 'nudgable' (i.e. adjust the offset).
var tile_l = this.lon2tile(this.extent.west);
var tile_r = this.lon2tile(this.extent.east);
var tile_t = this.lat2tile(this.extent.north);
var tile_b = this.lat2tile(this.extent.south);
// -------------
// Tile handling
// ** FIXME: see docs
loadTiles: function() {
// summary: Load all tiles for the current viewport. This is a bare-bones function
// at present: it needs configurable URLs (not just Bing), attribution/logo
// support, and to be 'nudgable' (i.e. adjust the offset).
var tl = this.locationCoord({
lat: this.extent.north,
lon: this.extent.west
}, this.zoom),
br = this.locationCoord({
lat: this.extent.south,
lon: this.extent.east
}, this.zoom),
tileKeys = _.keys(this.tiles),
seen = [],
coord = { z: this.zoom };
var tileKeys = _.keys(this.tiles);
var seen = [];
var coord = { z: this.zoom };
for (coord.x = tile_l; coord.x <= tile_r; coord.x++) {
for (coord.y = tile_t; coord.y <= tile_b; coord.y++) {
if (!this._getTile(coord)) {
for (coord.x = tl.x; coord.x <= br.x; coord.x++) {
for (coord.y = tl.y; coord.y <= br.y; coord.y++) {
if (!this._getTile(coord)) {
this._fetchTile(coord);
}
seen.push(iD.Util.tileKey(coord));
}
}
}
}
_.each(_.without(tileKeys, seen), _.bind(function(key) {
delete this.tiles[key];
}, this));
},
},
_fetchTile: function(coord) {
// summary: Load a tile image at the given tile co-ordinates.
@@ -465,17 +473,22 @@ declare("iD.renderer.Map", null, {
// this.controller.entityMouseEvent(e,null);
},
updateCoordsFromViewportPosition:function(e) {
updateCoordsFromViewportPosition: function(e) {
// summary: Update centre and bbox from the current viewport origin.
this._updateCoords(this.containerx,this.containery);
this._updateCoords(this.containerx, this.containery);
},
updateCoordsFromLatLon:function(lat,lon) {
setCentre: function(loc) {
// summary: Update centre and bbox to a specified lat/lon.
this._updateCoords(-(this.lon2coord(lon)-this.mapwidth/2),
-(this.lat2coord(lat)-this.mapheight/2));
var coord = this.locationCoord(loc, this.zoom);
this._updateCoords(
-coord.x - this.mapwidth / 2,
-coord.y - this.mapheight / 2);
return this;
},
setCenter: function(loc) { this.setCentre(loc); },
_updateCoords:function(x, y) {
// summary: Set centre and bbox.
this.containerx = x;
@@ -507,13 +520,13 @@ declare("iD.renderer.Map", null, {
coord2latp:function(a) { return a/-this.zoomfactor+this.baselatp; },
lon2coord:function(a) { return (a-this.baselon)*this.zoomfactor; },
coord2lon:function(a) { return a/this.zoomfactor+this.baselon; },
lon2screen:function(a) { return this.lon2coord(a) + domGeom.getMarginBox(this.div).l + this.containerx; },
lon2screen:function(a) { return this.lon2coord(a) + this.marginBox.l + this.containerx; },
lat2latp:function(a) { return 180/Math.PI * Math.log(Math.tan(Math.PI/4+a*(Math.PI/180)/2)); },
latp2lat:function(a) { return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2); },
lat2coord:function(a) { return -(this.lat2latp(a)-this.baselatp)*this.zoomfactor; },
coord2lat:function(a) { return this.latp2lat(a/-this.zoomfactor+this.baselatp); },
lat2screen:function(a) { return this.lat2coord(a) + domGeom.getMarginBox(this.div).t + this.containery; },
lat2screen:function(a) { return this.lat2coord(a) + this.marginBox.t + this.containery; },
locationCoord: function(ll, z) {
var z2 = Math.pow(2, z), d2r = Math.PI / 180;
@@ -534,8 +547,8 @@ declare("iD.renderer.Map", null, {
// Turn event co-ordinates into map co-ordinates
mouseX:function(e) { return e.clientX - domGeom.getMarginBox(this.div).l - this.containerx; },
mouseY:function(e) { return e.clientY - domGeom.getMarginBox(this.div).t - this.containery; }
mouseX: function(e) { return e.clientX - this.marginBox.l - this.containerx; },
mouseY: function(e) { return e.clientY - this.marginBox.t - this.containery; }
});
// ----------------------------------------------------------------------

View File

@@ -1,8 +1,8 @@
// iD/renderer/NodeUI.js
// NodeUI classes for iD
define(['dojo/_base/declare','dojo/_base/lang','dojo/_base/array','dojox/gfx/_base','iD/renderer/EntityUI'],
function(declare,lang,array,g){
define(['dojo/_base/declare','dojo/_base/array','dojox/gfx/_base','iD/renderer/EntityUI'],
function(declare,array,g){
// ----------------------------------------------------------------------
// NodeUI class

View File

@@ -7,7 +7,7 @@
// fill images
// opacity
define(['dojo/_base/declare','dojo/_base/lang','iD/renderer/EntityUI'], function(declare,lang){
define(['dojo/_base/declare','iD/renderer/EntityUI'], function(declare) {
// ----------------------------------------------------------------------
// WayUI class
@@ -115,12 +115,13 @@ declare("iD.renderer.WayUI", [iD.renderer.EntityUI], {
color: [0,0,0,0]
}));
var entityMouseEvent = _.bind(this.entityMouseEvent, this);
hit.source=this;
hit.connect("onclick", lang.hitch(this,this.entityMouseEvent));
hit.connect("onmousedown", lang.hitch(this,this.entityMouseEvent));
hit.connect("onmouseup", lang.hitch(this,this.entityMouseEvent));
hit.connect("onmouseenter", lang.hitch(this,this.entityMouseEvent));
hit.connect("onmouseleave", lang.hitch(this,this.entityMouseEvent));
hit.connect("onclick", entityMouseEvent);
hit.connect("onmousedown", entityMouseEvent);
hit.connect("onmouseup", entityMouseEvent);
hit.connect("onmouseenter", entityMouseEvent);
hit.connect("onmouseleave", entityMouseEvent);
}
// Draw nodes
for (i=0; i<way.nodes.length; i++) {