Prechádzať zdrojové kódy

Enhanced version of the SWF navigator providing a better stability for big numbers of elements.

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@3408 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 10 rokov pred
rodič
commit
8aadcfca96

+ 51 - 9
navigator/iTop/GraphNode.as

@@ -5,7 +5,8 @@
 	import flash.net.*;
 	import flash.events.*;
 	import flash.text.*; 
-	import flash.xml.*; 
+	import flash.xml.*;
+	import flash.filters.*;
 	import flash.ui.ContextMenu;
 	import flash.ui.ContextMenuItem;
 	import iTop.ToolTip;
@@ -17,11 +18,12 @@
 		private var m_oIcon:Loader;
 		private var m_sClass:String;
 		private var m_sClassName:String;
-		private var m_iId:Number;
+		private var m_iId:int;
 		private var m_sParentKey:String;
 		private var m_oToolTip:ToolTip;
 		private var m_fZoom:Number;
 		private var m_oParent:Navigator;
+		private var m_bRoot:Boolean;
 		private static const ROUND:Number = 20;
 		private static const PADDING:Number = 5;
 		public var m_speed_x:Number = 0;
@@ -36,6 +38,7 @@
 			m_sClass = sClass;
 			m_sClassName = sClassName;
 			m_iId = iId;
+			m_bRoot = false;
 			m_sLabel.autoSize = TextFieldAutoSize.LEFT;
 			m_sLabel.multiline = false;
 			m_sLabel.text = sLabel;
@@ -59,12 +62,16 @@
 			m_oToolTip.scaleY = 1 / m_fZoom;
 			m_oParent = oParent;
 			
-			var myURL:URLRequest = new URLRequest(sIconPath);
-			m_oIcon = new Loader();
-			m_oIcon.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
-			m_oIcon.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onLoadError);
-			m_oIcon.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
-			m_oIcon.load(myURL);
+			if (!m_oParent.DEBUG)
+			{
+				var myURL:URLRequest = new URLRequest(sIconPath);
+				m_oIcon = new Loader();
+				m_oIcon.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError);
+				m_oIcon.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onLoadError);
+				m_oIcon.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete);
+				m_oIcon.load(myURL);
+			}
+		
 			//addChild(m_oIcon);
 			addEventListener(MouseEvent.MOUSE_DOWN, mouseDown)  
 			addEventListener(MouseEvent.MOUSE_UP, mouseReleased); 
@@ -79,6 +86,22 @@
 
 		}
 		
+		public function MarkAsRoot()
+		{
+			m_bRoot = true;
+			SetGlowFilter();
+		}
+		
+		protected function SetGlowFilter()
+		{
+			var glow:GlowFilter = new GlowFilter();
+			glow.color = 0x3333FF;
+			glow.blurX = 15;
+			glow.blurY = 15;
+			glow.inner = false;
+			filters = [glow];
+		}
+		
 		public function GetKey()
 		{
 			return m_sClass+'/'+m_iId;
@@ -115,8 +138,19 @@
 		{
 			trace("Click in Node");
 			m_oParent.m_bChildDragging = true;
+			m_oParent.m_bAutoPanAndZoom = false;
+			m_oParent.m_bHighFrictionMode = true;
+			m_oParent.m_bComputationNeeded = true;
 			m_bInDrag = true;
-			m_oToolTip.timer.stop(); // Don't show the tooltip while dragging
+			var shadow:DropShadowFilter = new DropShadowFilter(); 
+			shadow.distance = 5; 
+			shadow.angle = 45;
+			shadow.alpha = 0.5;
+			filters = [shadow];
+			if  ((m_oToolTip) && (m_oToolTip.timer))
+			{
+				m_oToolTip.timer.stop(); // Don't show the tooltip while dragging
+			}
 			startDrag(); 
 		} 
 		
@@ -125,6 +159,14 @@
 			m_bInDrag = false;
 			stopDrag(); 
 			m_oParent.m_bChildDragging = false;
+			if (m_bRoot)
+			{
+				SetGlowFilter(); // Apply the glow filter
+			}
+			else
+			{
+				filters = []; // Remove the drop shadow
+			}
 		}
 
 		public function mouseOver( e:MouseEvent ):void

