mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-18 14:58:43 +02:00
Cleanup: unused code
SVN:trunk[4708]
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
#
|
||||
# The following source files are not re-distributed with the "build" of the application
|
||||
# since they are used solely for constructing other files during the build process
|
||||
#
|
||||
iTop
|
||||
navigator.as2
|
||||
navigator.fla
|
||||
@@ -1,205 +0,0 @@
|
||||
package iTop
|
||||
{
|
||||
import flash.display.*;
|
||||
import flash.geom.*;
|
||||
import flash.net.*;
|
||||
import flash.events.*;
|
||||
import flash.text.*;
|
||||
import flash.xml.*;
|
||||
import flash.filters.*;
|
||||
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_sClassName:String;
|
||||
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;
|
||||
public var m_speed_y:Number = 0;
|
||||
public var m_bInDrag:Boolean = false;
|
||||
|
||||
public function GraphNode(oParent:Navigator, oPt:Point, sClass:String, sClassName:String, iId:Number, sLabel:String, sIconPath:String, sParentKey:String, fZoom:Number, oDetails:Object)
|
||||
{
|
||||
x = oPt.x;
|
||||
y = oPt.y;
|
||||
m_fZoom = fZoom;
|
||||
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;
|
||||
m_sLabel.width = m_sLabel.textWidth;
|
||||
m_sLabel.x = -m_sLabel.width/2;
|
||||
m_sLabel.height = m_sLabel.textHeight;
|
||||
// Draw the background
|
||||
graphics.beginFill( 0xf1f1f6, 0.8 );
|
||||
graphics.drawRoundRect( m_sLabel.x -PADDING, m_sLabel.y - PADDING, m_sLabel.width+PADDING*2, m_sLabel.height+PADDING*2, ROUND );
|
||||
graphics.endFill();
|
||||
|
||||
m_sParentKey = sParentKey;
|
||||
var sTooltipText:String = "<p><b>"+m_sClassName+"</b></p><p>"+sLabel+"</p>";
|
||||
for (var s:String in oDetails)
|
||||
{
|
||||
sTooltipText += '<p>'+s+': '+oDetails[s]+'</p>';
|
||||
}
|
||||
trace('Tooltip text: '+sTooltipText);
|
||||
m_oToolTip = new ToolTip(sTooltipText);
|
||||
m_oToolTip.scaleX = 1 / m_fZoom;
|
||||
m_oToolTip.scaleY = 1 / m_fZoom;
|
||||
m_oParent = oParent;
|
||||
|
||||
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);
|
||||
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 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;
|
||||
}
|
||||
|
||||
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);
|
||||
//hitArea = m_oIcon; // Drag only by the icon...
|
||||
trace('m_sLabel, getChildIndex:'+getChildIndex(m_sLabel));
|
||||
trace('m_oToolTip, getChildIndex:'+getChildIndex(m_oToolTip));
|
||||
trace('m_oIcon, getChildIndex:'+getChildIndex(m_oIcon));
|
||||
//swapChildren(m_oToolTip, );
|
||||
// Start the tooltip
|
||||
m_oToolTip.start();
|
||||
}
|
||||
|
||||
function mouseDown(event:MouseEvent):void
|
||||
{
|
||||
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;
|
||||
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();
|
||||
}
|
||||
|
||||
function mouseReleased(event:MouseEvent):void
|
||||
{
|
||||
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
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLabelWidth():Number
|
||||
{
|
||||
return m_sLabel.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,890 +0,0 @@
|
||||
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;
|
||||
// For callbacks from Javascript
|
||||
import flash.external.ExternalInterface;
|
||||
|
||||
// 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;
|
||||
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;
|
||||
protected var m_sExclude:String;
|
||||
|
||||
// Constants
|
||||
protected var m_RADIUS = 150;
|
||||
protected var m_Q = 0.9; // Electrostatic 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; // 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 = [];
|
||||
m_aNodes = [];
|
||||
m_sExclude = '';
|
||||
m_fZoom = 1;
|
||||
m_Ks = m_KsLowFriction;
|
||||
m_oLoader = null;
|
||||
initParameters();
|
||||
var success = true;
|
||||
if (ExternalInterface.available)
|
||||
{
|
||||
//Security.allowDomain(loader.contentLoaderInfo.url);
|
||||
//the addCallback registers a function to be called from javascript, and this is what you wanted to do:
|
||||
try
|
||||
{
|
||||
ExternalInterface.addCallback("Filter", DoFilter);
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
m_sTitle.text = 'E: '+err.description;
|
||||
success = false
|
||||
}
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
//m_sTitle.text = 'Ok...';
|
||||
doLoadData();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_sTitle.text = 'Failed to addCallback';
|
||||
}
|
||||
|
||||
addEventListener(Event.ENTER_FRAME, initGraphics);
|
||||
//Stop scaling the flash content
|
||||
stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
}
|
||||
|
||||
function Reset()
|
||||
{
|
||||
m_aLinks = [];
|
||||
for (var i:String in m_aNodes)
|
||||
{
|
||||
m_oCanvas.removeChild(m_aNodes[i]);
|
||||
}
|
||||
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
|
||||
{
|
||||
//do something
|
||||
m_sExclude = sExcludeList;
|
||||
doLoadData();
|
||||
}
|
||||
|
||||
protected function initParameters():void
|
||||
{
|
||||
|
||||
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');
|
||||
m_sObjId = ReadParam('obj_id', '7');
|
||||
m_sStartPosition = ReadParam('start_pos', 'left');
|
||||
}
|
||||
|
||||
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;
|
||||
m_oCanvas.scaleY = m_fZoom;
|
||||
// Handle listeners...
|
||||
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();
|
||||
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);
|
||||
}
|
||||
|
||||
function SetZoomLevel(fZoomLevel:Number):void
|
||||
{
|
||||
m_fZoom = fZoomLevel;
|
||||
m_oCanvas.scaleX = m_fZoom;
|
||||
m_oCanvas.scaleY = m_fZoom;
|
||||
}
|
||||
function GetZoomLevel()
|
||||
{
|
||||
return m_fZoom;
|
||||
}
|
||||
|
||||
function doLoadData()
|
||||
{
|
||||
m_sTitle.text = "Loading...";
|
||||
m_oPreloader.visible = true;
|
||||
m_oZoomSlider.enabled = true;
|
||||
var sSeparator:String = '?';
|
||||
if (m_sDataUrl.indexOf(sSeparator) != -1)
|
||||
{
|
||||
sSeparator = '&';
|
||||
}
|
||||
var myString:String = m_sDataUrl+sSeparator+'relation='+m_sRelation+'&class='+m_sObjClass+'&id='+m_sObjId+'&exclude='+m_sExclude;
|
||||
trace("Requesting:"+myString);
|
||||
var myXMLURL:URLRequest = new URLRequest(myString);
|
||||
if (m_oLoader != null)
|
||||
{
|
||||
m_oLoader.close();
|
||||
}
|
||||
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
|
||||
{
|
||||
try
|
||||
{
|
||||
Reset();
|
||||
var myXML:XML = XML(m_oLoader.data);
|
||||
//trace("Data loaded." + myXML);
|
||||
//trace("===========================");
|
||||
parseXMLData(null, myXML, 0, 0);
|
||||
m_sTitle.text = decodeEntities(myXML.attribute("title").toString());
|
||||
|
||||
|
||||
// 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();
|
||||
}
|
||||
catch(error:IOErrorEvent)
|
||||
{
|
||||
m_sTitle.text = "I/O Error: unable to load the graph data ("+error+")";
|
||||
}
|
||||
catch(error:TypeError)
|
||||
{
|
||||
m_sTitle.text = "Error: unable to load the graph data (Invalid XML data)";
|
||||
}
|
||||
catch(error:Error)
|
||||
{
|
||||
m_sTitle.text = "Error: unable to load the graph data ("+error+")";
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (m_oPreloader != null)
|
||||
{
|
||||
m_oPreloader.visible = false;
|
||||
}
|
||||
m_oZoomSlider.enabled = true;
|
||||
m_oVersion.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
function onXMLLoadError(event:IOErrorEvent):void
|
||||
{
|
||||
if (m_oPreloader != null)
|
||||
{
|
||||
m_oPreloader.visible = false;
|
||||
}
|
||||
m_sTitle.text = "I/O Error: unable to load the graph data ("+event+")";
|
||||
}
|
||||
|
||||
function parseXMLData(oParentNode:GraphNode, oXMLData:XML, iChildIndex:Number, iChildCount:Number)
|
||||
{
|
||||
//trace(oXMLData.child("node").length());
|
||||
var oNode:GraphNode;
|
||||
oNode = addNode(oParentNode, oXMLData.child("node")[0], iChildIndex, iChildCount);
|
||||
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, oLinks.link.length());
|
||||
iChildIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function decodeEntities(str: String)
|
||||
{
|
||||
return str.replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<').replace(/"/g, '"').replace(/'/g, "'");
|
||||
}
|
||||
|
||||
function addNode(oParent:GraphNode, oXMLData:XML, iChildIndex:Number, iChildCount:Number)
|
||||
{
|
||||
var sClass:String = oXMLData.@obj_class;
|
||||
var sClassName:String = oXMLData.@obj_class_name;
|
||||
var iId = oXMLData.@id;
|
||||
var sLabel:String = decodeEntities(oXMLData.@name);
|
||||
var sIcon:String = oXMLData.@icon;
|
||||
var oDetails:Object = {};
|
||||
var sZlist:String = oXMLData.@zlist;
|
||||
|
||||
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, iChildCount);
|
||||
var sParentKey = null;
|
||||
if (oParent != null)
|
||||
{
|
||||
sParentKey = oParent.GetKey();
|
||||
}
|
||||
// Read the details
|
||||
var aDetails:Array;
|
||||
aDetails = sZlist.split(',');
|
||||
for(var i:String in aDetails)
|
||||
{
|
||||
//if (oXMLData.hasOwnProperty('att_'+i))
|
||||
//{
|
||||
oDetails[aDetails[i]] = oXMLData.attribute('att_'+i).toString();
|
||||
//}
|
||||
}
|
||||
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;
|
||||
}
|
||||
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, iChildCount: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 nbItemsOnRow:Number = 0;
|
||||
var nbRows:Number = 0;
|
||||
// Determines the position of this element
|
||||
// The elements are placed on circles of maximum m_MAX_ITEMS_PER_ROW elements per row
|
||||
// The last row containing potentially less items
|
||||
// nbRows indicates on which row (first row = 0) the item is to be placed
|
||||
if (iChildCount > m_MAX_ITEMS_PER_ROW)
|
||||
{
|
||||
nbRows = Math.floor(iChildIndex / m_MAX_ITEMS_PER_ROW);
|
||||
if ( iChildIndex > (Math.floor(iChildCount / m_MAX_ITEMS_PER_ROW)*m_MAX_ITEMS_PER_ROW))
|
||||
{
|
||||
// node is on the last (incomplete) row
|
||||
nbItemsOnRow = (iChildCount % m_MAX_ITEMS_PER_ROW);
|
||||
}
|
||||
else
|
||||
{
|
||||
nbItemsOnRow = m_MAX_ITEMS_PER_ROW;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (iChildCount == 2)
|
||||
{
|
||||
nbItemsOnRow = 4; // Nicer display than everything aligned at 180 deg.
|
||||
}
|
||||
else
|
||||
{
|
||||
nbItemsOnRow = iChildCount;
|
||||
}
|
||||
}
|
||||
var radius = this.m_RADIUS * (1 + nbRows);
|
||||
angle += (1 - 2*((1+iChildIndex) % 2))*(Math.floor((1+iChildIndex) / 2))*(2*Math.PI) / nbItemsOnRow;
|
||||
|
||||
oPt.x += radius * Math.cos(angle);
|
||||
oPt.y += radius * 0.7 * Math.sin(angle); // Ellipse because the labels are written horizontally !
|
||||
|
||||
//trace("iChildIndex: "+iChildIndex+" (iChildCount: "+iChildCount+") 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
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
function drawArrow(oPt:Point, dx:Number, dy:Number, color:uint):void
|
||||
{
|
||||
var l:Number = Math.sqrt(dx*dx+dy*dy);
|
||||
var arrowSize:Number = 5;
|
||||
if (l > 0)
|
||||
{
|
||||
m_oCanvas.graphics.lineStyle(2,color,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;
|
||||
}
|
||||
}
|
||||
|
||||
public function ComputeElectrostaticForces():Array
|
||||
{
|
||||
var aForces:Array = [];
|
||||
//trace('====== BEGIN ComputeElectrostaticForces() =======');
|
||||
|
||||
for (var i:String in this.m_aNodes)
|
||||
{
|
||||
aForces[i] = new Object;
|
||||
aForces[i].FxTotal = 0;
|
||||
aForces[i].FyTotal = 0;
|
||||
var oCurrentNode:GraphNode = GetNode(i);
|
||||
for (var j:String in this.m_aNodes)
|
||||
{
|
||||
if (i != j)
|
||||
{
|
||||
var oRemoteNode:GraphNode = GetNode(j);
|
||||
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 Fx:Number = 0;
|
||||
var Fy:Number = 0;
|
||||
if (d2 < 0.05)
|
||||
{
|
||||
d2 = 0.05;
|
||||
}
|
||||
if (d2 < 2 ) // Full influence under 2 * m_RADIUS px
|
||||
{
|
||||
Fx = -this.m_Q * dx / d2;
|
||||
Fy = -this.m_Q * dy / d2;
|
||||
aForces[i].FxTotal += Fx;
|
||||
aForces[i].FyTotal += Fy;
|
||||
}
|
||||
else if (d2 < 4 ) // Decrease the influence to between 4 and 2 * m_RADIUS px
|
||||
{
|
||||
Fx = -this.m_Q * (4 - d2) * dx / d2;
|
||||
Fy = -this.m_Q * (4 - d2) * dy / d2;
|
||||
aForces[i].FxTotal += Fx;
|
||||
aForces[i].FyTotal += Fy;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//for (i in this.m_aNodes)
|
||||
//{
|
||||
// trace('ELECTROSTATIC forces on '+i+': Fx='+aForces[i].FxTotal+', Fy='+aForces[i].FyTotal);
|
||||
// if (Math.abs(aForces[i].FyTotal) > 1)
|
||||
// {
|
||||
// for (i in this.m_aNodes)
|
||||
// {
|
||||
// var oNode:GraphNode = GetNode(i);
|
||||
// trace('node: '+i+' (x='+oNode.x+', y='+oNode.y+')');
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//trace('====== END ComputeElectrostaticForces() =======');
|
||||
return aForces;
|
||||
}
|
||||
|
||||
|
||||
function ComputeElasticForces()
|
||||
{
|
||||
//trace('====== BEGIN ComputeElasticForces() =======');
|
||||
var aForces:Array = [];
|
||||
|
||||
for (var i:String in this.m_aNodes)
|
||||
{
|
||||
aForces[i] = new Object;
|
||||
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;
|
||||
var dy = oStartNode.y - oEndNode.y;
|
||||
//d = Math.sqrt(dx*dx + dy*dy);
|
||||
//Fx = -K * d * dx / d;
|
||||
//Fy = -K * d * dy / d;
|
||||
//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;
|
||||
aForces[oEndNode.GetKey()].FyTotal -= Fy;
|
||||
}
|
||||
//for (i in this.m_aNodes)
|
||||
//{
|
||||
// trace('Elastic forces on '+i+': Fx='+aForces[i].FxTotal+', Fy='+aForces[i].FyTotal);
|
||||
// if (Math.abs(aForces[i].FyTotal) > 1)
|
||||
// {
|
||||
// for (i in this.m_aNodes)
|
||||
// {
|
||||
// var oNode:GraphNode = GetNode(i);
|
||||
// trace('node: '+i+' (x='+oNode.x+', y='+oNode.y+')');
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//trace('====== END ComputeElasticForces() =======');
|
||||
return aForces;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the nodes' position based on their current movement and the forces applied
|
||||
*/
|
||||
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();
|
||||
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);
|
||||
if (!oNode.m_bInDrag)
|
||||
{
|
||||
var Fx:Number = aElasticForces[i].FxTotal + aElectrostaticForces[i].FxTotal;
|
||||
var Fy:Number = aElasticForces[i].FyTotal + aElectrostaticForces[i].FyTotal;
|
||||
|
||||
if ( (Fx*Fx + Fy*Fy) < (this.m_Ks*this.m_Ks))
|
||||
{
|
||||
// Movement is less than minimum level (solid friction) => object is stopped
|
||||
// otherwise let's keep it moving
|
||||
oNode.m_speed_x = 0;
|
||||
oNode.m_speed_y = 0;
|
||||
//trace('object '+i+' stopped ! (x='+oNode.x+', y='+oNode.y+')');
|
||||
}
|
||||
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: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() =======');
|
||||
}
|
||||
|
||||
public function DrawForces(aForces:Array, color:uint)
|
||||
{
|
||||
for (var i:String in aForces)
|
||||
{
|
||||
var oNode:GraphNode = GetNode(i);
|
||||
var oForce:Object = aForces[i];
|
||||
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 = 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+')');
|
||||
}
|
||||
}
|
||||
|
||||
public function UpdatePanAndZoom(countDownRatio:Number)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var idealZoomLevel:Number = 1;
|
||||
trace('Stage dimensions: width:'+stage.stageWidth+' height:'+stage.stageHeight);
|
||||
|
||||
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 = 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);
|
||||
}
|
||||
}
|
||||
|
||||
public function DumpPositions()
|
||||
{
|
||||
for (var i:String in this.m_aNodes)
|
||||
{
|
||||
var oNode:GraphNode = GetNode(i);
|
||||
trace(i+' Position: (x='+oNode.x+', y='+oNode.y+')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
package iTop
|
||||
{
|
||||
import flash.display.*;
|
||||
import flash.geom.*;
|
||||
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 = 10;
|
||||
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.0;
|
||||
private static const ALPHA_INC:Number = 0.1;
|
||||
private static const MAX_ALPHA:Number = 1;
|
||||
private static const REFRESH:Number = (MAX_ALPHA - MIN_ALPHA) / ALPHA_INC;
|
||||
private static const APPEAR_TIMEOUT = 1000; // ms
|
||||
// For appearence, fading in and out
|
||||
public 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( 0xEEEE99, 0.95 );
|
||||
graphics.drawRoundRect( 0, 0, _tf.textWidth+PADDING*4, _tf.textHeight+PADDING*4, ROUND );
|
||||
graphics.endFill();
|
||||
this.alpha = MIN_ALPHA;
|
||||
this.visible = false;
|
||||
}
|
||||
// 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
|
||||
{
|
||||
// Make the tooltip appear smoothly after a delay
|
||||
if (this.timer != null)
|
||||
{
|
||||
this.timer.stop();
|
||||
}
|
||||
this.timer = new Timer( APPEAR_TIMEOUT, 1 );
|
||||
this.timer.addEventListener( "timer", appear );
|
||||
this.timer.start();
|
||||
this.parent.addEventListener( MouseEvent.MOUSE_OUT, mouse_out );
|
||||
}
|
||||
public function mouse_out( e:MouseEvent ):void
|
||||
{
|
||||
var fadeSpeed:Number = 500 / REFRESH;
|
||||
if (this.timer != null)
|
||||
{
|
||||
this.timer.stop();
|
||||
}
|
||||
this.timer = new Timer( fadeSpeed, REFRESH );
|
||||
this.timer.addEventListener( "timer", fadeOut );
|
||||
this.timer.start();
|
||||
this.parent.removeEventListener( MouseEvent.MOUSE_OUT, mouse_out );
|
||||
}
|
||||
|
||||
private function appear(i:uint):void
|
||||
{
|
||||
// The delay has elapsed, show (smoothly) the tooltip
|
||||
// Make sure that the tooltip always appears at se same scale 1:1 even
|
||||
// if the whole scene is zoomed out
|
||||
scaleX = 1 / this.parent.parent.scaleX;
|
||||
scaleY = 1 / this.parent.parent.scaleY;
|
||||
if (this.timer != null)
|
||||
{
|
||||
this.timer.stop();
|
||||
}
|
||||
// Reuse the time for the fadeIn
|
||||
this.parent.setChildIndex( this, this.parent.numChildren-1 )
|
||||
// Move the tool tip to the top!
|
||||
var fadeSpeed:Number = 500 / REFRESH;
|
||||
this.alpha = MIN_ALPHA;
|
||||
if (this.timer != null)
|
||||
{
|
||||
this.timer.stop();
|
||||
}
|
||||
this.timer = new Timer( fadeSpeed, REFRESH );
|
||||
this.timer.addEventListener( "timer", fadeIn );
|
||||
this.timer.start();
|
||||
this.parent.addEventListener( MouseEvent.MOUSE_OUT, mouse_out );
|
||||
}
|
||||
|
||||
private function fadeIn( i:uint ):void
|
||||
{
|
||||
this.visible = true;
|
||||
if (this.alpha < (1.0 - ALPHA_INC))
|
||||
{
|
||||
this.alpha += ALPHA_INC;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.alpha = 1.0;
|
||||
}
|
||||
//trace("++ Tooltip alpha: "+this.alpha+" ALPHA_INC:"+ALPHA_INC);
|
||||
}
|
||||
private function fadeOut( i:uint ):void
|
||||
{
|
||||
if (this.alpha > ALPHA_INC)
|
||||
{
|
||||
this.alpha -= ALPHA_INC;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.alpha = 0.0;
|
||||
this.visible = false;
|
||||
}
|
||||
//trace("-- Tooltip alpha: "+this.alpha+" ALPHA_INC:"+ALPHA_INC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,701 +0,0 @@
|
||||
var TEST_MODE = 0;
|
||||
|
||||
if (TEST_MODE == 1)
|
||||
{
|
||||
var root_object_id = 11;
|
||||
var root_object_class = "bizPC";
|
||||
var root_relation = "neighboors";
|
||||
var xml_document_url = "http://localhost:81/pages/xml.navigator.php";
|
||||
var details_url = "http://localhost:81/pages/UI.php?operation=details";
|
||||
}
|
||||
else
|
||||
{
|
||||
var root_object_id = obj_id; // 11;
|
||||
var root_object_class = obj_class; // "bizPC";
|
||||
var root_relation = relation; // "neighboors";
|
||||
var xml_document_url = unescape(xmlUrl); // "http://localhost:81/pages/xml.navigator.php";
|
||||
var details_url = unescape(drillUrl); // "http://localhost:81/pages/UI.php?operation=details";
|
||||
}
|
||||
if (pWidth == undefined)
|
||||
{
|
||||
pWidth = 800;
|
||||
}
|
||||
if (pHeight == undefined)
|
||||
{
|
||||
pHeight = 800;
|
||||
}
|
||||
var K = 0; //0.02; // elasticity coeff
|
||||
var Q = 0; // Normally each element may have a specific "charge"
|
||||
var deltaT = 1; // delta time
|
||||
var solidFriction = 10;
|
||||
var radius = 25;
|
||||
if (customRadius != undefined)
|
||||
{
|
||||
radius = customRadius;
|
||||
}
|
||||
if (displayController != 'true')
|
||||
{
|
||||
_level0.Controller._x = -1000; // Make it invisible
|
||||
}
|
||||
var M = 1; // Mass of the object
|
||||
var frictionCoeff = 0.9; // Friction coefficient
|
||||
var bDrawForces = false;
|
||||
var aXPos = new Array;
|
||||
var aYPos = new Array;
|
||||
var aClips = new Array;
|
||||
var aLinks = new Array;
|
||||
var aWeights = new Array;
|
||||
|
||||
var oItemsContextMenu = new ContextMenu();
|
||||
oItemsContextMenu.hideBuiltInItems();
|
||||
var menuItem = new ContextMenuItem ("Details...", DisplayObjectDetails);
|
||||
var menuItem2 = new ContextMenuItem ("Expand", Expand);
|
||||
var menuItem3 = new ContextMenuItem ("Drill down", DrillDown);
|
||||
|
||||
function DisplayObjectDetails(oSelectedObject)
|
||||
{
|
||||
// Called by the context menu
|
||||
var fullUrl:String = details_url;
|
||||
if (fullUrl.indexOf("?",0) > 0)
|
||||
{
|
||||
fullUrl = fullUrl+"&class="+oSelectedObject.obj_class+"&id="+oSelectedObject.id;
|
||||
}
|
||||
else
|
||||
{
|
||||
fullUrl = fullUrl+"?class="+oSelectedObject.obj_class+"&id="+oSelectedObject.id;
|
||||
}
|
||||
getURL(fullUrl, "_top");
|
||||
}
|
||||
|
||||
function DrillDown(oSelectedObject)
|
||||
{
|
||||
DoReload(oSelectedObject.id, oSelectedObject.obj_class, root_relation);
|
||||
}
|
||||
|
||||
function Expand(oSelectedObject)
|
||||
{
|
||||
DoLoad(oSelectedObject.id, oSelectedObject.obj_class, root_relation);
|
||||
}
|
||||
|
||||
oItemsContextMenu.customItems.push(menuItem, menuItem2, menuItem3);
|
||||
|
||||
function DrawLinks()
|
||||
{
|
||||
oLinksMovie = _root.links;
|
||||
oLinksMovie.clear();
|
||||
oLinksMovie.lineStyle (5, 0xcccccc, 100);
|
||||
for(i=0; i<aLinks.length; i++)
|
||||
{
|
||||
x1 = aClips[aLinks[i].start]._x;
|
||||
y1 = aClips[aLinks[i].start]._y;
|
||||
x2 = aClips[aLinks[i].end]._x;
|
||||
y2 = aClips[aLinks[i].end]._y;
|
||||
dx = x2 -x1;
|
||||
dy = y2 - y1;
|
||||
l = Math.sqrt( dx*dx + dy*dy);
|
||||
|
||||
//trace("Linking item "+aLinks[i].start+" to item "+aLinks[i].end+"; Line from: ("+x1+", "+y1+") to ("+x2+", "+y2+")");
|
||||
oLinksMovie.moveTo(x1, y1);
|
||||
oLinksMovie.lineTo(x2, y2);
|
||||
if (aLinks[i].bArrow)
|
||||
{
|
||||
dx = x2 -x1;
|
||||
dy = y2 - y1;
|
||||
l = Math.sqrt( dx*dx + dy*dy);
|
||||
x_mid = (x1+x2) / 2;
|
||||
y_mid = (y1+y2) / 2;
|
||||
oLinksMovie.lineStyle (3, 0x999999, 100);
|
||||
oLinksMovie.moveTo(x_mid, y_mid);
|
||||
oLinksMovie.lineTo(x_mid + 5*(dy-dx)/l, y_mid-5*(dx+dy)/l);
|
||||
oLinksMovie.moveTo(x_mid, y_mid);
|
||||
oLinksMovie.lineTo(x_mid - 5*(dx+dy)/l, y_mid-5*(dy-dx)/l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function ComputeElasticForces()
|
||||
{
|
||||
var aForces = new Array;
|
||||
|
||||
for(var i=0; i<aClips.length; i++)
|
||||
{
|
||||
aForces[i] = new Object;
|
||||
aForces[i].FxTotal = 0;
|
||||
aForces[i].FyTotal = 0;
|
||||
}
|
||||
// Elastic forces: each link applies a force proportional to its length (F = - K * x)
|
||||
for(var l=0; l<aLinks.length; l++)
|
||||
{
|
||||
dx = aClips[aLinks[l].start]._x - aClips[aLinks[l].end]._x;
|
||||
dy = aClips[aLinks[l].start]._y - aClips[aLinks[l].end]._y;
|
||||
//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;
|
||||
Fx = -K * weightCoeff * dx;
|
||||
Fy = -K * weightCoeff * dy;
|
||||
aForces[aLinks[l].start].FxTotal += Fx;
|
||||
aForces[aLinks[l].start].FyTotal += Fy;
|
||||
aForces[aLinks[l].end].FxTotal -= Fx;
|
||||
aForces[aLinks[l].end].FyTotal -= Fy;
|
||||
}
|
||||
return aForces;
|
||||
}
|
||||
|
||||
function ComputeElectrostaticForces()
|
||||
{
|
||||
aForces = new Array;
|
||||
|
||||
for(var i=0; i<aClips.length; i++)
|
||||
{
|
||||
aForces[i] = new Object;
|
||||
aForces[i].FxTotal = 0;
|
||||
aForces[i].FyTotal = 0;
|
||||
}
|
||||
// Each items applies a force to all the others, in proportion to the inverse of the square
|
||||
// of their distance: (F = Q / x2)
|
||||
for (var i=0; i<aClips.length; i++)
|
||||
{
|
||||
for(var j=0; j<aClips.length; j++)
|
||||
{
|
||||
if (i != j) // no force on itself !!
|
||||
{
|
||||
dx = aClips[i]._x - aClips[j]._x;
|
||||
dy = aClips[i]._y - aClips[j]._y;
|
||||
d2 = (dx*dx + dy*dy) / (radius * radius);
|
||||
d = Math.sqrt(d2);
|
||||
if (d2 < 0.05)
|
||||
{
|
||||
d2 = 0.05;
|
||||
}
|
||||
Fx = Q * dx / d2;
|
||||
Fy = Q * dy / d2;
|
||||
aForces[i].FxTotal += Fx;
|
||||
aForces[i].FyTotal += Fy;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return aForces;
|
||||
}
|
||||
|
||||
function DrawForces()
|
||||
{
|
||||
oForcesMovie.clear();
|
||||
oForcesMovie = _root.forces;
|
||||
|
||||
// Draw elastic forces in red
|
||||
oForcesMovie.lineStyle (1, 0xff0000, 100);
|
||||
aElasticForces = ComputeElasticForces();
|
||||
DrawForcesVectors(aElasticForces);
|
||||
|
||||
// Draw electrostatic forces in blue
|
||||
oForcesMovie.lineStyle (1, 0x0000ff, 100);
|
||||
aElectrostaticForces = ComputeElectrostaticForces();
|
||||
DrawForcesVectors(aElectrostaticForces);
|
||||
|
||||
// Compute resulting forces and draw them (in green)
|
||||
aForces = new Array;
|
||||
for(var i=0; i<aClips.length; i++)
|
||||
{
|
||||
aForces[i] = new Object;
|
||||
aForces[i].FxTotal = aElasticForces[i].FxTotal + aElectrostaticForces[i].FxTotal;
|
||||
aForces[i].FyTotal = aElasticForces[i].FyTotal + aElectrostaticForces[i].FyTotal;
|
||||
|
||||
Vx = frictionCoeff*(aClips[i].Vx + aForces[i].FxTotal / M * deltaT);
|
||||
Vy = frictionCoeff*(aClips[i].Vy + aForces[i].FyTotal / M * deltaT);
|
||||
V = Math.sqrt(Vx*Vx + Vy*Vy);
|
||||
if (V < solidFriction)
|
||||
{
|
||||
c = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = (V - solidFriction) / V;
|
||||
}
|
||||
aClips[i].Vx = c * Vx;
|
||||
aClips[i].Vy = c * Vy;
|
||||
}
|
||||
oForcesMovie.lineStyle (2, 0x00ff00, 100);
|
||||
DrawForcesVectors(aForces);
|
||||
UpdatePositions();
|
||||
}
|
||||
|
||||
function DrawForcesVectors(aForces)
|
||||
{
|
||||
if (bDrawForces)
|
||||
{
|
||||
for(var i=0; i<aClips.length; i++)
|
||||
{
|
||||
oForcesMovie.moveTo(aClips[i]._x, aClips[i]._y);
|
||||
//trace("Resulting force on item"+i+": ("+aForces[i].FxTotal+", "+aForces[i].FyTotal+").");
|
||||
Fx = aForces[i].FxTotal;
|
||||
Fy = aForces[i].FyTotal;
|
||||
strengh = Math.sqrt(Fx*Fx + Fy*Fy);
|
||||
if (strengh > 1) // if less than 1 pixel, don't draw it
|
||||
{
|
||||
// Draw the arrow: main line
|
||||
oForcesMovie.lineTo(aClips[i]._x + Fx, aClips[i]._y + Fy);
|
||||
// Head of the arrow
|
||||
oForcesMovie.lineTo(aClips[i]._x + Fx + 5*(Fy-Fx)/strengh, aClips[i]._y + Fy - 5*(Fx+Fy)/strengh);
|
||||
oForcesMovie.moveTo(aClips[i]._x + Fx, aClips[i]._y + Fy);
|
||||
// Head of the arrow
|
||||
oForcesMovie.lineTo(aClips[i]._x + Fx - 5*(Fx+Fy)/strengh, aClips[i]._y + Fy - 5*(Fy-Fx)/strengh);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function DrawItems()
|
||||
{
|
||||
aForces = ComputeForces();
|
||||
DrawLinks(true);
|
||||
DrawForces(aForces);
|
||||
}
|
||||
|
||||
function DoStartDrag()
|
||||
{
|
||||
this.bInDrag = true;
|
||||
if (this.iTimeout != 0)
|
||||
{
|
||||
clearTimeout(this.iTimeout);
|
||||
this.iTimeout = 0;
|
||||
}
|
||||
this.startDrag()
|
||||
}
|
||||
|
||||
|
||||
function DoReleaseDrag()
|
||||
{
|
||||
this.stopDrag();
|
||||
this.bInDrag = false;
|
||||
if (this.lastclick - (this.lastclick=getTimer()) + 250 > 0)
|
||||
{
|
||||
//do doubleclick action
|
||||
trace("double");
|
||||
DoReload(this.id, this.obj_class);
|
||||
}
|
||||
else
|
||||
{
|
||||
//do singleclick action
|
||||
trace("single");
|
||||
}
|
||||
}
|
||||
|
||||
function DoRollOver()
|
||||
{
|
||||
trace("Roll Over: "+this.name);
|
||||
var iTimeOut:Number;
|
||||
iTimeout = setTimeout(ShowTooltip, 500, this);
|
||||
this.iTimeout = iTimeout;
|
||||
}
|
||||
|
||||
function DoRollOut()
|
||||
{
|
||||
trace("Roll Out");
|
||||
if (this.iTimeout != 0)
|
||||
{
|
||||
clearTimeout(this.iTimeout);
|
||||
this.iTimeout = 0;
|
||||
}
|
||||
HideTooltip();
|
||||
}
|
||||
|
||||
function UpdatePositions()
|
||||
{
|
||||
var MIN_MOVE_LIMIT = 0.3; // Whatever moves of less than 0.3 px per cycle, remains frozen to spare some CPU
|
||||
for(var i=0; i<aClips.length; i++)
|
||||
{
|
||||
if (!aClips[i].bInDrag)
|
||||
{
|
||||
//trace("Speed: ("+aClips[i].Vx+", "+aClips[i].Vy+")");
|
||||
if ( (Math.abs(aClips[i].Vx * deltaT) > MIN_MOVE_LIMIT) || (Math.abs(aClips[i].Vy * deltaT) > MIN_MOVE_LIMIT) )
|
||||
{
|
||||
aClips[i]._x += aClips[i].Vx * deltaT;
|
||||
aClips[i]._y += aClips[i].Vy * deltaT;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function CreateItem(id, obj_class, icon, name, x, y, parentId, oNodeDetails)
|
||||
{
|
||||
trace("CreateItem(id:"+id+" , parentId:"+parentId+")");
|
||||
var i = aClips.length; // Add new elements at the end of the array
|
||||
var sMovieName;
|
||||
switch (icon)
|
||||
{
|
||||
case "application":
|
||||
sMovieName = "Item_application";
|
||||
break;
|
||||
|
||||
case "business_process":
|
||||
sMovieName = "Item_business_process";
|
||||
break;
|
||||
|
||||
case "chemicals":
|
||||
sMovieName = "Item_chemicals";
|
||||
break;
|
||||
|
||||
case "contact":
|
||||
sMovieName = "Item_contact";
|
||||
break;
|
||||
|
||||
case "contract":
|
||||
sMovieName = "Item_contract";
|
||||
break;
|
||||
|
||||
case "change":
|
||||
sMovieName = "Item_change";
|
||||
break;
|
||||
|
||||
case "database":
|
||||
sMovieName = "Item_database";
|
||||
break;
|
||||
|
||||
case "db_instance":
|
||||
sMovieName = "Item_db_instance";
|
||||
break;
|
||||
|
||||
case "desktop":
|
||||
sMovieName = "Item_dekstop";
|
||||
break;
|
||||
|
||||
case "incident":
|
||||
sMovieName = "Item_incident";
|
||||
break;
|
||||
|
||||
case "interface":
|
||||
sMovieName = "Item_interface";
|
||||
break;
|
||||
|
||||
case "laptop":
|
||||
sMovieName = "Item_laptop";
|
||||
break;
|
||||
|
||||
case "network_device":
|
||||
sMovieName = "Item_nw_device";
|
||||
break;
|
||||
|
||||
case "printer":
|
||||
sMovieName = "Item_printer";
|
||||
break;
|
||||
|
||||
case "server":
|
||||
sMovieName = "Item_server";
|
||||
break;
|
||||
|
||||
case "wireless_device":
|
||||
sMovieName = "Item_wireless_device";
|
||||
break;
|
||||
|
||||
default:
|
||||
sMovieName = "Item";
|
||||
}
|
||||
aClips[i]= _root.links.attachMovie(sMovieName, "r"+i, i+10);
|
||||
aClips[i]._x= x;
|
||||
aClips[i]._y= y;
|
||||
aClips[i].parentId = parentId;
|
||||
aClips[i].details = oNodeDetails;
|
||||
aClips[i]._xscale = radius;
|
||||
aClips[i]._yscale = radius;
|
||||
aClips[i].onPress = DoStartDrag;
|
||||
aClips[i].onRelease = DoReleaseDrag;
|
||||
aClips[i].onRollOver = DoRollOver;
|
||||
aClips[i].onRollOut = DoRollOut;
|
||||
aClips[i].Vx = 0; // No inital speed
|
||||
aClips[i].Vy = 0; // No inital speed
|
||||
aClips[i].bInDrag = false;
|
||||
aClips[i].id = id;
|
||||
aClips[i].icon = icon;
|
||||
aClips[i].name = name;
|
||||
aClips[i].obj_class = obj_class;
|
||||
aClips[i].menu = oItemsContextMenu;
|
||||
aWeights[i] = 1;
|
||||
trace("Element added: index="+i+", id="+id+", obj_class="+id+", obj_class="+name+", icon="+icon+newline+"details: "+aClips[i].details.values);
|
||||
return i;
|
||||
}
|
||||
|
||||
function GetParentAngle(oClip:MovieClip)
|
||||
{
|
||||
var angle:Number = 0;
|
||||
|
||||
trace("GetParentAngle oClip.parentId: "+oClip.parentId);
|
||||
if (oClip.parentId != undefined)
|
||||
{
|
||||
oParentClip = aClips[oClip.parentId];
|
||||
dx = oClip._x - oParentClip._x;
|
||||
dy = oClip._y - oParentClip._y;
|
||||
trace("GetParentAngle dx: "+dx+", dy:"+dy);
|
||||
if ((dx == 0) && (dy == 0))
|
||||
{
|
||||
angle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = Math.atan2(dy, dx);
|
||||
}
|
||||
}
|
||||
trace("GetParentAngle returned: "+((angle*360)/(2*Math.PI)));
|
||||
return angle;
|
||||
}
|
||||
|
||||
function FindItemByIdAndClass(id, obj_class)
|
||||
{
|
||||
var result = -1;
|
||||
var i = 0;
|
||||
while ( (i < aClips.length) && (result == -1))
|
||||
{
|
||||
if ((aClips[i].id == id) && (aClips[i].obj_class == obj_class))
|
||||
{
|
||||
result = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function AddLink(sourceIndex, destinationIndex, bArrow)
|
||||
{
|
||||
trace("Adding link between srcIndex:"+sourceIndex+" and destIndex:"+destinationIndex+" (arrow:"+bArrow+" )");
|
||||
aLinks[aLinks.length] = { start: sourceIndex, end: destinationIndex, bArrow: bArrow };
|
||||
}
|
||||
|
||||
oLinksMovie = _root.createEmptyMovieClip ("links", -1);
|
||||
oForcesMovie = _root.createEmptyMovieClip ("forces", 9999);
|
||||
oLinksMovie.onEnterFrame = DrawItems;
|
||||
oForcesMovie.onEnterFrame = DrawForces;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Experimenting with the load of an XML file
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Create a new XML object.
|
||||
var myLoader:XML = new XML();
|
||||
|
||||
// Set the ignoreWhite property to true (default value is false).
|
||||
myLoader.ignoreWhite = true;
|
||||
|
||||
// After loading is complete, trace the XML object.
|
||||
myLoader.onLoad = function(success)
|
||||
{
|
||||
DumpClips("Beginning of (asynchronous) load");
|
||||
if (success)
|
||||
{
|
||||
myXML = new XML();
|
||||
myXML.parseXML(myLoader);
|
||||
oRootNode = myXML.firstChild;
|
||||
trace("root node: "+oRootNode.nodeName);
|
||||
if (oRootNode.attributes.title != undefined)
|
||||
{
|
||||
StaticContainer.Schema_title = oRootNode.attributes.title;
|
||||
}
|
||||
else
|
||||
{
|
||||
StaticContainer.Schema_title = "";
|
||||
}
|
||||
oFirstNode = oRootNode.firstChild;
|
||||
oStartPoint = {x:0, y:0};
|
||||
var placement = "";
|
||||
switch (oRootNode.attributes.position)
|
||||
{
|
||||
case "top":
|
||||
oStartPoint.x = pWidth/2;
|
||||
oStartPoint.y = 2*radius;
|
||||
break;
|
||||
|
||||
case "left":
|
||||
oStartPoint.x = 2*radius;
|
||||
oStartPoint.y = pHeight/2;
|
||||
break;
|
||||
|
||||
case "center":
|
||||
default:
|
||||
oStartPoint.x = pWidth /2;
|
||||
oStartPoint.y = pHeight /2;
|
||||
placement = "surround";
|
||||
}
|
||||
LoadNode(oFirstNode, undefined, oStartPoint.x, oStartPoint.y, placement);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace("Failed to load XML data:"+newline+myLoader);
|
||||
}
|
||||
_level0.LoadingAnimation._alpha = 0;
|
||||
_level0.LoadingAnimation.stop();
|
||||
DumpClips("End of (asynchronous) load");
|
||||
}
|
||||
|
||||
function LoadNode(oXmlNode:Object, parentIndex:Number, x:Number, y:Number, placementMethod:String)
|
||||
{
|
||||
trace("Loading Node: "+oXmlNode);
|
||||
|
||||
var nodeId = oXmlNode.attributes.id;
|
||||
var nodeClass = oXmlNode.attributes.obj_class;
|
||||
var nodeName = oXmlNode.attributes.name;
|
||||
var nodeIcon = oXmlNode.attributes.icon;
|
||||
var nodeIndex = FindItemByIdAndClass(nodeId, nodeClass);
|
||||
var nodeZlist = oXmlNode.attributes.zlist;
|
||||
var aNodeZlist = nodeZlist.split(',');
|
||||
var oNodeDetails = { names: new Array(), values: new Array() };
|
||||
for(var att_index=0; att_index<aNodeZlist.length; att_index++)
|
||||
{
|
||||
oNodeDetails.names[att_index] = aNodeZlist[att_index];
|
||||
oNodeDetails.values[att_index] = eval("oXmlNode.attributes.att_"+att_index);
|
||||
}
|
||||
trace("ZList:"+nodeZlist);
|
||||
trace("oNodeDetails.values:"+oNodeDetails.values);
|
||||
oXmlNode.attributes.zlist;
|
||||
if (nodeIndex == -1)
|
||||
{
|
||||
nodeIndex = CreateItem(nodeId, nodeClass, nodeIcon, nodeName, x, y, parentIndex, oNodeDetails);
|
||||
trace("Node inserted: nodeIndex = "+nodeIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
trace("Node (id:"+nodeId+" , class:"+nodeClass+", name:"+nodeName+" ) already loaded...");
|
||||
placementMethod = "";
|
||||
}
|
||||
var oLinks = oXmlNode.firstChild;
|
||||
trace("oLinks: "+oLink);
|
||||
if (oLinks != undefined)
|
||||
{
|
||||
var iCount:Number = 0;
|
||||
for(var i=0; i<oLinks.childNodes.length; i++)
|
||||
{
|
||||
var oCurrentLink = oLinks.childNodes[i];
|
||||
var arrow = oCurrentLink.attributes.arrow;
|
||||
trace(oCurrentLink.nodeName);
|
||||
|
||||
var oChildNode = oCurrentLink.firstChild;
|
||||
var childId = oChildNode.attributes.id;
|
||||
var childClass = oChildNode.attributes.obj_class;
|
||||
var childIndex = FindItemByIdAndClass(childId, childClass);
|
||||
var oChildPt:Object;
|
||||
if (placementMethod == 'surround')
|
||||
{
|
||||
angle = 2*Math.PI / (oLinks.childNodes.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
angle = Math.PI / 8;
|
||||
}
|
||||
if (childIndex == -1)
|
||||
{
|
||||
trace("Placing child: id:"+chidlId+", class:"+childClass+", name:"+childName);
|
||||
oChildPt = PlaceChild(aClips[nodeIndex], iCount, angle);
|
||||
iCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
oChildPt.x = aClips[childIndex]._x;
|
||||
oChildPt.y = aClips[childIndex]._y;
|
||||
}
|
||||
trace("iCount: "+iCount);
|
||||
trace("============= DOWN ONE LEVEL ==============");
|
||||
childIndex = LoadNode(oChildNode, nodeIndex, oChildPt.x, oChildPt.y);
|
||||
trace("============= UP ONE LEVEL ==============");
|
||||
AddLink(nodeIndex, childIndex, arrow /* bArrow */);
|
||||
}
|
||||
}
|
||||
return nodeIndex;
|
||||
}
|
||||
|
||||
function DoReload(id, obj_class, relation)
|
||||
{
|
||||
_level0.LoadingAnimation.gotoAndPlay(1);
|
||||
_level0.LoadingAnimation._alpha = 35;
|
||||
trace("Reloading for id = "+id+", obj_class = "+obj_class);
|
||||
var icon = "";
|
||||
var name = ""
|
||||
var oDetails = {};
|
||||
for (var i=0; i < aClips.length; i++)
|
||||
{
|
||||
if ( (aClips[i].id == id) && (aClips[i].obj_class == obj_class) )
|
||||
{
|
||||
icon = aClips[i].icon;
|
||||
name = aClips[i].name;
|
||||
oDetails = aClips[i].details;
|
||||
}
|
||||
aClips[i].removeMovieClip();
|
||||
}
|
||||
aClips = new Array;
|
||||
aLinks = new Array;
|
||||
aWeights = new Array;
|
||||
DumpClips("Before recreating any item");
|
||||
CreateItem(id, obj_class, icon, name, 100, 400, undefined, oDetails); // Re-create the root node
|
||||
DumpClips("After creating the first item");
|
||||
var sLoadUrl = xml_document_url+"?class="+obj_class+"&id="+id+"&relation="+relation;
|
||||
trace("Reloading from: "+sLoadUrl);
|
||||
myLoader.load(sLoadUrl); // Load the rest of the items
|
||||
}
|
||||
|
||||
function DoLoad(id, obj_class, relation)
|
||||
{
|
||||
_level0.LoadingAnimation.gotoAndPlay(1);
|
||||
_level0.LoadingAnimation._alpha = 35;
|
||||
trace("Expanding id = "+id+", obj_class = "+obj_class);
|
||||
var sLoadUrl = xml_document_url+"?class="+obj_class+"&id="+id+"&relation="+relation;
|
||||
trace("Loading from: "+sLoadUrl);
|
||||
myLoader.load(sLoadUrl); // Load the rest of the items
|
||||
}
|
||||
|
||||
function PlaceChild(oClip:MovieClip, iChildIndex:Number, deltaAngle)
|
||||
{
|
||||
var angle:Number = GetParentAngle(oClip) + GetAngle(iChildIndex, deltaAngle);
|
||||
x = oClip._x + 7*radius*Math.cos(angle);
|
||||
y = oClip._y + 7*radius*Math.sin(angle);
|
||||
|
||||
trace("Child "+iChildIndex+", angle: "+(angle*360/(2*Math.PI))+" placed at { x: " +x+", y: "+y+" }");
|
||||
return { x:x, y:y, angle: angle };
|
||||
}
|
||||
|
||||
function GetAngle(iChildIndex:Number, deltaAngle)
|
||||
{
|
||||
return (1-2*(iChildIndex % 2))*Math.floor( (iChildIndex+1) / 2) * deltaAngle;
|
||||
}
|
||||
|
||||
function DumpClips(message)
|
||||
{
|
||||
trace("******** aClips - "+message+" **********");
|
||||
for (var i=0; i<aClips.length; i++)
|
||||
{
|
||||
trace("aClips["+i+"] = { id: "+aClips[i].id+", obj_class: "+aClips[i].obj_class+", name: "+aClips[i].name+", type: "+aClips[i].type+" }");
|
||||
}
|
||||
trace("*************************");
|
||||
}
|
||||
|
||||
function ShowTooltip(oClip)
|
||||
{
|
||||
// Show the Tooltip next to the mouse cursor
|
||||
var mouse_point:Object = {x:oClip._xmouse, y:oClip._ymouse};
|
||||
oClip.localToGlobal(mouse_point);
|
||||
Tooltip_movie._x = mouse_point.x;
|
||||
Tooltip_movie._y = mouse_point.y;
|
||||
Tooltip_movie._alpha = 60;
|
||||
Tooltip_movie.oldDepth = Tooltip_movie.getDepth();
|
||||
Tooltip_movie.swapDepths(999);
|
||||
Tooltip_movie._visible = true;
|
||||
trace(Tooltip_movie.Properties_grid);
|
||||
for(var index = 0; index <50; index++)
|
||||
{
|
||||
Tooltip_movie.Properties_grid.removeItemAt(0);
|
||||
}
|
||||
trace("Clips details: "+oClip.details.names);
|
||||
for(var index = 0; index <oClip.details.names.length; index++)
|
||||
{
|
||||
Tooltip_movie.Properties_grid.addItem({Name: oClip.details.names[index], Value: oClip.details.values[index]});
|
||||
}
|
||||
Tooltip_movie.Properties_grid.spaceColumnsEqually();
|
||||
oClip.iTimeout = 0;
|
||||
}
|
||||
|
||||
function HideTooltip()
|
||||
{
|
||||
Tooltip_movie._visible = false;
|
||||
Tooltip_movie.swapDepths(Tooltip_movie.oldDepth);
|
||||
}
|
||||
// Load the XML into the myLoader object.
|
||||
//myLoader.load(xmlUrl+"?class="+root_object_class+"&id="+root_object_id);
|
||||
myLoader.load(xml_document_url+"?class="+root_object_class+"&id="+root_object_id+"&relation="+root_relation);
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,214 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
|
||||
/**
|
||||
* Specific page to build the XML data describing the "relation" around a given seed object
|
||||
* This XML is desgined to be consumed by the Flash Navigator object (see ../navigator folder)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
require_once('../approot.inc.php');
|
||||
require_once(APPROOT.'/application/application.inc.php');
|
||||
require_once(APPROOT.'/application/webpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
|
||||
require_once(APPROOT.'/application/wizardhelper.class.inc.php');
|
||||
require_once(APPROOT.'/application/ui.linkswidget.class.inc.php');
|
||||
|
||||
/**
|
||||
* Fills the given XML node with te details of the specified object
|
||||
*/
|
||||
function AddNodeDetails(&$oNode, $oObj)
|
||||
{
|
||||
$aZlist = MetaModel::GetZListItems(get_class($oObj), 'list');
|
||||
$aLabels = array();
|
||||
$index = 0;
|
||||
foreach($aZlist as $sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
|
||||
$aLabels[] = $oAttDef->GetLabel();
|
||||
if (!$oAttDef->IsLinkSet())
|
||||
{
|
||||
$oNode->SetAttribute('att_'.$index, $oObj->GetAsHTML($sAttCode));
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
$oNode->SetAttribute('zlist', implode(',', $aLabels));
|
||||
}
|
||||
|
||||
$G_aCachedObjects = array();
|
||||
|
||||
/**
|
||||
* Get the related objects through the given relation, output in XML
|
||||
* @param DBObject $oObj The current object
|
||||
* @param string $sRelation The name of the relation to search with
|
||||
*/
|
||||
function GetRelatedObjectsAsXml(DBObject $oObj, $sRelationName, &$oLinks, &$oXmlDoc, &$oXmlNode, $iDepth = 0, $aExcludedClasses)
|
||||
{
|
||||
global $G_aCachedObjects;
|
||||
|
||||
$iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
|
||||
$aResults = array();
|
||||
$bAddLinks = false;
|
||||
|
||||
if ($iDepth > ($iMaxRecursionDepth - 1)) return;
|
||||
|
||||
$sIdxKey = get_class($oObj).':'.$oObj->GetKey();
|
||||
if (!array_key_exists($sIdxKey, $G_aCachedObjects))
|
||||
{
|
||||
$oObj->GetRelatedObjects($sRelationName, 1 /* iMaxDepth */, $aResults);
|
||||
$G_aCachedObjects[$sIdxKey] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
//$aResults = $G_aCachedObjects[$sIdxKey];
|
||||
}
|
||||
|
||||
foreach($aResults as $sRelatedClass => $aObjects)
|
||||
{
|
||||
foreach($aObjects as $id => $oTargetObj)
|
||||
{
|
||||
if (is_object($oTargetObj))
|
||||
{
|
||||
if (in_array(get_class($oTargetObj), $aExcludedClasses))
|
||||
{
|
||||
GetRelatedObjectsAsXml($oTargetObj, $sRelationName, $oLinks, $oXmlDoc, $oXmlNode, $iDepth+1, $aExcludedClasses);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oLinkingNode = $oXmlDoc->CreateElement('link');
|
||||
$oLinkingNode->SetAttribute('relation', $sRelationName);
|
||||
$oLinkingNode->SetAttribute('arrow', 1); // Such relations have a direction, display an arrow
|
||||
$oLinkedNode = $oXmlDoc->CreateElement('node');
|
||||
$oLinkedNode->SetAttribute('id', $oTargetObj->GetKey());
|
||||
$oLinkedNode->SetAttribute('obj_class', get_class($oTargetObj));
|
||||
$oLinkedNode->SetAttribute('obj_class_name', htmlspecialchars(MetaModel::GetName(get_class($oTargetObj))));
|
||||
$oLinkedNode->SetAttribute('name', htmlspecialchars($oTargetObj->GetRawName())); // htmlentities is too much for XML
|
||||
$oLinkedNode->SetAttribute('icon', BuildIconPath($oTargetObj->GetIcon(false /* No IMG tag */)));
|
||||
AddNodeDetails($oLinkedNode, $oTargetObj);
|
||||
$oSubLinks = $oXmlDoc->CreateElement('links');
|
||||
// Recurse
|
||||
GetRelatedObjectsAsXml($oTargetObj, $sRelationName, $oSubLinks, $oXmlDoc, $oLinkedNode, $iDepth+1, $aExcludedClasses);
|
||||
$oLinkingNode->AppendChild($oLinkedNode);
|
||||
$oLinks->AppendChild($oLinkingNode);
|
||||
$bAddLinks = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($bAddLinks)
|
||||
{
|
||||
$oXmlNode->AppendChild($oLinks);
|
||||
}
|
||||
}
|
||||
|
||||
function BuildIconPath($sIconPath)
|
||||
{
|
||||
return $sIconPath;
|
||||
}
|
||||
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
|
||||
// For developping the Navigator from within Flash
|
||||
//session_start();
|
||||
//$_SESSION['auth_user'] = 'admin';
|
||||
//UserRights::Login($_SESSION['auth_user']); // Set the user's language
|
||||
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
|
||||
|
||||
$oPage = new ajax_page("");
|
||||
$oPage->no_cache();
|
||||
|
||||
$sClass = utils::ReadParam('class', 'Contact', false, 'class');
|
||||
$id = utils::ReadParam('id', 1);
|
||||
$sRelation = utils::ReadParam('relation', 'impacts');
|
||||
$aValidRelations = MetaModel::EnumRelations();
|
||||
$sFormat = utils::ReadParam('format', 'xml');
|
||||
$sExcludedClasses = utils::ReadParam('exclude', '', false, 'raw_data');
|
||||
$aExcludedClasses = explode(',', $sExcludedClasses);
|
||||
|
||||
|
||||
if (!in_array($sRelation, $aValidRelations))
|
||||
{
|
||||
// Not a valid relation, use the default one instead
|
||||
$sRelation = 'impacts';
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if ($id != 0)
|
||||
{
|
||||
switch($sFormat)
|
||||
{
|
||||
case 'html':
|
||||
$oPage->SetContentType('text/html');
|
||||
$oObj = MetaModel::GetObject($sClass, $id, true /* object must exist */);
|
||||
$aResults = array();
|
||||
$iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
|
||||
$oObj->GetRelatedObjects($sRelation, $iMaxRecursionDepth /* iMaxDepth */, $aResults);
|
||||
|
||||
$iBlock = 1; // Zero is not a valid blockid
|
||||
foreach($aResults as $sClass => $aObjects)
|
||||
{
|
||||
$oSet = CMDBObjectSet::FromArray($sClass, $aObjects);
|
||||
$oPage->add("<h1>".MetaModel::GetRelationDescription($sRelation).' '.$oObj->GetName()."</h1>\n");
|
||||
$oPage->add("<div class=\"page_header\">\n");
|
||||
$oPage->add("<h2>".MetaModel::GetClassIcon($sClass)." <span class=\"hilite\">".Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aObjects), Metamodel::GetName($sClass))."</h2>\n");
|
||||
$oPage->add("</div>\n");
|
||||
$oBlock = DisplayBlock::FromObjectSet($oSet, 'list');
|
||||
$oBlock->Display($oPage, $iBlock++);
|
||||
$oPage->P(' '); // Some space ?
|
||||
}
|
||||
break;
|
||||
|
||||
case 'xml':
|
||||
default:
|
||||
$oPage->SetContentType('text/xml');
|
||||
$oObj = MetaModel::GetObject($sClass, $id, true /* object must exist */);
|
||||
// Build the root XML part
|
||||
$oXmlDoc = new DOMDocument( '1.0', 'UTF-8' );
|
||||
$oXmlRoot = $oXmlDoc->CreateElement('root');
|
||||
$oXmlNode = $oXmlDoc->CreateElement('node');
|
||||
$oXmlNode->SetAttribute('id', $oObj->GetKey());
|
||||
$oXmlNode->SetAttribute('obj_class', get_class($oObj));
|
||||
$oXmlNode->SetAttribute('obj_class_name', htmlspecialchars(MetaModel::GetName(get_class($oObj))));
|
||||
$oXmlNode->SetAttribute('name', htmlspecialchars($oObj->GetRawName()));
|
||||
$oXmlNode->SetAttribute('icon', BuildIconPath($oObj->GetIcon(false /* No IMG tag */))); // Hard coded for the moment
|
||||
AddNodeDetails($oXmlNode, $oObj);
|
||||
|
||||
$oLinks = $oXmlDoc->CreateElement("links");
|
||||
|
||||
$oXmlRoot->SetAttribute('position', 'left');
|
||||
$oXmlRoot->SetAttribute('title', MetaModel::GetRelationDescription($sRelation).' '. htmlspecialchars($oObj->GetRawName()));
|
||||
GetRelatedObjectsAsXml($oObj, $sRelation, $oLinks, $oXmlDoc, $oXmlNode, 0, $aExcludedClasses);
|
||||
|
||||
$oXmlRoot->AppendChild($oXmlNode);
|
||||
$oXmlDoc->AppendChild($oXmlRoot);
|
||||
$oPage->add($oXmlDoc->SaveXML());
|
||||
break;
|
||||
}
|
||||
}
|
||||
$oPage->output();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
echo "Error: ".$e->getMessage();
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user