Start UI refactor

This commit is contained in:
Tom MacWright
2012-10-18 12:37:01 -04:00
parent fb3fb4080b
commit 4182cc1240
18 changed files with 286 additions and 316 deletions

View File

@@ -1,6 +1,8 @@
body {
font:normal 13px/20px Helvetica, Arial, sans-serif;
background:#e4e4e4;
margin:0;
text-rendering: optimizeLegibility;
}
:focus {
outline-color: transparent;
@@ -24,6 +26,30 @@ text {
-moz-user-select: none;
}
#map {
height: 600px;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.help-pane {
position:absolute;
left:0;
width:300px;
opacity:0.9;
top:40px;
background:#FFFBD3;
}
.help-pane div {
padding:10px;
font-style:italic;
}
#map.state-drawing {
cursor: pointer;
}
@@ -32,13 +58,41 @@ text {
font-weight: bold;
}
/* Zoom controls */
#modebuttons {
width:300px;
position:absolute;
left:0px;
top:0px;
}
#zoombuttons {
position:absolute;
right:20px;
top:20px;
}
#addPOI {
display:none;
}
#modebuttons button {
width:100px;
cursor:pointer;
background:#fff;
color:#555;
font:bold 19px/35px 'Helvetica Neue';
border:0;
border-right:1px solid #222;
border-bottom:1px solid #222;
padding:0 10px;
height:40px;
margin:0;
}
#modebuttons button:hover {
background:#eee;
}
#zoombuttons button {
cursor:pointer;
width:30px;

View File

