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

SVN:trunk[583]
This commit is contained in:
Denis Flaven
2010-07-06 17:53:26 +00:00
parent a5157a34fe
commit b35b25d56a
5 changed files with 578 additions and 0 deletions

134
navigator/iTop/GraphNode.as Normal file
View File

@@ -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
navigator/iTop/Navigator.as Normal file
View File

@@ -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
navigator/iTop/ToolTip.as Normal file
View File

@@ -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;
}
}
}

Binary file not shown.

Binary file not shown.