فهرست منبع

New version (complety rewritten in AS3) of the flash navigator

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@583 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 15 سال پیش
والد
کامیت
0393d70fe4
5فایلهای تغییر یافته به همراه578 افزوده شده و 0 حذف شده
  1. 134 0
      navigator/iTop/GraphNode.as
  2. 351 0
      navigator/iTop/Navigator.as
  3. 93 0
      navigator/iTop/ToolTip.as
  4. BIN
      navigator/navigator.fla
  5. BIN
      navigator/navigator.swf

+ 134 - 0
navigator/iTop/GraphNode.as

@@ -0,0 +1,134 @@
+package iTop
+{
+	import flash.display.*;
+	import flash.geom.*;
+	import flash.net.*;
+	import flash.events.*;
+	import flash.text.*; 
+	import flash.ui.ContextMenu;
+	import flash.ui.ContextMenuItem;
+	import iTop.ToolTip;
+	import iTop.Navigator;
+	
+	// Items to load on the main chart
+	public class GraphNode extends Sprite
+	{
+		private var m_oIcon:Loader;
+		private var m_sClass;String;
+		private var m_iId:Number;
+		private var m_sParentKey:String;
+		private var m_oToolTip:ToolTip;
+		private var m_fZoom:Number;
+		private var m_oParent:Navigator;
+		
+		public function GraphNode(oParent:Navigator, oPt:Point, sClass:String, iId:Number, sLabel:String, sIconPath:String, sParentKey:String, fZoom:Number)
+		{
+			x = oPt.x;
+			y = oPt.y;
+			m_fZoom = fZoom;
+			m_sClass = sClass;
+			m_iId = iId;
+			m_sLabel.text = sLabel;
+			m_sLabel.autoSize = TextFieldAutoSize.CENTER;
+			m_sLabel.width = m_sLabel.textWidth;
+			m_sLabel.x = -m_sLabel.width/2;
+			m_sLabel.height = m_sLabel.textHeight;
+			m_sParentKey = sParentKey;
+			m_oToolTip = new ToolTip( "<p><b>"+m_sClass+"</b></p><p>"+sLabel+"</p>");
+			m_oToolTip.scaleX = 1 / m_fZoom;
+			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);
+			addChild(m_oIcon);
+			addEventListener(MouseEvent.MOUSE_DOWN, mouseDown)  
+			addEventListener(MouseEvent.MOUSE_UP, mouseReleased); 
+			addEventListener( MouseEvent.MOUSE_OVER, mouseOver );
+			
+			var oContextMenu:ContextMenu = new ContextMenu();
+			oContextMenu.hideBuiltInItems();
+            var oCMI:ContextMenuItem = new ContextMenuItem('Details...');
+            oCMI.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, navigateToObjectDetails);
+            oContextMenu.customItems.push(oCMI);
+            this.contextMenu = oContextMenu;
+
+		}
+		
+		public function GetKey()
+		{
+			return m_sClass+'/'+m_iId;
+		}
+		
+		public function GetParentKey()
+		{
+			return m_sParentKey;
+		}
+		
+		function onLoadError(event:ErrorEvent):void
+		{
+			// Display error message to user in case of loading error.
+			trace ("Sorry that there is an error during the loading of an external image. The error is:" + "\n" + event); 
+		}
+		function onLoadComplete(event:Event):void
+		{ 
+			// Add the Loader on the Sprite when the loading is completed
+			m_oIcon.x = -m_oIcon.width / 2;
+			m_oIcon.y = -m_oIcon.height + 8; // Slightly shifted downward
+			
+			// Construct a tooltip
+			addChild(m_oToolTip);
+			addChild(m_oIcon);
+			trace('m_sLabel, getChildIndex:'+getChildIndex(m_sLabel));
+			trace('m_oToolTip, getChildIndex:'+getChildIndex(m_oToolTip));
+			//swapChildren(m_oToolTip, );
+			// Start the tooltip
+			m_oToolTip.start(); 
+		}
+		 
+		function mouseDown(event:MouseEvent):void 
+		{
+			trace("Click in Node");
+			m_oParent.m_bChildDragging = true;
+			startDrag(); 
+		} 
+		
+		function mouseReleased(event:MouseEvent):void 
+		{ 
+			stopDrag(); 
+			m_oParent.m_bChildDragging = false;
+		}
+
+		public function mouseOver( e:MouseEvent ):void
+		{
+			// Move to the top
+			parent.setChildIndex( this, this.parent.numChildren-1 );
+		}
+		
+		private function navigateToObjectDetails(evt:ContextMenuEvent):void
+		{
+			var sUrl:String = ReadParam('drillUrl', 'http://localhost/pages/UI.php?operation=details');
+			sUrl += '&class='+m_sClass+'&id='+m_iId;
+			var oReq:URLRequest = new URLRequest(sUrl);
+			navigateToURL(oReq, '_top');
+		}
+
+		public function ReadParam(sName:String, sDefaultValue:String)
+		{
+			var paramObj:Object = LoaderInfo(this.root.loaderInfo).parameters;
+		
+			if (paramObj.hasOwnProperty(sName))
+			{
+				return unescape(paramObj[sName]);
+			}
+			else
+			{
+				return sDefaultValue;
+			}
+		}
+	}
+}

