From 2778f76ca447a6ffdf60c721a92c5f1cb8ba606b Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Fri, 19 Oct 2012 12:52:05 -0400 Subject: [PATCH] Many changes * Smaller progress circle * Fixed position edit dialog for now * Remove array dependency in map * Use coord and coord keys --- css/app.css | 24 ++-- index.html | 2 +- js/iD/Util.js | 6 +- js/iD/controller/edit/EditBaseState.js | 7 +- js/iD/renderer/EntityUI.js | 4 +- js/iD/renderer/Map.js | 191 +++++++++++++++---------- js/iD/styleparser/RuleSet.js | 4 +- 7 files changed, 139 insertions(+), 99 deletions(-) diff --git a/css/app.css b/css/app.css index 9632eba42..9b91b9c5b 100644 --- a/css/app.css +++ b/css/app.css @@ -144,13 +144,18 @@ polyline { .edit-pane { position:absolute; display:none; + top:80px; + height:520px; width:300px; background:#fff; - box-shadow:1px 1px 3px #111; - max-height:300px; overflow:auto; } +.edit-pane.active { + display:block; + right:0px; +} + .edit-pane h2 { margin:0; padding:5px 5px 10px 5px; @@ -175,11 +180,11 @@ polyline { .edit-pane a.close { position:absolute; - top:0; + top:5px; right:10px; font-weight:bold; text-decoration:none; - font-size:18px; + font-size:20px; color:#DD4848; } .edit-pane table { @@ -195,7 +200,7 @@ polyline { } .presets h3 { - padding: 5px; + padding: 5px 10px; font: normal 13px/15px Helvetica, Arial, sans-serif; text-align:center; margin: 0; @@ -205,7 +210,7 @@ polyline { text-decoration:none; display:block; background:#eee; - padding:5px; + padding:5px 10px; border-top:1px solid #ccc; } @@ -217,14 +222,13 @@ polyline { #progress { position:absolute; - left:50%; - top:300px; + left:305px; + top:10px; color:#fff; z-index:999; width:100px; - margin-left:-50px; text-align:center; - font-size:100px; + font-size:28px; display:none; font-weight:bold; } diff --git a/index.html b/index.html index 264a14aeb..a296c48d5 100755 --- a/index.html +++ b/index.html @@ -47,7 +47,7 @@ require(["dojo/dom-geometry","dojo/dom-class","dojo/on","dojo/dom","dojo/Evented var map = new iD.renderer.Map({ lat: 51.87, lon: -1.49, - scale: 17, + zoom: 17, div: "map", connection: conn, width: dom.byId('map').offsetWidth, diff --git a/js/iD/Util.js b/js/iD/Util.js index a5a4e20d2..88c221198 100644 --- a/js/iD/Util.js +++ b/js/iD/Util.js @@ -27,8 +27,8 @@ iD.Util.friendlyName = function(entity) { return n.length === 0 ? 'unknown' : n.join('; '); }; +// TODO: don't use a cache here? iD.Util._presets = {}; - iD.Util.presets = function(type, callback) { if (iD.Util._presets[type]) return callback(iD.Util._presets[type]); $.ajax({ @@ -43,3 +43,7 @@ iD.Util.presets = function(type, callback) { } }); }; + +iD.Util.tileKey = function(coord) { + return coord.z + ',' + coord.x + ',' + coord.y; +}; diff --git a/js/iD/controller/edit/EditBaseState.js b/js/iD/controller/edit/EditBaseState.js index 72b9e0680..6102e5195 100644 --- a/js/iD/controller/edit/EditBaseState.js +++ b/js/iD/controller/edit/EditBaseState.js @@ -22,10 +22,7 @@ declare("iD.controller.edit.EditBaseState", [iD.controller.ControllerState], { // y: Number Screen co-ordinate. // entity: iD.Entity The entity to be edited. $('.edit-pane h2').text(iD.Util.friendlyName(entity)); - $('.edit-pane').css({ - left: x, - top: y - }).show(); + $('.edit-pane').show().addClass('active'); $('.edit-pane a.tab').click(function(e) { $('.edit-pane a.tab').removeClass('active'); var hud = $(e.currentTarget).addClass('active') @@ -84,7 +81,7 @@ declare("iD.controller.edit.EditBaseState", [iD.controller.ControllerState], { closeEditorTooltip: function(e) { if (e) e.preventDefault(); // summary: Close the tooltip. - $('.edit-pane').hide(); + $('.edit-pane').removeClass('active').hide(); } }); diff --git a/js/iD/renderer/EntityUI.js b/js/iD/renderer/EntityUI.js index 3de9915f1..90dc250ee 100755 --- a/js/iD/renderer/EntityUI.js +++ b/js/iD/renderer/EntityUI.js @@ -52,8 +52,8 @@ declare("iD.renderer.EntityUI", null, { }, refreshStyleList:function(tags) { // summary: Calculate the list of styles that apply to this UI at this zoom level. - if (!this.styleList || !this.styleList.isValidAt(this.map.scale)) { - this.styleList=this.map.ruleset.getStyles(this.entity,tags,this.map.scale); + if (!this.styleList || !this.styleList.isValidAt(this.map.zoom)) { + this.styleList=this.map.ruleset.getStyles(this.entity,tags, this.map.zoom); } this.layer=this.styleList.layerOverride(); if (isNaN(this.layer)) { diff --git a/js/iD/renderer/Map.js b/js/iD/renderer/Map.js index a8cb4d043..b2c1ebdd6 100755 --- a/js/iD/renderer/Map.js +++ b/js/iD/renderer/Map.js @@ -1,11 +1,11 @@ // iD/renderer/Map.js // at present this combines P2's Map and MapPaint functionality -define(['dojo/_base/declare','dojo/_base/array','dojo/_base/event','dojo/_base/lang', +define(['dojo/_base/declare','dojo/_base/event','dojo/_base/lang', '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, Event, lang, domGeom, Gfx, Matrix){ // ---------------------------------------------------------------------- // Connection base class @@ -15,8 +15,8 @@ declare("iD.renderer.Map", null, { MASTERSCALE: 5825.4222222222, MINSCALE: 14, MAXSCALE: 23, - scale: NaN, - scalefactor: NaN, + zoom: NaN, + zoomfactor: NaN, baselon: NaN, // original longitude at top left of viewport baselat: NaN, // original latitude at top left of viewport baselatp: NaN, // original projected latitude at top left of viewport @@ -31,7 +31,7 @@ declare("iD.renderer.Map", null, { wayuis: {}, // | tilegroup: null, // group within container for adding bitmap tiles - tiles: [], // index of tile objects + tiles: {}, // index of tile objects tilebaseURL: 'http://ecn.t0.tiles.virtualearth.net/tiles/a$quadkey.jpeg?g=587&mkt=en-gb&n=z', // Bing imagery URL dragging: false, // current drag state @@ -68,8 +68,8 @@ declare("iD.renderer.Map", null, { this.mapheight = obj.height ? obj.height : 400; // Initialise variables - this.nodeuis={}, - this.wayuis={}, + this.nodeuis = {}, + this.wayuis = {}, this.div=document.getElementById(obj.div); this.surface=Gfx.createSurface(obj.div, this.mapwidth, this.mapheight); this.backdrop=this.surface.createRect({ @@ -81,7 +81,7 @@ declare("iD.renderer.Map", null, { this.tilegroup = this.surface.createGroup(); this.container = this.surface.createGroup(); this.conn = obj.connection; - this.scale = obj.scale ? obj.scale : 17; + this.zoom = obj.zoom ? obj.zoom : 17; this.baselon = obj.lon; this.baselat = obj.lat; this.baselatp = this.lat2latp(obj.lat); @@ -246,21 +246,26 @@ declare("iD.renderer.Map", null, { }); if (remove !== false) { - array.forEach(o.waysOutside, function(way) { + _.each(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(); } - } else { m.deleteUI(way); } + if (redraw) { + m.wayuis[way.id].recalculate(); + m.wayuis[way.id].redraw(); + } + } else { + m.deleteUI(way); + } }); } - array.forEach(o.poisInside, function(poi) { + _.each(o.poisInside, function(poi) { if (!poi.loaded) return; if (!m.nodeuis[poi.id]) { m.createUI(poi); } else if (redraw) { m.nodeuis[poi.id].redraw(); } }); if (remove !== false) { - array.forEach(o.poisOutside, function(poi) { + _.each(o.poisOutside, function(poi) { if (m.nodeuis[poi.id]) { // && !m.nodeuis[poi.id].purgable if (redraw) { m.nodeuis[poi.id].redraw(); } } else { m.deleteUI(poi); } @@ -273,27 +278,31 @@ declare("iD.renderer.Map", null, { zoomIn: function() { // summary: Zoom in by one level (unless maximum reached). - if (this.scale !== this.MAXSCALE) { this.changeScale(this.scale+1); } + if (this.zoom !== this.MAXSCALE) { + this.changeScale(this.zoom + 1); + } }, zoomOut: function() { // summary: Zoom out by one level (unless minimum reached). - if (this.scale !== this.MINSCALE) { this.changeScale(this.scale-1); } + if (this.zoom !== this.MINSCALE) { + this.changeScale(this.zoom - 1); + } this.download(); }, - changeScale: function(scale) { + changeScale: function(zoom) { // summary: Redraw the map at a new zoom level. - this.scale=scale; + this.zoom = zoom; this._setScaleFactor(); this._blankTiles(); - this.updateCoordsFromLatLon(this.centrelat,this.centrelon); // recentre - this.updateUIs(true,true); + this.updateCoordsFromLatLon(this.centrelat, this.centrelon); // recentre + this.updateUIs(true, true); }, _setScaleFactor: function() { // summary: Calculate the scaling factor for this zoom level. - this.scalefactor=this.MASTERSCALE/Math.pow(2,13-this.scale); + this.zoomfactor = this.MASTERSCALE/Math.pow(2,13-this.zoom); }, // ---------------------- @@ -323,56 +332,67 @@ declare("iD.renderer.Map", null, { // 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); + 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); + 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)) { + this._fetchTile(coord); } + seen.push(iD.Util.tileKey(coord)); } } + + _.each(_.without(tileKeys, seen), _.bind(function(key) { + delete this.tiles[key]; + }, this)); }, - _fetchTile: function(z,x,y) { + _fetchTile: function(coord) { // summary: Load a tile image at the given tile co-ordinates. - var t=this.tilegroup.createImage({ - x: Math.floor(this.lon2coord(this.tile2lon(x))), - y: Math.floor(this.lat2coord(this.tile2lat(y))), - width: 256, height: 256, - src: this._tileURL(z,x,y) + var t = this.tilegroup.createImage({ + x: Math.floor(this.lon2coord(this.tile2lon(coord.x))), + y: Math.floor(this.lat2coord(this.tile2lat(coord.y))), + width: 256, + height: 256, + src: this._tileURL(coord) }); - this._assignTile(z,x,y,t); + this._assignTile(coord, t); }, - _getTile: function(z,x,y) { + _getTile: function(coord) { // summary: See if this tile is already loaded. - var k = z + ',' + x + ',' + y; - return this.tiles[k]; + return this.tiles[iD.Util.tileKey(coord)]; }, - _assignTile: function(z,x,y,t) { + _assignTile: function(coord, t) { // summary: Store a reference to the tile so we know it's loaded. - var k = z + ',' + x + ',' + y; - if (!this.tiles[k]) { - this.tiles[z + ',' + x + ',' + y] = t; - } + this.tiles[iD.Util.tileKey(coord)] = t; }, - _tileURL: function(z,x,y) { + _tileURL: function(coord) { // summary: Calculate the URL for a tile at the given co-ordinates. - var u=''; - for (var zoom=z; zoom>0; zoom--) { - var byte=0; - var mask=1<<(zoom-1); - if ((x & mask) !== 0) byte++; - if ((y & mask) !== 0) byte += 2; - u=u+byte.toString(); + var u = ''; + for (var zoom = coord.z; zoom > 0; zoom--) { + var byte = 0; + var mask = 1 << (zoom - 1); + if ((coord.x & mask) !== 0) byte++; + if ((coord.y & mask) !== 0) byte += 2; + u = u + byte.toString(); } - return this.tilebaseURL.replace('$z',z).replace('$x',x).replace('$y',y).replace('$quadkey',u); + return this.tilebaseURL + .replace('$z', coord.z) + .replace('$x', coord.x) + .replace('$y', coord.y) + .replace('$quadkey', u); }, _blankTiles: function() { @@ -387,14 +407,15 @@ declare("iD.renderer.Map", null, { 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; + var srcElement = (e.gfxTarget === this.backdrop) ? + e.gfxTarget : e.gfxTarget.parent; Event.stop(e); - this.dragging=true; - this.dragged=false; - this.dragx=this.dragy=NaN; - this.startdragx=e.clientX; - this.startdragy=e.clientY; - this.dragconnect=srcElement.connect("onmouseup", lang.hitch(this,"endDrag")); + this.dragging = true; + this.dragged = false; + this.dragx = this.dragy=NaN; + this.startdragx = e.clientX; + this.startdragy = e.clientY; + this.dragconnect = srcElement.connect("onmouseup", _.bind(this.endDrag, this)); }, endDrag: function(e) { @@ -405,7 +426,10 @@ declare("iD.renderer.Map", null, { this.dragging=false; this.dragtime=e.timeStamp; this.updateCoordsFromViewportPosition(); - if (Math.abs(e.clientX-this.startdragx)<3 && Math.abs(e.clientY-this.startdragy)<3) { return; } + if (Math.abs(e.clientX - this.startdragx) < 3 && + Math.abs(e.clientY - this.startdragy) < 3) { + return; + } this.download(); }, @@ -421,8 +445,8 @@ declare("iD.renderer.Map", null, { this.updateOrigin(); this.dragged=true; } - this.dragx=x; - this.dragy=y; + this.dragx = x; + this.dragy = y; } else { this.controller.entityMouseEvent(e,null); } @@ -430,8 +454,8 @@ declare("iD.renderer.Map", null, { 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)]); + this.container.setTransform([Matrix.translate(this.containerx, this.containery)]); + this.tilegroup.setTransform([Matrix.translate(this.containerx, this.containery)]); }, _mouseEvent: function(e) { @@ -455,10 +479,12 @@ declare("iD.renderer.Map", null, { _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.containerx = x; + this.containery = y; + this.updateOrigin(); + this.centrelon = this.coord2lon(-x + this.mapwidth/2); + this.centrelat = this.coord2lat(-y + this.mapheight/2); + this.extent = { north: this.coord2lat(-y), south: this.coord2lat(-y + this.mapheight), @@ -478,23 +504,32 @@ declare("iD.renderer.Map", null, { // ----------------------- // Co-ordinate conversions - latp2coord:function(a) { return -(a-this.baselatp)*this.scalefactor; }, - coord2latp:function(a) { return a/-this.scalefactor+this.baselatp; }, - lon2coord:function(a) { return (a-this.baselon)*this.scalefactor; }, - coord2lon:function(a) { return a/this.scalefactor+this.baselon; }, + latp2coord:function(a) { return -(a-this.baselatp)*this.zoomfactor; }, + 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; }, 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.scalefactor; }, - coord2lat:function(a) { return this.latp2lat(a/-this.scalefactor+this.baselatp); }, + 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; }, - lon2tile:function(a) { return (Math.floor((a+180)/360*Math.pow(2,this.scale))); }, - lat2tile:function(a) { return (Math.floor((1-Math.log(Math.tan(a*Math.PI/180) + 1/Math.cos(a*Math.PI/180))/Math.PI)/2 *Math.pow(2,this.scale))); }, - tile2lon:function(a) { return (a/Math.pow(2,this.scale)*360-180); }, + locationCoord: function(ll, z) { + var z2 = Math.pow(2, z), d2r = Math.PI / 180; + return { + z: z, + x: Math.floor((ll.lon + 180) / 360 * z2), + y: Math.floor((1 - Math.log(Math.tan(ll.lat * d2r) + + 1 / Math.cos(ll.lat * d2r)) / Math.PI) / 2 * z2) + }; + }, + lon2tile:function(a) { return (Math.floor((a+180)/360*Math.pow(2,this.zoom))); }, + lat2tile:function(a) { return (Math.floor((1-Math.log(Math.tan(a*Math.PI/180) + 1/Math.cos(a*Math.PI/180))/Math.PI)/2 *Math.pow(2,this.zoom))); }, + tile2lon:function(a) { return (a/Math.pow(2,this.zoom)*360-180); }, tile2lat:function(a) { - var n=Math.PI-2*Math.PI*a/Math.pow(2,this.scale); + var n=Math.PI-2*Math.PI*a/Math.pow(2,this.zoom); return (180/Math.PI*Math.atan(0.5*(Math.exp(n)-Math.exp(-n)))); }, diff --git a/js/iD/styleparser/RuleSet.js b/js/iD/styleparser/RuleSet.js index c0e540e1a..69cbe16a5 100755 --- a/js/iD/styleparser/RuleSet.js +++ b/js/iD/styleparser/RuleSet.js @@ -209,8 +209,8 @@ declare("iD.styleparser.RuleSet", null, { parseZoom:function(s) { var o={}; if ((o=this.ZOOM_MINMAX.exec(s))) { return [o[1],o[2]]; } - else if ((o=this.ZOOM_MIN.exec(s) )) { return [o[1],maxscale]; } - else if ((o=this.ZOOM_MAX.exec(s) )) { return [minscale,o[1]]; } + else if ((o=this.ZOOM_MIN.exec(s) )) { return [o[1], maxscale]; } + else if ((o=this.ZOOM_MAX.exec(s) )) { return [minscale, o[1]]; } else if ((o=this.ZOOM_SINGLE.exec(s))) { return [o[1],o[1]]; } return null; },