+ 204 - 59
navigator/iTop/Navigator.as

@@ -14,6 +14,8 @@
 	// The main canvas
 	public class Navigator extends MovieClip
 	{
+		public var DEBUG:Boolean = false;
+		protected var CURRENT_VERSION:String = 'v. 2.0.6';
 		protected var m_oLoader:URLLoader;
 		protected var m_aNodes:Object;
 		protected var m_aLinks:Array;
@@ -33,21 +35,29 @@
 		// Constants
 		protected var m_RADIUS = 150;
 		protected var m_Q = 0.9; // Electrostatic forces coeff
-		protected var m_K = 1.0; // Elastic forces coeff
+		protected var m_K = 1; // Elastic forces coeff
 		protected var m_Kf = 0.7; // Fluid friction coeff
 		protected var m_Ks = 30; // Solid friction coeff
+		protected var m_KsLowFriction = 10; // Solid friction coeff
+		protected var m_KsHighFriction = 30; // Solid friction coeff
 		protected var m_deltaT = 0.1; // Interval of time between updates
 		protected var m_MAX_ITEMS_PER_ROW = 8;
-		protected var m_FOCUS_DELAY_COUNTDOWN = 30; // 30 images to zoom & pan correctly
+		protected var m_FOCUS_DELAY_COUNTDOWN; // Number of images to zoom & pan correctly
 		protected var m_fZoom:Number;
+		protected var m_iIterations:int = 0;
+		public var m_bComputationNeeded = true;
+		public var m_bAutoPanAndZoom = true;
+		public var m_bHighFrictionMode = false;
+		protected var m_iNbNodes:int = 0;
 		
 		// Constructor
 		public function Navigator()
 		{
-			m_aLinks = new Array();
-			m_aNodes = new Array();
+			m_aLinks = [];
+			m_aNodes = [];
 			m_sExclude = '';
 			m_fZoom = 1;
+			m_Ks = m_KsLowFriction;
 			m_oLoader = null;
 			initParameters();
 			var success = true;
@@ -83,15 +93,21 @@
 		
 		function Reset()
 		{
-			m_aLinks = new Array();
+			m_aLinks = [];
 			for (var i:String in m_aNodes)
 			{
 				m_oCanvas.removeChild(m_aNodes[i]);
 			}
-			m_aNodes = new Array();
+			m_aNodes = [];
+			m_bAutoPanAndZoom = true;
+			m_bHighFrictionMode = false;
+			m_iIterations = 0;
+			m_iNbNodes = 0;
+			m_bComputationNeeded = true;
 			removeEventListener(Event.ENTER_FRAME, drawLines);
 			stage.removeEventListener(MouseEvent.MOUSE_DOWN, mouseDown)  
 			stage.removeEventListener(MouseEvent.MOUSE_UP, mouseReleased);
+			stage.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
 		}
 		
 		function DoFilter(sExcludeList:String):void
@@ -104,7 +120,9 @@
 		protected function initParameters():void
 		{
 			
-			m_sDataUrl = ReadParam('xmlUrl', 'http://localhost:81/pages/xml.navigator.php?operation=relation');
+			m_sDataUrl = ReadParam('xmlUrl', 'c:\\temp\\test.xml');
+			//m_sDataUrl = ReadParam('xmlUrl', 'c:\\temp\\test2.xml');
+			//m_sDataUrl = ReadParam('xmlUrl', 'c:\\temp\\navigator.xml');
 			m_sDetailsUrl = ReadParam('drillUrl', 'http://localhost/pages/UI.php?operation=details');
 			m_sRelation = ReadParam('relation', 'impacts');
 			m_sObjClass = ReadParam('obj_class', 'DBServerInstance');
@@ -114,6 +132,7 @@
 		
 		function initGraphics(event:Event):void
 		{
+			stage.align = 'left';
 			m_oCanvas = new NavigatorCanvas(); // All drawings will occur here
 			addChild(m_oCanvas); 
 			m_oCanvas.scaleX = m_fZoom;
@@ -122,26 +141,54 @@
 			removeEventListener(Event.ENTER_FRAME,initGraphics);
 			m_oZoomSlider.value = 100;
 			m_oZoomSlider.addEventListener(SliderEvent.CHANGE, onZoomChange);
+			m_oVersion.text = CURRENT_VERSION;
 		}
 		function mouseDown(event:MouseEvent):void 
 		{ 
 			trace("Click in canvas");
 			if (!m_bChildDragging)
 			{
+				m_bAutoPanAndZoom = false;
 				m_oCanvas.startDrag(); 
 			}
-		} 
+		}
 		
 		function mouseReleased(event:MouseEvent):void 
 		{ 
 			if (!m_bChildDragging)
 			{
-				m_oCanvas.stopDrag(); 
+				m_oCanvas.stopDrag();
+				trace('Canvas.x = '+m_oCanvas.x+', Canvas.y = '+m_oCanvas.y); 
 			}
 		}
 		
+		function mouseWheelHandler(event:MouseEvent):void
+		{
+        	trace("mouseWheelHandler delta: " + event.delta);
+			var newZoomLevel:Number = m_fZoom;
+			if (event.delta > 0)
+			{
+				newZoomLevel += 0.05;
+				if (newZoomLevel < 1.0)
+				{
+					SetZoomLevel(newZoomLevel);
+					m_oZoomSlider.value = Math.round(100*newZoomLevel);
+				}
+			}
+			else
+			{
+				newZoomLevel -= 0.05;
+				if (newZoomLevel > 0.0)
+				{
+					SetZoomLevel(newZoomLevel);
+					m_oZoomSlider.value = Math.round(100*newZoomLevel);
+				}
+			}
+    	}
+		
 		function onZoomChange(event:SliderEvent):void
-		{ 
+		{
+			m_bAutoPanAndZoom = false;
     		SetZoomLevel(event.value/100);
 		}
 		
@@ -190,10 +237,18 @@
 				//trace("===========================");
 				parseXMLData(null, myXML, 0, 0);
 				m_sTitle.text = decodeEntities(myXML.attribute("title").toString());
-				m_oZoomSlider.enabled = true;
+
+
+				// Initial positions computation
+				for(var i=0; i<10; i++)
+				{
+					UpdatePositions();
+				}
+				UpdatePanAndZoom(1);
 				addEventListener(Event.ENTER_FRAME, drawLines);
 				stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown)  
 				stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased);
+				stage.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler);
 				//trace('======= Initial Posistions =========');
 				//DumpPositions();
 			}