+ 351 - 0
navigator/iTop/Navigator.as

@@ -0,0 +1,351 @@
+package iTop
+{
+	import flash.display.*;
+	import flash.geom.*;
+	import flash.net.*;
+	import flash.events.*;
+	import iTop.GraphNode;
+	import fl.controls.Slider; 
+	import fl.events.SliderEvent; 
+	import fl.controls.Label; 
+ 	
+	// The main canvas
+	public class Navigator extends MovieClip
+	{
+		protected var m_oLoader:URLLoader;
+		protected var m_aNodes:Object;
+		protected var m_aLinks:Array;
+		protected var m_oRootNode:GraphNode;
+		protected var m_oCanvas:NavigatorCanvas;
+		public var m_bChildDragging:Boolean;
+		
+		// Parameters
+		protected var m_sStartPosition:String;
+		protected var m_sDataUrl:String;
+		protected var m_sDetailsUrl:String;
+		protected var m_sRelation:String;
+		protected var m_sObjClass:String;
+		protected var m_sObjId:String;
+		
+		// Constants
+		protected var m_RADIUS = 120;
+		protected var m_ITEMS_PER_ROW = 8;
+		protected var m_fZoom:Number;
+		
+		// Constructor
+		public function Navigator()
+		{
+			m_aLinks = new Array();
+			m_aNodes = new Array();
+			m_fZoom = 1;
+			initParameters();
+			doLoadData();
+			addEventListener(Event.ENTER_FRAME, initGraphics);
+		}
+		
+		protected function initParameters():void
+		{
+			
+			m_sDataUrl = ReadParam('xmlUrl', 'http://localhost:81/pages/xml.navigator.php?operation=relation');
+			m_sDetailsUrl = ReadParam('drillUrl', 'http://localhost/pages/UI.php?operation=details');
+			m_sRelation = ReadParam('relation', 'impacts');
+			m_sObjClass = ReadParam('obj_class', 'Server');
+			m_sObjId = ReadParam('obj_id', '1');
+			m_sStartPosition = ReadParam('start_pos', 'left');
+		}
+		
+		function initGraphics(event:Event):void
+		{
+			m_oCanvas = new NavigatorCanvas(); // All drawings will occur here
+			addChild(m_oCanvas); 
+			m_oCanvas.scaleX = m_fZoom;
+			m_oCanvas.scaleY = m_fZoom;
+			// Handle listeners...
+			removeEventListener(Event.ENTER_FRAME,initGraphics);
+			addEventListener(Event.ENTER_FRAME, drawLines);
+			m_oZoomSlider.value = 100;
+			m_oZoomSlider.addEventListener(SliderEvent.CHANGE, onZoomChange);
+			stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDown)  
+			stage.addEventListener(MouseEvent.MOUSE_UP, mouseReleased); 
+		}
+		function mouseDown(event:MouseEvent):void 
+		{ 
+			trace("Click in canvas");
+			if (!m_bChildDragging)
+			{
+				m_oCanvas.startDrag(); 
+			}
+		} 
+		
+		function mouseReleased(event:MouseEvent):void 
+		{ 
+			if (!m_bChildDragging)
+			{
+				m_oCanvas.stopDrag(); 
+			}
+		}
+		
+		function onZoomChange(event:SliderEvent):void
+		{ 
+    		m_fZoom = event.value/100;
+			m_oCanvas.scaleX = m_fZoom;
+			m_oCanvas.scaleY = m_fZoom;
+		}
+		
+		function doLoadData()
+		{
+			var myString:String = m_sDataUrl+'?relation='+m_sRelation+'&class='+m_sObjClass+'&id='+m_sObjId;
+			trace("Requesting:"+myString);
+			var myXMLURL:URLRequest = new URLRequest(myString);
+			m_oLoader = new URLLoader();
+			m_oLoader.addEventListener(Event.COMPLETE, onXMLLoadComplete);
+			m_oLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onXMLLoadError);
+			m_oLoader.addEventListener(IOErrorEvent.IO_ERROR, onXMLLoadError);
+			m_oLoader.load(myXMLURL);
+		}
+		
+		function onXMLLoadComplete(event:Event):void
+		{
+			var myXML:XML = XML(m_oLoader.data);
+			//trace("Data loaded." + myXML);
+			//trace("===========================");
+			parseXMLData(null, myXML, 0);
+			m_sTitle.text = myXML.attribute("title");
+			m_oZoomSlider.enabled = true;
+			removeChild(m_oPreloader);
+		}
+
+		function onXMLLoadError(event:IOErrorEvent):void
+		{
+			trace("An error occured:" + Event);
+		}
+		
+		function parseXMLData(oParentNode:GraphNode, oXMLData:XML, iChildIndex:Number)
+		{
+			//trace(oXMLData.child("node").length());
+			var oNode:GraphNode;
+			oNode  = addNode(oParentNode, oXMLData.child("node")[0], iChildIndex);
+			if (oParentNode != null)
+			{
+				AddLink(oParentNode.GetKey(), oNode.GetKey());
+			}
+			//trace('Root node:'+oRoot.toString());
+			var oLinks = oXMLData.child("node")[0].links;
+			var iChildIndex:Number = 0;
+			if (oLinks.length() > 0)
+			{
+				//trace('links: '+oLinks.toString());
+				var oLink = oLinks.link;
+				for each(var oChild:XML in oLink)
+				{
+					parseXMLData(oNode, oChild, iChildIndex);
+					iChildIndex++;
+				}
+			}
+		}
+		
+		function addNode(oParent:GraphNode, oXMLData:XML, iChildIndex)
+		{
+			var sClass  = oXMLData.@obj_class;
+			var iId = oXMLData.@id;
+			var sLabel = oXMLData.@name;
+			var sIcon = oXMLData.@icon;
+			
+			var oNode:GraphNode = GetNode(sClass+'/'+iId);
+			if (oNode == null)
+			{
+				// If the node does not already exist, let's create it
+				var oPt:Point = GetNextFreePosition(oParent, iChildIndex);
+				var sParentKey = null;
+				if (oParent != null)
+				{
+					sParentKey = oParent.GetKey();
+				}
+				oNode = new GraphNode(this, oPt, sClass, iId, sLabel, sIcon, sParentKey, m_fZoom);
+				this.m_aNodes[oNode.GetKey()] = oNode; //Keep it referenced
+				if (oParent == null)
+				{
+					m_oRootNode = oNode;
+				}
+				m_oCanvas.addChild(oNode);
+			}
+			return oNode;
+			//trace("class: "+sClass+", id: "+iId+", name: "+sLabel+", Icon: "+sIcon);
+		}
+		
+		function GetNode(sKey)
+		{
+			if (m_aNodes.hasOwnProperty(sKey))
+			{
+				return m_aNodes[sKey];
+			}
+			else
+			{
+				return null;
+			}
+		}
+		
+		function GetNextFreePosition(oParent:GraphNode, iChildIndex:Number):Point
+		{
+			var oPt:Point = GetInitialPosition();
+			var angle:Number = GetInitialAngle();
+			if (oParent != null)
+			{
+				oPt.x = oParent.x;
+				oPt.y = oParent.y;
+				var sGrandParentKey:String = oParent.GetParentKey();
+				if (sGrandParentKey != null)
+				{
+					var oGrandParent:GraphNode = GetNode(sGrandParentKey);
+					var dx:Number = oParent.x - oGrandParent.x;
+					var dy:Number = oParent.y - oGrandParent.y;
+					if ((dx == 0) && (dy == 0))
+					{
+						angle = GetInitialAngle();
+					}
+					else
+					{
+						angle = Math.atan2(dy, dx);
+					}
+				}
+				var radius = m_RADIUS * Math.floor(iChildIndex / m_ITEMS_PER_ROW);
+				angle += iChildIndex*(2*Math.PI) / m_ITEMS_PER_ROW;
+				
+				oPt.x += m_RADIUS * Math.cos(angle);
+				oPt.y += m_RADIUS * Math.sin(angle);
+				
+				trace("iChildIndex: "+iChildIndex+" x: "+oPt.x+" y: "+oPt.y+" sGdParentKey: "+sGrandParentKey);
+			}
+			return oPt;
+		}
+		
+		function GetInitialPosition():Point
+		{
+			trace('width: '+stage.stageWidth+' height: '+stage.stageHeight);
+			var oPos:Point = new Point(0,0);
+			switch(m_sStartPosition)
+			{
+				case 'left':
+				oPos.x = m_RADIUS;
+				oPos.y = stage.stageHeight / 2;
+				break;
+				
+				case 'right':
+				oPos.x = stage.stageWidth - m_RADIUS;
+				oPos.y = stage.stageHeight / 2;
+				break;
+				
+				case 'top':
+				oPos.x = stage.stageWidth/2;
+				oPos.y = m_RADIUS;
+				break;
+				
+				case 'bottom':
+				oPos.x = stage.stageWidth/2;
+				oPos.y = stage.stageHeight - m_RADIUS;
+				break;
+			}
+			return oPos;
+		}
+
+		function GetInitialAngle():Number
+		{
+			var angle:Number;
+			switch(m_sStartPosition)
+			{
+				case 'left':
+				angle = 0;
+				break;
+				
+				case 'right':
+				angle = Math.PI;
+				break;
+				
+				case 'top':
+				angle = -Math.PI / 2;
+				break;
+				
+				case 'right':
+				angle = Math.PI / 2;
+				break;
+			}
+			return angle;
+		}
+				
+		function AddLink(sStart:String, sEnd:String)
+		{
+			var oLink = new Link(sStart, sEnd);
+			m_aLinks.push(oLink);
+		}
+		
+		function drawLines(event:Event):void
+		{
+			m_oCanvas.graphics.clear();
+			m_oCanvas.graphics.lineStyle(2,0x666666,100);
+			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);
+				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);
+			}
+		}
+		function drawArrow(oPt:Point, dx:Number, dy:Number):void
+		{
+			var l:Number = Math.sqrt(dx*dx+dy*dy);
+			var arrowSize:Number = 5;
+			m_oCanvas.graphics.lineStyle(2,0x666666,100,false,"normal",CapsStyle.ROUND);
+			m_oCanvas.graphics.moveTo(oPt.x, oPt.y);
+			m_oCanvas.graphics.lineTo(oPt.x + arrowSize*(dy-dx)/l, oPt.y - arrowSize*(dx+dy)/l);
+			m_oCanvas.graphics.moveTo(oPt.x, oPt.y);
+			m_oCanvas.graphics.lineTo(oPt.x - arrowSize*(dx+dy)/l, oPt.y - arrowSize*(dy-dx)/l);
+		}
+		
+		public function ReadParam(sName:String, sDefaultValue:String)
+		{
+			var paramObj:Object = LoaderInfo(this.root.loaderInfo).parameters;
+		
+			if (paramObj.hasOwnProperty(sName))
+			{
+				return unescape(paramObj[sName]);
+			}
+			else
+			{
+				return sDefaultValue;
+			}
+		}
+	}	
+}
+
+class Link extends Object
+{
+	protected var m_sStart:String;
+	protected var m_sEnd:String;
+	public function Link(sStartNodeKey:String, sEndNodeKey:String)
+	{
+		m_sStart = sStartNodeKey;
+		m_sEnd = sEndNodeKey;
+	}
+	
+	public function GetStart():String
+	{
+		return m_sStart;
+	}
+	public function GetEnd():String
+	{
+		return m_sEnd;
+	}
+}
+
+import flash.display.*;
+import flash.geom.*;
+import flash.events.*;
+
+class NavigatorCanvas extends Sprite
+{
+	public function NavigatorCanvas()
+	{
+	}
+}