@@ -24,7 +24,6 @@
<script>
require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/dom","dojo/Evented",
"dijit/form/Button","dijit/form/ToggleButton",
"dojox/layout/FloatingPane",
"iD/actions/UndoStack",
"iD/actions/CreatePOIAction",
@@ -37,12 +36,12 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
"iD/ui/DragAndDrop","iD/ui/StepPane",
"dojo/domReady!"], function(lang,domGeom,domClass,on,dom,Evented){
var ruleset=new iD.styleparser.RuleSet();
var conn=new iD.Connection("http://www.overpass-api.de/api/xapi?");
var ruleset = new iD.styleparser.RuleSet();
var conn = new iD.Connection("http://www.overpass-api.de/api/xapi?");
// Load styles
ruleset.registerCallback(styleLoaded);
ruleset.loadFromCSS("potlatch.css",styleLoaded);
ruleset.loadFromCSS("potlatch.css", styleLoaded);
// Initialise map
var map = new iD.renderer.Map({
@@ -55,51 +54,35 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
height: dom.byId('map').offsetHeight
});
conn.registerMap(map);
map.ruleset=ruleset;
map.ruleset = ruleset;
// Initialise controller
var controller=new iD.Controller(map);
var controller = new iD.Controller(map);
map.setController(controller);
// Initialise event listeners
controller.on("enterState", enterStateListener);
controller.on("exitState", exitStateListener);
// ----------------------------------------------------
// Data is loaded and app ready to go
function styleLoaded() {
// Initialise drag-and-drop icons
new iD.ui.DragAndDrop("map",map,"dndgrid");
new iD.ui.DragAndDrop("map", map, "dndgrid");
// Initialise help pane
controller.setStepper(new iD.ui.StepPane("helpPane","helpSteps"));
controller.setStepper(new iD.ui.StepPane("helpPane", "helpSteps"));
// Set initial controllerState
controller.setState(new iD.controller.edit.NoSelection());
// Load presets
controller.setTagPresets('way','presets/ways.json');
controller.setTagPresets('node','presets/nodes.json');
// Load presets
controller.setTagPresets('way', 'presets/ways.json');
controller.setTagPresets('node', 'presets/nodes.json');
// Load data
map.download();
}
// ----------------------------------------------------
// State event listeners
function enterStateListener(event) {
domClass.add(event.state[0]+"Button","currentMode");
};
function exitStateListener(event) {
domClass.remove(event.state[0]+"Button","currentMode");
};
// ----------------------------------------------------
// Mode button handlers
/*
enterWayMode=function() {
controller.setState(new iD.controller.shape.NoSelection());
};
@@ -114,6 +97,17 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
cancelClicked=function() {
controller.stepper.hide();
};
*/
$('#add-place').click(function() {
});
$('#add-road').click(function() {
controller.setState(new iD.controller.shape.NoSelection());
});
$('#add-area').click(function() {
controller.setState(new iD.controller.shape.NoSelection());
});
// ----------------------------------------------------
// Map control handlers
@@ -147,58 +141,36 @@ require(["dojo/_base/lang","dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/
});
</script>
</script>
<!-- see http://dojotoolkit.org/documentation/tutorials/1.7/themes_buttons_textboxes/
and http://dojotoolkit.org/widgets -->
<div id="modebuttons" style="position:absolute; left: 10px; top: 10px;">
<div id="addPOI" data-dojo-type="dijit.form.DropDownButton" data-dojo-props="iconClass:'dijitIconApplication', onClick:function(){}">
<span>Add point</span>
<div data-dojo-type="dijit.TooltipDialog">
<p>Drag points onto the map</p>
<table id="dndgrid">
</table>
</div>
</div><script>require(["dijit/form/DropDownButton", "dijit/TooltipDialog","dojo/dnd/Source","dojo/parser", "dojo/domReady!"]);</script>
<button id="shapeButton" data-dojo-type="dijit.form.ToggleButton" data-dojo-props="onClick:enterWayMode">
Add road or shape
</button><script>require(["dijit/form/ToggleButton", "dojo/parser", "dojo/domReady!"]);</script>
<button id="editButton" data-dojo-type="dijit.form.Button" data-dojo-props="onClick:enterEditMode">
Edit object
</button><script>require(["dijit/form/Button", "dojo/parser", "dojo/domReady!"]);</script>
<div id='modebuttons'>
<button id='add-place'>
+ Place</button><button id="add-road">
+ Road</button><button id="add-area">
+ Area</button>
<div id='addPOI'>
<p>Drag points onto the map</p>
<table id='dndgrid'>
</table>
</div>
</div>
<div id="zoombuttons">
<button id="zoomIn">+</button><button id="zoomOut">&ndash;</button>
<button id="zoomIn">+</button><button id="zoomOut">&ndash;</button>
</div>
<!-- Floating help window -->
<div class='help-pane' id='road-help'>
<div>Click on the map to start a road</div>
<div>Draw the road by clicking on points along its path</div>
<div>Choose a road type</div>
</div>
<!-- Map div -->
<div id="map" style="height:600px"
style="-webkit-touch-callout: none; -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none;">
</div>
<div id="map"></div>
<p>Work in progress: <a href='http://www.geowiki.com/'>introduction</a>, <a href='http://github.com/systemed/iD'>code</a>, <a href='http://www.geowiki.com/docs'>docs</a>. Imagery <a href="http://opengeodata.org/microsoft-imagery-details">&copy; 2012</a> Bing, GeoEye, Getmapping, Intermap, Microsoft.</p>
<!-- Floating help window -->
<div id="helpPane" data-dojo-type="dojox.layout.FloatingPane"
data-dojo-props="resizable:true, closable:false, dockable:false, title: 'Step by step'"
style="position:absolute; top:45px; left:50px; width:200px; height:200px; visibility: hidden;" >
<ol id="helpSteps">
</ol>
<button id="finishHelpButton" data-dojo-type="dijit.form.Button" data-dojo-props="onClick:finishClicked">
Finish
</button><script>require(["dijit/form/Button", "dojo/parser", "dojo/domReady!"]);</script>
<button id="cancelHelpButton" data-dojo-type="dijit.form.Button" data-dojo-props="onClick:cancelClicked" style="float:right">
Cancel
</button><script>require(["dijit/form/Button", "dojo/parser", "dojo/domReady!"]);</script>
</div>
</div><!-- applayout -->
</body>
</html>

View File

@@ -143,13 +143,13 @@ iD.Connection.prototype = {
// ----------
// OSM parser
loadFromAPI:function(left,right,top,bottom) {
loadFromAPI: function(box) {
// 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=" + [left,bottom,right,top]);
this.loadFromURL("http://www.overpass-api.de/api/xapi?map?bbox=" + [box.west, box.south, box.east, box.north]);
},
loadFromURL:function(url) {
loadFromURL: function(url) {
// summary: Load all data from a given URL.
$.ajax({
url: url,
@@ -160,17 +160,16 @@ iD.Connection.prototype = {
},
_processOSM:function(dom) {
// var jsdom = $.parseXML(result).childNodes[1];
var nodelist = [];
for (var i in dom.childNodes[0].childNodes) {
var obj=dom.childNodes[0].childNodes[i];
var obj = dom.childNodes[0].childNodes[i];
switch(obj.nodeName) {
case "node":
var node = new iD.Node(this,
+getAttribute(obj,'id'),
+getAttribute(obj,'lat'),
+getAttribute(obj,'lon'),
+getAttribute(obj, 'id'),
+getAttribute(obj, 'lat'),
+getAttribute(obj, 'lon'),
getTags(obj));
this._assign(node);
nodelist.push(node);
@@ -179,7 +178,7 @@ iD.Connection.prototype = {
case "way":
var way = new iD.Way(this,
getAttribute(obj,'id'),
getNodes(obj,this),
getNodes(obj, this),
getTags(obj));
this._assign(way);
break;
@@ -187,7 +186,7 @@ iD.Connection.prototype = {
case "relation":
var relation = new iD.Relation(this,
getAttribute(obj,'id'),
getMembers(obj,this),
getMembers(obj, this),
getTags(obj));
this._assign(relation);
break;
@@ -204,7 +203,7 @@ iD.Connection.prototype = {
};
}
function getAttribute(obj,name) {
function getAttribute(obj, name) {
return _.find(obj.attributes, filterNodeName(name)).nodeValue;
}

View File

@@ -20,7 +20,7 @@ declare("iD.Controller", [Evented], {
this.editorCache = {};
},
setStepper:function(stepper) {
setStepper: function(stepper) {
// summary: Set reference for the singleton-like class for the step-by-step instruction panel.
this.stepper = stepper;
},

View File

@@ -39,11 +39,11 @@ iD.Node.prototype = {
return 180/Math.PI * (2 * Math.atan(Math.exp(a*Math.PI/180)) - Math.PI/2);
},
within: function(left, right, top, bottom) {
return (this.lon >= left) &&
(this.lon <= right) &&
(this.lat >= bottom) &&
(this.lat <= top);
within: function(extent) {
return (this.lon >= extent.west) &&
(this.lon <= extent.east) &&
(this.lat >= extent.south) &&
(this.lat <= extent.north);
},
refresh: function() {

View File

@@ -12,6 +12,7 @@ iD.Way = function(conn, id, nodes, tags, loaded) {
this.loaded = (loaded === undefined) ? true : loaded;
this.modified = this.id < 0;
this.nodes = nodes || [];
this.extent = {};
_.each(nodes, _.bind(function(node) {
node.entity.addParent(this);
}, this));
@@ -49,11 +50,11 @@ iD.Way.prototype = {
// Bounding-box handling
within:function(left,right,top,bottom) {
// TODO invert and just return
if (!this.edgel ||
(this.edgel<left && this.edger<left ) ||
(this.edgel>right && this.edger>right ) ||
(this.edgeb<bottom && this.edget<bottom) ||
(this.edgeb>top && this.edgeb>top )) {
if (!this.extent.west ||
(this.extent.west < left && this.extent.east < left ) ||
(this.extent.west > right && this.extent.east > right ) ||
(this.extent.south < bottom && this.extent.north < bottom) ||
(this.extent.south > top && this.extent.south > top)) {
return false;
} else {
return true;
@@ -61,18 +62,22 @@ iD.Way.prototype = {
},
_calculateBbox:function() {
this.edgel = 999999; this.edger = -999999;
this.edgeb = 999999; this.edget = -999999;
this.extent = {
west: Infinity,
east: -Infinity,
south: Infinity,
north: -Infinity
};
_.each(this.nodes, _.bind(function(n) { this.expandBbox(n); }, this));
},
expandBbox:function(node) {
// summary: Enlarge the way's bounding box to make sure it
// includes the co-ordinates of a supplied node.
this.edgel=Math.min(this.edgel,node.lon);
this.edger=Math.max(this.edger,node.lon);
this.edgeb=Math.min(this.edgeb,node.lat);
this.edget=Math.max(this.edget,node.lat);
this.extent.west = Math.min(this.extent.west, node.lon);
this.extent.east = Math.max(this.extent.east, node.lon);
this.extent.south = Math.min(this.extent.south, node.lat);
this.extent.north = Math.max(this.extent.north, node.lat);
},
// --------------

View File

@@ -28,20 +28,21 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
constructor: function(way) {
this.way = way;
},
enterState: function() {
this.wayUI = this.controller.map.getUI(this.way);
this.wayUI.setStateClass('selected');
this.wayUI.setStateClass('shownodes');
this.wayUI.redraw();
this.controller.stepper.highlight('draw');
},
exitState: function() {
this.controller.map.clearElastic();
this.wayUI.resetStateClass('selected');
this.wayUI.resetStateClass('shownodes');
this.wayUI.redraw();
},
},
enterState: function() {
this.wayUI = this.controller.map.getUI(this.way);
this.wayUI.setStateClass('selected')
.setStateClass('shownodes')
.redraw();
this.controller.stepper.step(1);
},
exitState: function() {
this.controller.map.clearElastic();
this.wayUI
.resetStateClass('selected')
.resetStateClass('shownodes')
.redraw();
},
processMouseEvent:function(event,entityUI) {
var entity=entityUI ? entityUI.entity : null;
@@ -99,12 +100,12 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
// Click on node
if (entity === this.getDrawingNode()) {
// Double-click, so complete drawing
this.controller.stepper.highlight('tag');
this.controller.stepper.step(2);
return new iD.controller.edit.SelectedWay(this.way, null);
} else if (entity === this.getStartNode()) {
// Start of this way, so complete drawing
this.appendNode(entity, this.undoAdder() );
this.controller.stepper.highlight('tag');
this.controller.stepper.step(2);
return new iD.controller.edit.SelectedWay(this.way, null);
} else {
// Add to way
@@ -147,11 +148,11 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
},
getDrawingNode:function() {
return (this.editEnd ? this.way.nodes[this.way.length()-1] : this.way.nodes[0]);
return (this.editEnd ? this.way.nodes[this.way.nodes.length - 1] : this.way.nodes[0]);
},
getStartNode:function() {
return (this.editEnd ? this.way.nodes[0] : this.way.nodes[this.way.length()-1]);
return (this.editEnd ? this.way.nodes[0] : this.way.nodes[this.way.node.length - 1]);
},
appendNode:function(node, performAction) {
@@ -168,7 +169,6 @@ declare("iD.controller.shape.DrawWay", [iD.controller.ControllerState], {
this.appendNode(node, lang.hitch(undo,undo.push));
return node;
}
});
// ----------------------------------------------------------------------

View File

@@ -36,11 +36,7 @@ declare("iD.controller.shape.NoSelection", [iD.controller.ControllerState], {
enterState: function() {
this.controller.map.div.className = 'state-drawing';
this.controller.stepper.setSteps({
begin: "Click anywhere on the map to start drawing",
draw: "Keep clicking to add each point then double-click when you're done",
tag: "Set the type of the road or shape"
}, ['begin', 'draw', 'tag']).highlight('begin');
this.controller.stepper.show().step(0);
},
processMouseEvent:function(event,entityUI) {
@@ -53,9 +49,9 @@ declare("iD.controller.shape.NoSelection", [iD.controller.ControllerState], {
case 'node':
// Click to select a node
var ways=entity.parentWays();
if (ways.length==0) { return new iD.controller.shape.SelectedPOINode(entity); }
// else { return new iD.controller.shape.SelectedWayNode(entity,ways[0]); }
// ** FIXME: ^^^ the above should start a new branching way, not select the node
if (!ways.length) { return new iD.controller.shape.SelectedPOINode(entity); }
// else { return new iD.controller.shape.SelectedWayNode(entity,ways[0]); }
// ** FIXME: ^^^ the above should start a new branching way, not select the node
return this;
case 'way':
// Click to select a way

View File

@@ -5,7 +5,7 @@ define(['dojo/_base/declare','dojo/_base/array','dojo/_base/event','dojo/_base/l
'dojo/dom-geometry',
'dojox/gfx','dojox/gfx/matrix',
'iD/Connection','iD/Entity','iD/renderer/EntityUI','iD/renderer/WayUI','iD/renderer/NodeUI'],
function(declare,array,Event,lang,domGeom,Gfx,Matrix){
function(declare, array, Event, lang, domGeom, Gfx, Matrix){
// ----------------------------------------------------------------------
// Connection base class
@@ -47,10 +47,7 @@ declare("iD.renderer.Map", null, {
containery: 0, // |
centrelat: NaN, // lat/long and bounding box of map
centrelon: NaN, // |
edgel: NaN, // |
edger: NaN, // |
edget: NaN, // |
edgeb: NaN, // |
extent: {}, // |
mapheight: NaN, // size of map object in pixels
mapwidth: NaN, // |
@@ -109,22 +106,22 @@ declare("iD.renderer.Map", null, {
this.elastic = this.container.createGroup();
// Make draggable
this.backdrop.connect("onmousedown", lang.hitch(this,"startDrag"));
this.tilegroup.connect("onmousedown", lang.hitch(this,"startDrag"));
this.surface.connect("onclick", lang.hitch(this,"clickSurface"));
this.surface.connect("onmousemove", lang.hitch(this,"processMove"));
this.surface.connect("onmousedown", lang.hitch(this,"_mouseEvent"));
this.surface.connect("onmouseup", lang.hitch(this,"_mouseEvent"));
this.backdrop.connect("onmousedown", _.bind(this.startDrag, this));
this.tilegroup.connect("onmousedown", _.bind(this.startDrag, this));
this.surface.connect("onclick", _.bind(this.clickSurface, this));
this.surface.connect("onmousemove", _.bind(this.processMove, this));
this.surface.connect("onmousedown", _.bind(this._mouseEvent, this));
this.surface.connect("onmouseup", _.bind(this._mouseEvent, this));
},
setController:function(controller) {
// summary: Set the controller that will handle events on the map (e.g. mouse clicks).
this.controller=controller;
this.controller = controller;
},
_moveToPosition:function(group,position) {
_moveToPosition:function(group, position) {
// summary: Supplementary method for dojox.gfx.
// This should ideally be core Dojo stuff: see http://bugs.dojotoolkit.org/ticket/15296
// This should ideally be core Dojo stuff: see http://bugs.dojotoolkit.org/ticket/15296
var parent=group.getParent();
if (!parent) { return; }
this._moveChildToPosition(parent,group,position);
@@ -135,9 +132,9 @@ declare("iD.renderer.Map", null, {
}
},
_moveChildToPosition: function(parent,child,position) {
for(var i = 0; i < parent.children.length; ++i){
if(parent.children[i] == child){
_moveChildToPosition: function(parent, child, position) {
for (var i = 0; i < parent.children.length; ++i){
if (parent.children[i] === child){
parent.children.splice(i, 1);
parent.children.splice(position, 0, child);
break;
@@ -150,7 +147,7 @@ declare("iD.renderer.Map", null, {
sublayer:function(layer,groupType,sublayer) {
// summary: Find the gfx.Group for a given OSM layer and rendering sublayer, creating it
// if necessary. Note that sublayers are only implemented for stroke and fill.
// if necessary. Note that sublayers are only implemented for stroke and fill.
// groupType: String 'casing','text','hit','stroke', or 'fill'
var collection=this.layers[layer][groupType], sub;
switch (groupType) {
@@ -165,7 +162,7 @@ declare("iD.renderer.Map", null, {
sub=collection.children[i];
if (sub.sublayer==sublayer) { return sub; }
else if (sub.sublayer>sublayer) {
sub=collection.createGroup();
sub = collection.createGroup();
this._moveToPosition(sub,i);
sub.sublayer=sublayer;
return sub;
@@ -208,7 +205,7 @@ declare("iD.renderer.Map", null, {
},
refreshUI:function(entity) {
// summary: Redraw the UI for an entity.
// summary: Redraw the UI for an entity.
switch (entity.entityType) {
case 'node': if (this.nodeuis[entity.id]) { this.nodeuis[entity.id].redraw(); } break;
case 'way': if (this.wayuis[entity.id] ) { this.wayuis[entity.id].redraw(); } break;
@@ -218,14 +215,14 @@ declare("iD.renderer.Map", null, {
deleteUI:function(entity) {
// summary: Delete the UI for an entity.
switch (entity.entityType) {
case 'node':if (this.nodeuis[entity.id]) { this.nodeuis[entity.id].removeSprites(); delete this.nodeuis[entity.id]; } break;
case 'node': if (this.nodeuis[entity.id]) { this.nodeuis[entity.id].removeSprites(); delete this.nodeuis[entity.id]; } break;
case 'way': if (this.wayuis[entity.id] ) { this.wayuis[entity.id].removeSprites(); delete this.wayuis[entity.id]; } break;
}
},
download:function() {
// summary: Ask the connection to download data for the current viewport.
this.conn.loadFromAPI(this.edgel, this.edger, this.edget, this.edgeb);
this.conn.loadFromAPI(this.extent);
},
updateUIs:function(redraw,remove) {
@@ -235,7 +232,7 @@ declare("iD.renderer.Map", null, {
var m = this;
var way, poi;
var o = this.conn.getObjectsByBbox(this.edgel,this.edger,this.edget,this.edgeb);
var o = this.conn.getObjectsByBbox(this.extent);
_(o.waysInside).chain()
.filter(function(w) { return w.loaded; })
@@ -270,18 +267,18 @@ declare("iD.renderer.Map", null, {
// -------------
// Zoom handling
zoomIn:function() {
zoomIn: function() {
// summary: Zoom in by one level (unless maximum reached).
if (this.scale!=this.MAXSCALE) { this.changeScale(this.scale+1); }
if (this.scale !== this.MAXSCALE) { this.changeScale(this.scale+1); }
},
zoomOut:function() {
zoomOut: function() {
// summary: Zoom out by one level (unless minimum reached).
if (this.scale!=this.MINSCALE) { this.changeScale(this.scale-1); }
if (this.scale !== this.MINSCALE) { this.changeScale(this.scale-1); }
this.download();
},
changeScale:function(scale) {
changeScale: function(scale) {
// summary: Redraw the map at a new zoom level.
this.scale=scale;
this._setScaleFactor();
@@ -290,7 +287,7 @@ declare("iD.renderer.Map", null, {
this.updateUIs(true,true);
},
_setScaleFactor:function() {
_setScaleFactor: function() {
// summary: Calculate the scaling factor for this zoom level.
this.scalefactor=this.MASTERSCALE/Math.pow(2,13-this.scale);
},
@@ -298,42 +295,45 @@ declare("iD.renderer.Map", null, {
// ----------------------
// Elastic band redrawing
clearElastic:function() {
clearElastic: function() {
// summary: Remove the elastic band used to draw new ways.
this.elastic.clear();
},
drawElastic:function(x1,y1,x2,y2) {
drawElastic: function(x1,y1,x2,y2) {
// summary: Draw the elastic band (for new ways) between two points.
this.elastic.clear();
// **** Next line is SVG-specific
this.elastic.rawNode.setAttribute("pointer-events","none");
this.elastic.createPolyline( [{ x:x1, y:y1 }, { x:x2, y:y2 }] ).setStroke( {
color: [0,0,0,1],
color: [0, 0, 0, 1],
style: 'Solid',
width: 1 });
width: 1
});
},
// -------------
// Tile handling
// ** FIXME: see docs
loadTiles:function() {
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.edgel);
var tile_r=this.lon2tile(this.edger);
var tile_t=this.lat2tile(this.edget);
var tile_b=this.lat2tile(this.edgeb);
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);
for (var x=tile_l; x<=tile_r; x++) {
for (var y=tile_t; y<=tile_b; y++) {
if (!this._getTile(this.scale,x,y)) { this._fetchTile(this.scale,x,y); }
if (!this._getTile(this.scale,x,y)) {
this._fetchTile(this.scale,x,y);
}
}
}
},
_fetchTile:function(z,x,y) {
_fetchTile: function(z,x,y) {
// summary: Load a tile image at the given tile co-ordinates.
var t=this.tilegroup.createImage({
x: Math.floor(this.lon2coord(this.tile2lon(x))),
@@ -344,13 +344,13 @@ declare("iD.renderer.Map", null, {
this._assignTile(z,x,y,t);
},
_getTile:function(z,x,y) {
_getTile: function(z,x,y) {
// summary: See if this tile is already loaded.
var k = z + ',' + x + ',' + y;
return this.tiles[k];
},
_assignTile:function(z,x,y,t) {
_assignTile: function(z,x,y,t) {
// summary: Store a reference to the tile so we know it's loaded.
var k = z + ',' + x + ',' + y;
if (!this.tiles[k]) {
@@ -358,7 +358,7 @@ declare("iD.renderer.Map", null, {
}
},
_tileURL:function(z,x,y) {
_tileURL: function(z,x,y) {
// summary: Calculate the URL for a tile at the given co-ordinates.
var u='';
for (var zoom=z; zoom>0; zoom--) {
@@ -371,7 +371,7 @@ declare("iD.renderer.Map", null, {
return this.tilebaseURL.replace('$z',z).replace('$x',x).replace('$y',y).replace('$quadkey',u);
},
_blankTiles:function() {
_blankTiles: function() {
// summary: Unload all tiles and remove from the display.
this.tilegroup.clear();
this.tiles = {};
@@ -380,7 +380,7 @@ declare("iD.renderer.Map", null, {
// -------------------------------------------
// Co-ordinate management, dragging and redraw
startDrag:function(e) {
startDrag: function(e) {
// summary: Start dragging the map in response to a mouse-down.
// e: MouseEvent The mouse-down event that triggered it.
var srcElement = (e.gfxTarget==this.backdrop) ? e.gfxTarget : e.gfxTarget.parent;
@@ -393,7 +393,7 @@ declare("iD.renderer.Map", null, {
this.dragconnect=srcElement.connect("onmouseup", lang.hitch(this,"endDrag"));
},
endDrag:function(e) {
endDrag: function(e) {
// summary: Stop dragging the map in response to a mouse-up.
// e: MouseEvent The mouse-up event that triggered it.
Event.stop(e);
@@ -405,7 +405,7 @@ declare("iD.renderer.Map", null, {
this.download();
},
processMove:function(e) {
processMove: function(e) {
// summary: Drag the map to a new origin.
// e: MouseEvent The mouse-move event that triggered it.
var x = e.clientX;
@@ -424,13 +424,13 @@ declare("iD.renderer.Map", null, {
}
},
updateOrigin:function() {
updateOrigin: function() {
// summary: Tell Dojo to update the viewport origin.
this.container.setTransform([Matrix.translate(this.containerx,this.containery)]);
this.tilegroup.setTransform([Matrix.translate(this.containerx,this.containery)]);
},
_mouseEvent:function(e) {
_mouseEvent: function(e) {
// summary: Catch mouse events on the surface but not the tiles - in other words,
// on drawn items that don't have their own hitzones, like the fill of a shape.
if (e.type=='mousedown') { this.startDrag(e); }
@@ -449,15 +449,19 @@ declare("iD.renderer.Map", null, {
-(this.lat2coord(lat)-this.mapheight/2));
},
_updateCoords:function(x,y) {
_updateCoords:function(x, y) {
// summary: Set centre and bbox.
this.containerx=x; this.containery=y; this.updateOrigin();
this.centrelon=this.coord2lon(-x + this.mapwidth/2);
this.centrelat=this.coord2lat(-y + this.mapheight/2);
this.edget=this.coord2lat(-y);
this.edgeb=this.coord2lat(-y + this.mapheight);
this.edgel=this.coord2lon(-x);
this.edger=this.coord2lon(-x + this.mapwidth);
this.extent = {
north: this.coord2lat(-y),
south: this.coord2lat(-y + this.mapheight),
west: this.coord2lon(-x),
east: this.coord2lon(-x + this.mapwidth)
};
this.loadTiles();
},

View File

@@ -131,6 +131,8 @@ declare("iD.renderer.WayUI", [iD.renderer.EntityUI], {
if (node.entity.parentWays().length>1) { sc.push('junction'); }
this.map.createUI(node,sc);
}
return this;
},
entityMouseEvent:function(event) {

View File

@@ -19,28 +19,27 @@ declare("iD.styleparser.Condition", null, {
// summary: Run the condition against the supplied tags.
var p=this.params;
switch (this.type) {
case 'eq': return (tags[p[0]]==p[1]); break;
case 'ne': return (tags[p[0]]!=p[1]); break;
case 'eq': return (tags[p[0]]==p[1]);
case 'ne': return (tags[p[0]]!=p[1]);
case 'regex': var r=new RegExp(p[1],"i");
return (r.test(tags[p[0]])); break;
case 'true': return (tags[p[0]]=='true' || tags[p[0]]=='yes' || tags[p[0]]=='1'); break;
case 'false': return (tags[p[0]]=='false' || tags[p[0]]=='no' || tags[p[0]]=='0'); break;
case 'set': return (tags[p[0]]!=undefined && tags[p[0]]!=''); break;
case 'unset': return (tags[p[0]]==undefined || tags[p[0]]==''); break;
case '<': return (Number(tags[p[0]])< Number(p[1])); break;
case '<=': return (Number(tags[p[0]])<=Number(p[1])); break;
case '>': return (Number(tags[p[0]])> Number(p[1])); break;
case '>=': return (Number(tags[p[0]])>=Number(p[1])); break;
return (r.test(tags[p[0]]));
case 'true': return (tags[p[0]]=='true' || tags[p[0]]=='yes' || tags[p[0]]=='1');
case 'false': return (tags[p[0]]=='false' || tags[p[0]]=='no' || tags[p[0]]=='0');
case 'set': return (tags[p[0]] !== undefined && tags[p[0]]!=='');
case 'unset': return (tags[p[0]] === undefined || tags[p[0]]==='');
case '<': return (Number(tags[p[0]])< Number(p[1]));
case '<=': return (Number(tags[p[0]])<=Number(p[1]));
case '>': return (Number(tags[p[0]])> Number(p[1]));
case '>=': return (Number(tags[p[0]])>=Number(p[1]));
}
return false;
},
toString:function() {
return "["+this.type+": "+this.params+"]";
},
}
});
// ----------------------------------------------------------------------
// End of module
});
});

View File

@@ -13,7 +13,7 @@ declare("iD.styleparser.Rule", null, {
maxZoom: 255, // maximum zoom level at which the Rule is fulfilled
subject: '', // entity type to which the Rule applies: 'way', 'node', 'relation', 'area' (closed way) or 'line' (unclosed way)
constructor:function(_subject) {
constructor: function(_subject) {
// summary: A MapCSS selector. Contains a list of Conditions; the entity type to which the selector applies;
// and the zoom levels at which it is true. way[waterway=river][boat=yes] would be parsed into one Rule.
// The selectors and declaration together form a StyleChooser.
@@ -21,12 +21,12 @@ declare("iD.styleparser.Rule", null, {
this.conditions=[];
},
addCondition:function(_condition) {
addCondition: function(_condition) {
// summary: Add a condition to this rule.
this.conditions.push(_condition);
},
test:function(entity,tags,zoom) {
test: function(entity,tags,zoom) {
// summary: Evaluate the Rule on the given entity, tags and zoom level.
// returns: true if the Rule passes, false if the conditions aren't fulfilled.
if ((this.subject !== '') && (entity.entityType !== this.subject)) {

View File

@@ -48,8 +48,8 @@ declare("iD.styleparser.RuleChain", null, {
return this.rules.length;
},
setSubpart:function(_subpart) {
this.subpart = _subpart=='' ? 'default' : _subpart;
setSubpart:function(subpart) {
this.subpart = subpart || 'default';
},
// Test a ruleChain
@@ -60,7 +60,7 @@ declare("iD.styleparser.RuleChain", null, {
// - if they succeed, and it's the last in the chain, return happily
// - if they succeed, and there's more in the chain, rerun this for each parent until success
test:function(pos, entity, tags, zoom) {
test: function(pos, entity, tags, zoom) {
// summary: Test a rule chain by running all the tests in reverse order.
if (this.rules.length === 0) { return false; }
if (pos==-1) { pos=this.rules.length-1; }
@@ -76,7 +76,6 @@ declare("iD.styleparser.RuleChain", null, {
}
return false;
}
});
// ----------------------------------------------------------------------

View File

@@ -238,12 +238,12 @@ declare("iD.styleparser.RuleSet", null, {
} else {
var match = this.HEX.exec(colorStr);
if ( match ) {
if ( match[1].length == 3) {
// repeat digits. #abc => 0xaabbcc
return Number("0x"+match[1].charAt(0)+match[1].charAt(0)+
match[1].charAt(1)+match[1].charAt(1)+
match[1].charAt(2)+match[1].charAt(2));
} else if ( match[1].length == 6) {
if ( match[1].length == 3) {
// repeat digits. #abc => 0xaabbcc
return Number("0x"+match[1].charAt(0)+match[1].charAt(0)+
match[1].charAt(1)+match[1].charAt(1)+
match[1].charAt(2)+match[1].charAt(2));
} else if ( match[1].length == 6) {
return Number("0x"+match[1]);
} else {
return Number("0x000000"); //as good as any

View File

@@ -15,16 +15,16 @@ declare("iD.styleparser.Style", null, {
styleType: 'Style',
evals: null,
constructor: function(){
constructor: function() {
// summary: Base class for a set of painting attributes, into which the CSS declaration is parsed.
this.evals={};
this.evals = {};
},
drawn: function(){
drawn: function() {
return false;
},
has: function(k){
has: function(k) {
return this.properties.indexOf(k)>-1;
},
@@ -46,7 +46,7 @@ declare("iD.styleparser.Style", null, {
} else if (typeof(this[k])=='number') {
v=Number(v);
} else if (this[k] && this[k].constructor==Array) {
v=v.split(',').map(function(a) { return Number(a); });
v = v.split(',').map(function(a) { return Number(a); });
}
this[k]=v;
return true;
@@ -66,12 +66,12 @@ declare("iD.styleparser.Style", null, {
},
toString: function() {
var str='';
var str = '';
for (var k in this.properties) {
if (this.hasOwnProperty(k)) { str+=k+"="+this[k]+"; "; }
}
return str;
},
}
});
@@ -79,14 +79,14 @@ declare("iD.styleparser.Style", null, {
// InstructionStyle class
declare("iD.styleparser.InstructionStyle", [iD.styleparser.Style], {
set_tags:null,
breaker:false,
set_tags: null,
breaker: false,
styleType: 'InstructionStyle',
addSetTag:function(k,v) {
addSetTag: function(k,v) {
this.edited=true;
if (!this.set_tags) this.set_tags={};
this.set_tags[k]=v;
},
}
});
// ----------------------------------------------------------------------
@@ -100,19 +100,19 @@ declare("iD.styleparser.PointStyle", [iD.styleparser.Style], {
rotation: NaN,
styleType: 'PointStyle',
drawn:function() {
return (this.icon_image!=null);
return (this.icon_image !== null);
},
maxwidth:function() {
return this.evals['icon_width'] ? 0 : this.icon_width;
},
return this.evals.icon_width ? 0 : this.icon_width;
}
});
// ----------------------------------------------------------------------
// ShapeStyle class
declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], {
properties: ['width','color','opacity','dashes','linecap','linejoin','line_style',
'fill_image','fill_color','fill_opacity','casing_width','casing_color','casing_opacity','casing_dashes','layer'],
properties: ['width','color','opacity','dashes','linecap','linejoin','line_style',
'fill_image','fill_color','fill_opacity','casing_width','casing_color','casing_opacity','casing_dashes','layer'],
width:0, color:NaN, opacity:NaN, dashes:[],
linecap:null, linejoin:null, line_style:null,
@@ -127,7 +127,7 @@ declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], {
},
maxwidth:function() {
// If width is set by an eval, then we can't use it to calculate maxwidth, or it'll just grow on each invocation...
if (this.evals['width'] || this.evals['casing_width']) { return 0; }
if (this.evals.width || this.evals.casing_width) { return 0; }
return (this.width + (this.casing_width ? this.casing_width*2 : 0));
},
strokeStyler:function() {
@@ -167,7 +167,7 @@ declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], {
cap: cap,
join: join
};
},
}
});
// ----------------------------------------------------------------------
@@ -175,13 +175,13 @@ declare("iD.styleparser.ShapeStyle", [iD.styleparser.Style], {
declare("iD.styleparser.TextStyle", [iD.styleparser.Style], {
properties: ['font_family','font_bold','font_italic','font_caps','font_underline','font_size',
'text_color','text_offset','max_width',
'text','text_halo_color','text_halo_radius','text_center',
'letter_spacing'],
properties: ['font_family','font_bold','font_italic','font_caps','font_underline','font_size',
'text_color','text_offset','max_width',
'text','text_halo_color','text_halo_radius','text_center',
'letter_spacing'],
font_family: null,
font_bold: false,
font_family: null,
font_bold: false,
font_italic: false,
font_underline: false,
font_caps: false,
@@ -197,7 +197,7 @@ declare("iD.styleparser.TextStyle", [iD.styleparser.Style], {
styleType: 'TextStyle',
drawn: function() {
return (this.text!=null);
return (this.text !== null);
},
fontStyler:function() {
return {
@@ -218,7 +218,6 @@ declare("iD.styleparser.TextStyle", [iD.styleparser.Style], {
// not implemented yet
return this.dojoColor(0,1);
}
// getTextFormat, getHaloFilter, writeNameLabel
});
@@ -232,8 +231,8 @@ declare("iD.styleparser.ShieldStyle", [iD.styleparser.Style], {
shield_height: NaN,
styleType: 'ShieldStyle',
drawn:function() {
return (shield_image!=null);
},
return (shield_image !== null);
}
});
// ----------------------------------------------------------------------

View File

@@ -64,7 +64,7 @@ declare("iD.styleparser.StyleChooser", null, {
break;
}
if (r.drawn) { tags[':drawn']='yes'; }
tags['_width']=sl.maxwidth;
tags._width = sl.maxwidth;
r.runEvals(tags);
if (a[c.subpart]) {
@@ -79,8 +79,7 @@ declare("iD.styleparser.StyleChooser", null, {
}
}
}
},
}
});
// ----------------------------------------------------------------------

View File

@@ -17,10 +17,10 @@ declare("iD.styleparser.StyleList", null, {
validAt: -1, // Zoom level this is valid at (or -1 at all levels - saves recomputing)
constructor:function() {
// summary: A StyleList object is the full list of all styles applied to
// a drawn entity (i.e. node/way). Each array element applies to that
// sublayer (z-index). If there is no element, nothing is drawn on that sublayer.
// StyleLists are created by StyleChooser.getStyles.
// summary: A StyleList object is the full list of all styles applied to
// a drawn entity (i.e. node/way). Each array element applies to that
// sublayer (z-index). If there is no element, nothing is drawn on that sublayer.
// StyleLists are created by StyleChooser.getStyles.
this.shapeStyles={};
this.textStyles={};
this.pointStyles={};
@@ -30,7 +30,7 @@ declare("iD.styleparser.StyleList", null, {
hasStyles:function() {
// summary: Does this StyleList contain any styles?
return ( this.hasShapeStyles() || this.hasTextStyles() || this.hasPointStyles() || this.hasShieldStyles() );
return (this.hasShapeStyles() || this.hasTextStyles() || this.hasPointStyles() || this.hasShieldStyles());
},
hasFills:function() {
@@ -61,7 +61,7 @@ declare("iD.styleparser.StyleList", null, {
toString:function() {
// summary: Summarise StyleList as String - for debugging
var str='';
var str = '';
var k;
for (k in this.shapeStyles ) { str+="- SS "+k+"="+this.shapeStyles[k]+"\n"; }
for (k in this.textStyles ) { str+="- TS "+k+"="+this.textStyles[k]+"\n"; }

View File

@@ -11,90 +11,32 @@ define(['dojo/_base/declare','dojo/_base/lang'], function(declare,lang){
declare("iD.ui.StepPane", null, {
divname: null,
stepsname: null, // we probably don't want to have this
currentStep: 0,
order: null,
constructor:function(_divname,_stepsdivname) {
// summary: Populates and creates the 'Step by step' how-to panel.
// This is a bit messy at present - it shouldn't take stepsname or similar, it should just
// create the pane programmatically. We should also be able to set the title of the pane.
this.divname=_divname;
this.stepsname=_stepsdivname;
this.order=[];
constructor:function() {
},
stepsDiv:function() {
// summary: Getter for the <div> containing the steps.
return document.getElementById(this.stepsname);
},
stepsNodes:function() {
// summary: Getter for the nodes of the <div> containing the steps.
return this.stepsDiv().childNodes;
},
// ----------------
// Add/remove steps
addStep:function(name,text) {
// summary: Add a step to the end of the list.
// name: String A reference to this step (for example, 'start').
// text: String The text of the step.
this.order.push(name);
this.stepsDiv().appendChild(document.createElement('li')).innerHTML=text;
},
insertStep:function(pos,name,text) {
// summary: Insert a step at a position within the list.
// pos: Number The index at which to insert the step.
// name: String A reference to this step (for example, 'start').
// text: String The text of the step.
this.order.splice(pos,0,name);
this.stepsNodes()[pos+1].insertBefore(document.createElement('li')).innerHTML=text;
},
setSteps:function(steps,order) {
// summary: Set the entire list of steps.
// steps: Object A hash of each step, keyed by reference name. For example: { start: 'Click to begin', ... }
// order: String An array of the step names, in the desired order. For example: ['start','add','finish']
this.clear();
for (var i=0; i<order.length; i++) {
this.addStep(order[i], steps[order[i]]);
}
return this;
},
clear:function() {
// summary: Remove all steps.
for (var i=this.stepsNodes().length-1; i>=1; i--) {
this.stepsDiv().removeChild(this.stepsNodes()[i]);
}
this.order=[];
},
// ---------------------------
// Change the highlighted step
highlight:function(stepname) {
step: function(x) {
// summary: Highlight the step with the specified name, and dim all others.
this.show();
this.currentStep=stepname;
for (var i=1; i<this.stepsNodes().length; i++) {
this.stepsNodes()[i].style.color = this.order[i-1]==stepname ? 'black' : 'lightgray';
}
$('#road-help div').eq(x).show();
return this;
},
// ----------------
// Show/hide window
show:function() {
show: function() {
// summary: Show the window.
if(dijit.byId(this.divname).domNode.style.visibility == 'hidden')
dijit.byId(this.divname).show();
$('#road-help').show();
$('#road-help div').hide();
return this;
},
hide:function() {
// summary: Hide the window.
dijit.byId(this.divname).hide();
hide: function() {
$('#road-help').hide();
$('#road-help div').hide();
return this;
}
});
// ----------------------------------------------------------------------