@@ -215,6 +270,8 @@
 				{
 					m_oPreloader.visible = false;
 				}
+				m_oZoomSlider.enabled = true;
+				m_oVersion.visible = false;
 			}
 		}
 
@@ -263,7 +320,7 @@
 			var iId = oXMLData.@id;
 			var sLabel:String = decodeEntities(oXMLData.@name);
 			var sIcon:String = oXMLData.@icon;
-			var oDetails:Object = new Object;
+			var oDetails:Object = {};
 			var sZlist:String = oXMLData.@zlist;
 			
 			var oNode:GraphNode = GetNode(sClass+'/'+iId);
@@ -287,7 +344,13 @@
 					//}
 				}
 				oNode = new GraphNode(this, oPt, sClass, sClassName, iId, sLabel, sIcon, sParentKey, m_fZoom, oDetails);
+				if (oParent == null)
+				{
+					// this is the root node, higlight it
+					oNode.MarkAsRoot();
+				}
 				this.m_aNodes[oNode.GetKey()] = oNode; //Keep it referenced
+				m_iNbNodes++;
 				if (oParent == null)
 				{
 					m_oRootNode = oNode;
@@ -437,31 +500,78 @@
 		{
 			var color:uint = 0x666666;
 			m_oCanvas.graphics.clear();
+			
+			if (m_bHighFrictionMode)
+			{
+				// Increase the friction so that manually manipulating objects gets easier
+				trace("More friction now...");
+				m_Ks = m_KsHighFriction; // 5 times more friction
+			}
+			else
+			{
+				m_Ks = m_KsLowFriction;
+			}			
+			
+			if (DEBUG)
+			{
+				m_oCanvas.graphics.lineStyle(2,0xff3333,100,false,"normal",CapsStyle.ROUND);
+				
+				var sceneRect:Rectangle = null;
+				for(var i:String in this.m_aNodes)
+				{
+					if (sceneRect == null)
+					{
+						sceneRect = GetNode(i).getBounds(m_oCanvas);
+					}
+					else
+					{
+						sceneRect = sceneRect.union(GetNode(i).getBounds(m_oCanvas));
+					}
+				}
+				if (sceneRect != null)
+				{
+					/*
+					m_oCanvas.graphics.lineStyle(2,0xff0000,100,false,"normal",CapsStyle.ROUND);
+
+					m_oCanvas.graphics.moveTo(-500, 0);
+					m_oCanvas.graphics.lineTo(500, 0);
+
+					m_oCanvas.graphics.moveTo(0, -500);
+					m_oCanvas.graphics.lineTo(0, 500);
+
+					m_oCanvas.graphics.moveTo(sceneRect.x, sceneRect.y);
+					m_oCanvas.graphics.lineTo(sceneRect.x + sceneRect.width, sceneRect.y);
+					m_oCanvas.graphics.lineTo(sceneRect.x + sceneRect.width, sceneRect.y + sceneRect.height);
+					m_oCanvas.graphics.lineTo(sceneRect.x, sceneRect.y + sceneRect.height);
+					m_oCanvas.graphics.lineTo(sceneRect.x, sceneRect.y);
+					*/
+				}
+			}
+			
 			m_oCanvas.graphics.lineStyle(2,0x666666,100);
 			UpdatePositions();
+			if (m_bAutoPanAndZoom)
+			{
+				UpdatePanAndZoom(1);
+			}
+			
 			for (var index:String in m_aLinks)
 			{
+				
     			var oStartNode:GraphNode = GetNode(m_aLinks[index].GetStart());
 				var oEndNode = GetNode(m_aLinks[index].GetEnd());
+				
 				m_oCanvas.graphics.moveTo(oStartNode.x, oStartNode.y);
 				m_oCanvas.graphics.lineTo(oEndNode.x, oEndNode.y);
+				
+				if (DEBUG)
+				{
+					m_oCanvas.graphics.drawCircle(oStartNode.x, oStartNode.y, 5);
+					m_oCanvas.graphics.drawCircle(oEndNode.x, oEndNode.y, 5);
+				}
 				var oMiddlePoint:Point = new Point((oEndNode.x+oStartNode.x)/2, (oEndNode.y+oStartNode.y)/2);
 				drawArrow(oMiddlePoint, oEndNode.x - oStartNode.x, oEndNode.y - oStartNode.y, color);
 			}
-
-			if (this.m_FOCUS_DELAY_COUNTDOWN > 0)
-			{
-				this.m_FOCUS_DELAY_COUNTDOWN--;
-				trace('FOCUS_DELAY:'+this.m_FOCUS_DELAY_COUNTDOWN);
-				UpdatePanAndZoom(m_FOCUS_DELAY_COUNTDOWN / 30);
-			}
-			else if (this.m_FOCUS_DELAY_COUNTDOWN == 0)
-			{
-				// Increase the friction so that manually manipulating objects gets easier
-				trace("More friction now...");
-				m_Ks = 5*m_Ks; // 5 times more friction
-				this.m_FOCUS_DELAY_COUNTDOWN--;
-			}
 		}
 		function drawArrow(oPt:Point, dx:Number, dy:Number, color:uint):void
 		{
@@ -493,7 +603,7 @@
 		
 		public function ComputeElectrostaticForces():Array
 		{
-			var aForces:Array = new Array;
+			var aForces:Array = [];
 			//trace('====== BEGIN ComputeElectrostaticForces() =======');
 			
 			for (var i:String in this.m_aNodes)
@@ -510,7 +620,6 @@
 						var dx:Number = oRemoteNode.x - oCurrentNode.x;
 						var dy:Number = oRemoteNode.y - oCurrentNode.y;
 						var d2:Number = (dx*dx + dy*dy) / (this.m_RADIUS * this.m_RADIUS);
-						var d:Number = Math.sqrt(d2);
 						var Fx:Number = 0;
 						var Fy:Number = 0;
 						if (d2 < 0.05)
@@ -554,7 +663,7 @@
 		function ComputeElasticForces()
 		{
 			//trace('====== BEGIN ComputeElasticForces() =======');
-			var aForces:Array = new Array;
+			var aForces:Array = [];
 		
 			for (var i:String in this.m_aNodes)
 			{
@@ -562,9 +671,11 @@
 				aForces[i].FxTotal = 0;
 				aForces[i].FyTotal = 0;
 			}
+			
 			// Elastic forces: each link applies a force proportional to its length (F = - K * x)
 			for(i in this.m_aLinks)
 			{
+				trace(i);
     			var oStartNode:GraphNode = GetNode(m_aLinks[i].GetStart());
 				var oEndNode = GetNode(m_aLinks[i].GetEnd());
 				var dx = oStartNode.x - oEndNode.x;
@@ -572,10 +683,12 @@
 				//d = Math.sqrt(dx*dx + dy*dy);
 				//Fx = -K * d * dx / d;
 				//Fy = -K * d * dy / d;
-				// Links with more weight attached are more rigid !
-				//weightCoeff = (aWeights[aLinks[l].start] + aWeights[aLinks[l].end])/2;
+				//var Fy = -m_K * d * dy / d;
+				// Which can be simplified as:
 				var Fx = -this.m_K * dx;
 				var Fy = -this.m_K * dy;
+				// Links with more weight attached are more rigid !
+				//weightCoeff = (aWeights[aLinks[l].start] + aWeights[aLinks[l].end])/2;
 				aForces[oStartNode.GetKey()].FxTotal += Fx;
 				aForces[oStartNode.GetKey()].FyTotal += Fy;
 				aForces[oEndNode.GetKey()].FxTotal -= Fx;
@@ -602,11 +715,26 @@
 		 */		 		
 		function UpdatePositions()
 		{
+			if (!m_bComputationNeeded)
+			{
+				trace('Nothing is moving, halting the computation, deltaT='+m_deltaT);
+				return; // everything is still, no need to recompute
+			}
 			//trace('====== BEGIN UpdatePositions() =======');
 			var aElasticForces:Array = ComputeElasticForces();
 			var aElectrostaticForces:Array = ComputeElectrostaticForces();
-			//DrawForces(aElectrostaticForces, 0xcc0000);
-			//DrawForces(aElectrostaticForces, 0x0000cc);
+			if (DEBUG)
+			{
+				DrawForces(aElasticForces, 0xcc0000);
+				DrawForces(aElectrostaticForces, 0x0000cc);
+			}
+			var Ks2:Number = this.m_Ks*this.m_Ks;
+			var nbNodes:int = 0;
+			var dxMax:Number = 0;
+			var dyMax:Number = 0;
+			var maxAccel2 = 50000.0/(m_fZoom*m_fZoom);
+			m_bComputationNeeded = false; // Needed only if something is still moving
+			var nextDeltaT = m_deltaT;
 			for (var i:String in this.m_aNodes)
 			{
 				var oNode:GraphNode = GetNode(i);
@@ -625,16 +753,38 @@
 					}
 					else
 					{
+						var Ax = this.m_deltaT*Fx;
+						var Ay =  this.m_deltaT*Fy;
+						if ((Ax * Ax + Ay *Ay) > maxAccel2)
+						{
+							nextDeltaT = m_deltaT*0.95; // Slow down for the next pass
+						}
 						oNode.m_speed_x = oNode.m_speed_x*this.m_Kf + this.m_deltaT*Fx;
 						oNode.m_speed_y = oNode.m_speed_y*this.m_Kf + this.m_deltaT*Fy;
-						var dx:Number = oNode.m_speed_x * this.m_deltaT;
-						var dy:Number = oNode.m_speed_y * this.m_deltaT;
-						oNode.x = Math.round(oNode.x + dx);
-						oNode.y = Math.round(oNode.y + dy);
+						
+						var dx:int = oNode.m_speed_x * this.m_deltaT;
+						var dy:int = oNode.m_speed_y * this.m_deltaT;
+						dxMax = Math.max(dxMax, dx);
+						dyMax = Math.max(dyMax, dy);
+						if ((dx*m_fZoom > 1) || (dx*m_fZoom > 1))
+						{
+							// visibly moving by more than 1 px
+							oNode.x = oNode.x + dx;
+							oNode.y = oNode.y + dy;
+							m_bComputationNeeded = true;
+						}
 						//trace('object '+i+' moves (Force: Fx='+Fx+', Fy='+Fy+')! ');
 					}
 				}
+				else
+				{
+					 m_bComputationNeeded = true;
+				}
+				nbNodes++;
 			}
+			m_deltaT = nextDeltaT;
+			trace('Iteration: '+(m_iIterations)+', '+nbNodes+' nodes processed. Max displacement dx='+dxMax+', dy='+dyMax);
+			m_iIterations++;
 			//trace('======= Updated Positions =========');
 			//DumpPositions();
 			//trace('====== END UpdatePositions() =======');
@@ -649,8 +799,8 @@
 				m_oCanvas.graphics.lineStyle(2,color,100,false,"normal",CapsStyle.ROUND);
 				m_oCanvas.graphics.moveTo(oNode.x, oNode.y);
 				var oEndPoint:Point = new Point;
-				oEndPoint.x = Math.round(oNode.x + oForce.FxTotal);
-				oEndPoint.y = Math.round(oNode.y + oForce.FyTotal);
+				oEndPoint.x = oNode.x + oForce.FxTotal;
+				oEndPoint.y = oNode.y + oForce.FyTotal;
 				m_oCanvas.graphics.lineTo(oEndPoint.x, oEndPoint.y);
 				drawArrow(oEndPoint, oForce.FxTotal, oForce.FyTotal, color);
 				//trace('Drawinf vector '+i+': (x='+oNode.x+', y='+oNode.y+') to (x='+oEndPoint.x+', y='+oEndPoint.y+')');
@@ -676,27 +826,22 @@
 				var idealZoomLevel:Number = 1;
 				trace('Stage dimensions: width:'+stage.stageWidth+' height:'+stage.stageHeight);
 				
-				if ((sceneRect.width > stage.stageWidth) || (sceneRect.height > (stage.stageHeight - 50)))
-				{
-					var wRatio:Number = stage.stageWidth / sceneRect.width;
-					var hRatio:Number = (stage.stageHeight - 50) / sceneRect.height;
-					idealZoomLevel = Math.min(wRatio, hRatio);
-					SetZoomLevel(idealZoomLevel);
-					m_oZoomSlider.value = Math.round(100*idealZoomLevel);
-		
-				}
+				var wRatio:Number = stage.stageWidth / sceneRect.width;
+				var hRatio:Number = (stage.stageHeight - 50) / sceneRect.height;
+				idealZoomLevel = Math.min(Math.min(wRatio, hRatio), 1);
+				SetZoomLevel(idealZoomLevel);
+				m_oZoomSlider.value = Math.round(100*idealZoomLevel);
+
 				var xOffset:Number = 0;
-				var yOffset:Number = 50;
-				if (stage.stageWidth > sceneRect.width)
-				{
-					xOffset = (stage.stageWidth-sceneRect.width)/2
-				}
-				if (stage.stageHeight > sceneRect.height)
-				{
-					yOffset = 50 + (stage.stageHeight-50-sceneRect.height)/2
-				}
-				m_oCanvas.x = xOffset-sceneRect.x;
-				m_oCanvas.y = yOffset-sceneRect.y;
+				var yOffset:Number = 0;
+				var newWidth:Number = sceneRect.width * idealZoomLevel;
+				var newHeight:Number = sceneRect.height * idealZoomLevel;
+				
+				xOffset = stage.stageWidth/2 - newWidth/2 - sceneRect.x*idealZoomLevel;
+				yOffset = 50 + stage.stageHeight/2 - newHeight/2 - sceneRect.y*idealZoomLevel; 
+				
+				m_oCanvas.x = xOffset;
+				m_oCanvas.y = yOffset;
 				
 				trace('Scene bounding rect: x:'+sceneRect.x+' y:'+sceneRect.y+' width:'+sceneRect.width+' height:'+sceneRect.height+' zoomLevel:'+idealZoomLevel);
 			}

BIN
navigator/navigator.fla