+ 93 - 0
navigator/iTop/ToolTip.as

@@ -0,0 +1,93 @@
+package iTop
+{
+	import flash.display.Sprite;
+	import flash.text.TextField;
+	import flash.text.TextFormat;
+	import flash.text.TextFieldAutoSize;
+	import flash.text.TextLineMetrics;
+	import flash.display.BlendMode;
+	import flash.utils.Timer;
+	import flash.events.MouseEvent;
+	
+	public class ToolTip extends Sprite
+	{
+		private var _tip:String;
+		// You'll need this for proper text formatting
+		private var _tf:TextField = new TextField();
+		private var _format:TextFormat = new TextFormat();
+		private static const ROUND:Number = 2;
+		private static const HEIGHT:Number = 25;
+		private static const FONT_SIZE:uint = 12;
+		private static const FONT:String = 'Arial';
+		private static const PADDING:Number = 5;
+		private static const MIN_ALPHA:Number = 0;
+		private static const ALPHA_INC:Number = .1;
+		private static const MAX_ALPHA:Number = 1;
+		private static const REFRESH:Number = MAX_ALPHA / ALPHA_INC;
+		// For fading in and out
+		private var _timer:Timer;
+		public function ToolTip( tip:String )
+		{
+			// Hold onto the tip for posterity
+			_tip = tip;
+			// This ensures the textfield inherits this class's
+			// alpha property.  Very important because otherwise tf
+			// would always have an alpha of 1 meaning it will always be visible
+			this.blendMode = BlendMode.LAYER;
+			_format.size = FONT_SIZE;
+			_format.font = FONT;
+			// Make sure the text behaves and looks
+			// the way text on a button should
+			_tf.defaultTextFormat = _format;
+			// Always call defaultTextFormat before setting text otherwise
+			// the text doesn't use the formatting defined in tf
+			_tf.autoSize = TextFieldAutoSize.LEFT;
+			// You have to set autoSize to TextFieldAutoSize.LEFT
+			// for box.textWidth to be accurate
+			_tf.multiline = true;
+			_tf.htmlText = tip;
+			_tf.selectable = false;
+			_tf.x += PADDING;
+			_tf.y += PADDING;
+			addChild( _tf );
+			// Draw the background
+			graphics.beginFill( 0xF6F6F1, 1 );
+			graphics.drawRoundRect( 0, 0, _tf.textWidth+PADDING*4, _tf.textHeight+PADDING*4, ROUND );
+			graphics.endFill();
+			this.alpha = MIN_ALPHA;
+		}
+		// You have to call this after
+		// the tooltip has been added to the
+		// display list
+		public function start():void
+		{
+			this.parent.addEventListener( MouseEvent.MOUSE_OVER, mouse_over );
+		}
+		public function mouse_over( e:MouseEvent ):void
+		{
+			this.parent.setChildIndex( this, this.parent.numChildren-1 )
+			// Move the tool tip to the top!
+			var fadeSpeed:Number = 500 / REFRESH;
+			_timer = new Timer( fadeSpeed, REFRESH );
+			_timer.addEventListener( "timer", fadeIn );
+			_timer.start();
+			this.parent.addEventListener( MouseEvent.MOUSE_OUT, mouse_out );
+		}
+		public function mouse_out( e:MouseEvent ):void
+		{
+			var fadeSpeed:Number = 500 / REFRESH;
+			_timer = new Timer( fadeSpeed, REFRESH );
+			_timer.addEventListener( "timer", fadeOut );
+			_timer.start();
+		}
+		private function fadeIn( i:uint ):void
+		{
+			this.alpha += ALPHA_INC;
+		}
+		private function fadeOut( i:uint ):void
+		{
+			this.alpha -= ALPHA_INC;
+		}
+	}
+}
+

BIN
navigator/navigator.fla


BIN
navigator/navigator.swf