/** don't zoom in past this */
public const MAXSCALE:uint=23;
- /** sprite for ways and (POI/tagged) nodes in core layer */
- public var paint:MapPaint;
- /** sprite for vector background layers */
- public var vectorbg:Sprite;
+ // Container for MapPaint objects
+ private var paintContainer:Sprite;
/** map scale */
public var scale:uint=14;
/** current scaling factor for lon/latp */
public var scalefactor:Number=MASTERSCALE;
- public var bigedge_l:Number= 999999; // area of largest whichways
- public var bigedge_r:Number=-999999; // |
- public var bigedge_b:Number= 999999; // |
- public var bigedge_t:Number=-999999; // |
public var edge_l:Number; // current bounding box
public var edge_r:Number; // |
public const NOT_DRAGGING:uint=0; // |
public const NOT_MOVED:uint=1; // |
public const DRAGGING:uint=2; // |
+ public const SWALLOW_MOUSEUP:uint=3; // |
/** How far the map can be dragged without actually triggering a pan. */
public const TOLERANCE:uint=7; // |
- /** object containing HTML page parameters */
+ /** object containing HTML page parameters: lat, lon, zoom, background_dim, background_sharpen, tileblocks */
public var initparams:Object;
/** reference to backdrop sprite */
public var backdrop:Object;
/** background tile object */
public var tileset:TileSet;
- /** background tile URL, name and scheme */
- private var tileparams:Object={ url:'' };
- /** internal style URL */
- private var styleurl:String='';
/** show all objects, even if unstyled? */
public var showall:Boolean=true;
- /** server connection */
- public var connection:Connection;
- /** VectorLayer objects */
- public var vectorlayers:Object={};
-
- /** Should the position of mouse cursor be shown to the user? */
- private var showingLatLon:Boolean=false;
-
// ------------------------------------------------------------------------------------------
/** Map constructor function */
- public function Map(initparams:Object) {
+ public function Map() {
+ // Remove any existing sprites
+ while (numChildren) { removeChildAt(0); }
- this.initparams=initparams;
- connection = Connection.getConnection(initparams);
- connection.addEventListener(Connection.NEW_WAY, newWayCreated);
- connection.addEventListener(Connection.NEW_POI, newPOICreated);
- connection.addEventListener(Connection.WAY_RENUMBERED, wayRenumbered);
- connection.addEventListener(Connection.NODE_RENUMBERED, nodeRenumbered);
- gotEnvironment(null);
+ // 900913 background
+ tileset=new TileSet(this);
+ addChild(tileset);
+
+ // Container for all MapPaint objects
+ paintContainer = new Sprite();
+ addChild(paintContainer);
addEventListener(Event.ENTER_FRAME, everyFrame);
scrollRect=new Rectangle(0,0,800,600);
- }
- public function gotEnvironment(r:Object):void {
- var loader:Loader = new Loader();
- loader.contentLoaderInfo.addEventListener(Event.COMPLETE, gotFont);
- loader.load(new URLRequest("FontLibrary.swf"));
- }
-
- public function gotFont(r:Event):void {
- var FontLibrary:Class = r.target.applicationDomain.getDefinition("FontLibrary") as Class;
- Font.registerFont(FontLibrary.DejaVu);
-
- if (initparams['lat'] != null) {
- // parameters sent from HTML
- init(initparams['lat'],
- initparams['lon'],
- initparams['zoom']);
-
- } else {
- // somewhere innocuous
- init(53.09465,-2.56495,17);
+ if (ExternalInterface.available) {
+ ExternalInterface.addCallback("setPosition", function (lat:Number,lon:Number,zoom:uint):void {
+ updateCoordsFromLatLon(lat, lon);
+ changeScale(zoom);
+ });
}
}
// ------------------------------------------------------------------------------------------
/** Initialise map at a given lat/lon */
public function init(startlat:Number, startlon:Number, startscale:uint=0):void {
- while (numChildren) { removeChildAt(0); }
-
- tileset=new TileSet(this); // 0 - 900913 background
- if (initparams['tileblocks']) { // | option to block dodgy tile sources
- tileset.blocks=initparams['tileblocks'];// |
- } // |
- addChild(tileset); // |
- tileset.init(tileparams, false,
- initparams['background_dim'] ==null ? true : initparams['background_dim'],
- initparams['background_sharpen']==null ? false : initparams['background_sharpen']);
-
- vectorbg = new Sprite(); // 1 - vector background layers
- addChild(vectorbg); // |
-
- paint = new MapPaint(this,-5,5); // 2 - core paint object
- addChild(paint); // |
- paint.isBackground=false; // |
-
- if (styleurl) { // if we've only just set up paint, then setStyle won't have created the RuleSet
- paint.ruleset=new RuleSet(MINSCALE,MAXSCALE,redraw,redrawPOIs);
- paint.ruleset.loadFromCSS(styleurl);
- }
if (startscale>0) {
scale=startscale;
this.dispatchEvent(new MapEvent(MapEvent.SCALE, {scale:scale}));
}
-
scalefactor=MASTERSCALE/Math.pow(2,13-scale);
baselon =startlon -(mapwidth /2)/scalefactor;
basey =lat2latp(startlat)+(mapheight/2)/scalefactor;
- addDebug("Baselon "+baselon+", basey "+basey);
updateCoords(0,0);
this.dispatchEvent(new Event(MapEvent.INITIALISED));
download();
-
- if (ExternalInterface.available) {
- ExternalInterface.addCallback("setPosition", function (lat:Number,lon:Number,zoom:uint):void {
- updateCoordsFromLatLon(lat, lon);
- changeScale(zoom);
- });
- }
}
// ------------------------------------------------------------------------------------------
/** Recalculate co-ordinates from new Flash origin */
- public function updateCoords(tx:Number,ty:Number):void {
+ private function updateCoords(tx:Number,ty:Number):void {
setScrollRectXY(tx,ty);
edge_t=coord2lat(-ty );
}
/** Move the map to centre on a given latitude/longitude. */
- public function updateCoordsFromLatLon(lat:Number,lon:Number):void {
+ private function updateCoordsFromLatLon(lat:Number,lon:Number):void {
var cy:Number=-(lat2coord(lat)-mapheight/2);
var cx:Number=-(lon2coord(lon)-mapwidth/2);
updateCoords(cx,cy);
private function moveMap(dx:Number,dy:Number):void {
updateCoords(getX()+dx,getY()+dy);
- updateEntityUIs(false, false);
+ updateAllEntityUIs(false, false);
download();
}
/** Recentre map at given lat/lon, updating the UI and downloading entities. */
public function moveMapFromLatLon(lat:Number,lon:Number):void {
updateCoordsFromLatLon(lat,lon);
- updateEntityUIs(false,false);
+ updateAllEntityUIs(false,false);
download();
}
if (lat> edge_t || lat < edge_b || lon < edge_l || lon > edge_r) {
moveMapFromLatLon(lat, lon);
}
-
}
// Co-ordinate conversion functions
mapwidth = w; centre_lon=coord2lon(-getX()+w/2);
mapheight= h; centre_lat=coord2lat(-getY()+h/2);
setScrollRectSize(w,h);
+ updateCoords(getX(),getY());
this.dispatchEvent(new MapEvent(MapEvent.RESIZE, {width:w, height:h}));
}
}
- /** Download map data. Data is downloaded for the connection and the vector layers, where supported.
+ /** Download map data. Data is downloaded for the currently visible layers
* The bounding box for the download is taken from the current map edges.
*/
public function download():void {
- this.dispatchEvent(new MapEvent(MapEvent.DOWNLOAD, {minlon:edge_l, maxlon:edge_r, maxlat:edge_t, minlat:edge_b} ));
-
- if (edge_l>=bigedge_l && edge_r<=bigedge_r &&
- edge_b>=bigedge_b && edge_t<=bigedge_t) { return; } // we have already loaded this area, so ignore
- bigedge_l=edge_l; bigedge_r=edge_r;
- bigedge_b=edge_b; bigedge_t=edge_t;
- if (connection.waycount>1000) {
- connection.purgeOutside(edge_l,edge_r,edge_t,edge_b);
- }
- addDebug("Calling download with "+edge_l+"-"+edge_r+", "+edge_t+"-"+edge_b);
- connection.loadBbox(edge_l,edge_r,edge_t,edge_b);
-
- // Do the same for vector layers
- for each (var layer:VectorLayer in vectorlayers) {
- layer.loadBbox(edge_l,edge_r,edge_t,edge_b);
- }
- }
-
- private function newWayCreated(event:EntityEvent):void {
- var way:Way = event.entity as Way;
- if (!way.loaded || !way.within(edge_l,edge_r,edge_t,edge_b)) { return; }
- paint.createWayUI(way);
- }
-
- private function newPOICreated(event:EntityEvent):void {
- var node:Node = event.entity as Node;
- if (!node.within(edge_l,edge_r,edge_t,edge_b)) { return; }
- paint.createNodeUI(node);
- }
-
- private function wayRenumbered(event:EntityRenumberedEvent):void {
- var way:Way = event.entity as Way;
- paint.renumberWayUI(way,event.oldID);
- }
-
- private function nodeRenumbered(event:EntityRenumberedEvent):void {
- var node:Node = event.entity as Node;
- paint.renumberNodeUI(node,event.oldID);
- }
-
- /** Visually mark an entity as highlighted. */
- public function setHighlight(entity:Entity, settings:Object):void {
- if ( entity is Way && paint.wayuis[entity.id] ) { paint.wayuis[entity.id].setHighlight(settings); }
- else if ( entity is Node && paint.nodeuis[entity.id]) { paint.nodeuis[entity.id].setHighlight(settings); }
- }
-
- public function setHighlightOnNodes(way:Way, settings:Object):void {
- if (paint.wayuis[way.id]) paint.wayuis[way.id].setHighlightOnNodes(settings);
- }
-
- public function protectWay(way:Way):void {
- if (paint.wayuis[way.id]) paint.wayuis[way.id].protectSprites();
- }
-
- public function unprotectWay(way:Way):void {
- if (paint.wayuis[way.id]) paint.wayuis[way.id].unprotectSprites();
- }
-
- public function limitWayDrawing(way:Way,except:Number=NaN,only:Number=NaN):void {
- if (!paint.wayuis[way.id]) return;
- paint.wayuis[way.id].drawExcept=except;
- paint.wayuis[way.id].drawOnly =only;
- paint.wayuis[way.id].redraw();
- }
-
- /** Protect Entities and EntityUIs against purging. This prevents the currently selected items
- from being purged even though they're off-screen. */
-
- public function setPurgable(entities:Array, purgable:Boolean):void {
- for each (var entity:Entity in entities) {
- entity.locked=!purgable;
- if ( entity is Way ) {
- var way:Way=entity as Way;
- if (paint.wayuis[way.id]) { paint.wayuis[way.id].purgable=purgable; }
- for (var i:uint=0; i<way.length; i++) {
- var node:Node=way.getNode(i)
- node.locked=!purgable;
- if (paint.nodeuis[node.id]) { paint.nodeuis[node.id].purgable=purgable; }
- }
- } else if ( entity is Node && paint.nodeuis[entity.id]) {
- paint.nodeuis[entity.id].purgable=purgable;
- }
- }
+ for (var i:uint=0; i<paintContainer.numChildren; i++)
+ if(getLayerAt(i).visible == true) {
+ getLayerAt(i).connection.loadBbox(edge_l,edge_r,edge_t,edge_b);
+ }
}
// Handle mouse events on ways/nodes
public function entityMouseEvent(event:MouseEvent, entity:Entity):void {
if ( mapController != null )
mapController.entityMouseEvent(event, entity);
-
}
// ------------------------------------------------------------------------------------------
- // Add vector layer
+ // Add layers
+
+ public function addLayer(connection:Connection, styleurl:String, backgroundlayer:Boolean=true, interactive:Boolean=false):MapPaint {
+ var paint:MapPaint=new MapPaint(this, connection, styleurl, -5, 5);
+ paintContainer.addChildAt(paint,0);
+ paint.isBackground=backgroundlayer;
+ paint.interactive=interactive;
+ return paint;
+ }
+
+ public function removeLayerByName(name:String):void {
+ for (var i:uint=0; i<paintContainer.numChildren; i++) {
+ if (getLayerAt(i).connection.name==name)
+ paintContainer.removeChildAt(i);
+ // >>>> REFACTOR: needs to do the equivalent of VectorLayer.blank()
+ }
+ }
+
+ public function findLayer(name:String):MapPaint {
+ for (var i:uint=0; i<paintContainer.numChildren; i++)
+ if (getLayerAt(i).connection.name==name) return getLayerAt(i);
+ return null;
+ }
+
+ private function getLayerAt(i:uint):MapPaint {
+ return MapPaint(paintContainer.getChildAt(i));
+ }
+
+ /** Get all the layers available for this Map object
+ * @return An array of MapPaint objects */
+ public function getLayers():Array {
+ var a:Array = [];
+ for (var i:uint=0; i<paintContainer.numChildren; i++) {
+ a.push(getLayerAt(i));
+ }
+ return a;
+ }
- public function addVectorLayer(layer:VectorLayer):void {
- vectorlayers[layer.name]=layer;
- vectorbg.addChild(layer.paint);
+ /* Find which layer is editable */
+ public function get editableLayer():MapPaint {
+ var editableLayer:MapPaint;
+ for (var i:uint=0; i<paintContainer.numChildren; i++) {
+ if (!getLayerAt(i).isBackground) {
+ if (editableLayer) trace("Multiple editable layers found");
+ editableLayer=getLayerAt(i);
+ }
+ }
+ return editableLayer;
+ }
+
+ /** Find which paint object an entity will be displayed on. */
+ public function getLayerForEntity(entity:Entity):MapPaint {
+ for (var i:uint=0; i<paintContainer.numChildren; i++) {
+ if (getLayerAt(i).sameConnection(entity)) return getLayerAt(i);
+ }
+ return null;
}
// ------------------------------------------------------------------------------------------
// Redraw all items, zoom in and out
- public function updateEntityUIs(redraw:Boolean,remove:Boolean):void {
- paint.updateEntityUIs(connection.getObjectsByBbox(edge_l, edge_r, edge_t, edge_b), redraw, remove);
- for each (var v:VectorLayer in vectorlayers) {
- v.paint.updateEntityUIs(v.getObjectsByBbox(edge_l, edge_r, edge_t, edge_b), redraw, remove);
- }
+ private function updateAllEntityUIs(redraw:Boolean,remove:Boolean):void {
+ for (var i:uint=0; i<paintContainer.numChildren; i++)
+ getLayerAt(i).updateEntityUIs(redraw, remove);
}
- /** Redraw everything, including in every vector layer. */
public function redraw():void {
- paint.redraw();
- for each (var v:VectorLayer in vectorlayers) { v.paint.redraw(); }
+ for (var i:uint=0; i<paintContainer.numChildren; i++)
+ getLayerAt(i).redraw();
}
- /** Redraw POI's, including in every vector layer. */
public function redrawPOIs():void {
- paint.redrawPOIs();
- for each (var v:VectorLayer in vectorlayers) { v.paint.redrawPOIs(); }
+ for (var i:uint=0; i<paintContainer.numChildren; i++)
+ getLayerAt(i).redrawPOIs();
}
- /** Increase scale. */
public function zoomIn():void {
- if (scale==MAXSCALE) { return; }
- changeScale(scale+1);
+ if (scale!=MAXSCALE) changeScale(scale+1);
}
- /** Decrease scale. */
public function zoomOut():void {
- if (scale==MINSCALE) { return; }
- changeScale(scale-1);
+ if (scale!=MINSCALE) changeScale(scale-1);
}
private function changeScale(newscale:uint):void {
- addDebug("new scale "+newscale);
scale=newscale;
this.dispatchEvent(new MapEvent(MapEvent.SCALE, {scale:scale}));
scalefactor=MASTERSCALE/Math.pow(2,13-scale);
updateCoordsFromLatLon((edge_t+edge_b)/2,(edge_l+edge_r)/2); // recentre
tileset.changeScale(scale);
- updateEntityUIs(true,true);
+ updateAllEntityUIs(true,true);
download();
}
- private function reportPosition():void {
- addDebug("lon "+coord2lon(mouseX)+", lat "+coord2lat(mouseY));
- }
-
- private function toggleReportPosition():void {
- showingLatLon = !showingLatLon;
- this.dispatchEvent(new MapEvent(MapEvent.TOGGLE_LATLON, {latlon: showingLatLon}));
- }
-
- /** Switch to new MapCSS. */
- public function setStyle(url:String):void {
- styleurl=url;
- if (paint) {
- paint.ruleset=new RuleSet(MINSCALE,MAXSCALE,redraw,redrawPOIs);
- paint.ruleset.loadFromCSS(url);
- }
- }
-
- /** Select a new background imagery. */
- public function setBackground(bg:Object):void {
- tileparams=bg;
- if (tileset) { tileset.init(bg, bg.url!=''); }
- }
-
/** Set background dimming on/off. */
public function setDimming(dim:Boolean):void {
if (tileset) { tileset.setDimming(dim); }
// and mask)
/*
public function export():void {
- addDebug("size is "+this.width+","+this.height);
+ trace("size is "+this.width+","+this.height);
var jpgSource:BitmapData = new BitmapData(800,800); // (this.width, this.height);
jpgSource.draw(this);
var jpgEncoder:JPGEncoder = new JPGEncoder(85);
/** Prepare for being dragged by recording start time and location of mouse. */
public function mouseDownHandler(event:MouseEvent):void {
if (!_draggable) { return; }
- dragstate=NOT_MOVED;
+ if (dragstate==DRAGGING) { moveMap(x,y); dragstate=SWALLOW_MOUSEUP; } // cancel drag if mouse-up occurred outside the window (thanks, Safari)
+ else { dragstate=NOT_MOVED; }
lastxmouse=stage.mouseX; downX=stage.mouseX;
lastymouse=stage.mouseY; downY=stage.mouseY;
downTime=new Date().getTime();
public function mouseMoveHandler(event:MouseEvent):void {
if (!_draggable) { return; }
if (dragstate==NOT_DRAGGING) {
- this.dispatchEvent(new MapEvent(MapEvent.MOUSEOVER, { x: coord2lon(mouseX), y: coord2lat(mouseY) }));
+ this.dispatchEvent(new MapEvent(MapEvent.MOUSE_MOVE, { x: coord2lon(mouseX), y: coord2lat(mouseY) }));
return;
}
private function everyFrame(event:Event):void {
if (tileset) { tileset.serviceQueue(); }
+ if (stage.focus && !stage.contains(stage.focus)) { stage.focus=stage; }
}
// ------------------------------------------------------------------------------------------
case Keyboard.UP: moveMap(0,mapheight/2); break; // up cursor
case Keyboard.RIGHT: moveMap(-mapwidth/2,0); break; // right cursor
case Keyboard.DOWN: moveMap(0,-mapheight/2); break; // down cursor
- case 76: toggleReportPosition(); break; // L - report lat/long
}
}
- /** What to do if an error with the network connection happens. */
- public function connectionError(err:Object=null): void {
- addDebug("got error");
- }
-
- // ------------------------------------------------------------------------------------------
- // Debugging
-
- public function clearDebug():void {
- if (!Globals.vars.hasOwnProperty('debug')) return;
- Globals.vars.debug.text='';
- }
-
- public function addDebug(text:String):void {
- trace(text);
- if (!Globals.vars.hasOwnProperty('debug')) return;
- if (!Globals.vars.debug.visible) return;
- Globals.vars.debug.appendText(text+"\n");
- Globals.vars.debug.scrollV=Globals.vars.debug.maxScrollV;
- }
-
}
}