mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
- Updated flash navigator: better objects placement, auto-zoom & pan at startup, improved tooltip with some details on each objects.
SVN:trunk[710]
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
import flash.net.*;
|
||||
import flash.events.*;
|
||||
import flash.text.*;
|
||||
import flash.xml.*;
|
||||
import flash.ui.ContextMenu;
|
||||
import flash.ui.ContextMenuItem;
|
||||
import iTop.ToolTip;
|
||||
@@ -14,27 +15,46 @@
|
||||
public class GraphNode extends Sprite
|
||||
{
|
||||
private var m_oIcon:Loader;
|
||||
private var m_sClass;String;
|
||||
private var m_sClass:String;
|
||||
private var m_sClassName: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;
|
||||
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, iId:Number, sLabel:String, sIconPath:String, sParentKey:String, fZoom:Number)
|
||||
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_sLabel.autoSize = TextFieldAutoSize.LEFT;
|
||||
m_sLabel.multiline = false;
|
||||
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;
|
||||
// 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;
|
||||
m_oToolTip = new ToolTip( "<p><b>"+m_sClass+"</b></p><p>"+sLabel+"</p>");
|
||||
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;
|
||||
@@ -94,11 +114,14 @@
|
||||
{
|
||||
trace("Click in Node");
|
||||
m_oParent.m_bChildDragging = true;
|
||||
m_bInDrag = true;
|
||||
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;
|
||||
}
|
||||
@@ -130,5 +153,10 @@
|
||||
return sDefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLabelWidth():Number
|
||||
{
|
||||
return m_sLabel.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package iTop
|
||||
package iTop
|
||||
{
|
||||
import flash.display.*;
|
||||
import flash.geom.*;
|
||||
@@ -8,7 +8,7 @@
|
||||
import fl.controls.Slider;
|
||||
import fl.events.SliderEvent;
|
||||
import fl.controls.Label;
|
||||
|
||||
|
||||
// The main canvas
|
||||
public class Navigator extends MovieClip
|
||||
{
|
||||
@@ -28,8 +28,14 @@
|
||||
protected var m_sObjId:String;
|
||||
|
||||
// Constants
|
||||
protected var m_RADIUS = 120;
|
||||
protected var m_ITEMS_PER_ROW = 8;
|
||||
protected var m_RADIUS = 150;
|
||||
protected var m_Q = 0.9; // Electrostatic forces coeff
|
||||
protected var m_K = 1.0; // Elastic forces coeff
|
||||
protected var m_Kf = 0.7; // Fluid friction coeff
|
||||
protected var m_Ks = 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 = 50; // 50 images to zoom & pan correctly
|
||||
protected var m_fZoom:Number;
|
||||
|
||||
// Constructor
|
||||
@@ -41,6 +47,8 @@
|
||||
initParameters();
|
||||
doLoadData();
|
||||
addEventListener(Event.ENTER_FRAME, initGraphics);
|
||||
//Stop scaling the flash content
|
||||
stage.scaleMode = StageScaleMode.NO_SCALE;
|
||||
}
|
||||
|
||||
protected function initParameters():void
|
||||
@@ -62,11 +70,6 @@
|
||||
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
|
||||
{
|
||||
@@ -87,14 +90,24 @@
|
||||
|
||||
function onZoomChange(event:SliderEvent):void
|
||||
{
|
||||
m_fZoom = event.value/100;
|
||||
SetZoomLevel(event.value/100);
|
||||
}
|
||||
|
||||
function SetZoomLevel(fZoomLevel:Number):void
|
||||
{
|
||||
m_fZoom = fZoomLevel;
|
||||
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;
|
||||
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;
|
||||
trace("Requesting:"+myString);
|
||||
var myXMLURL:URLRequest = new URLRequest(myString);
|
||||
m_oLoader = new URLLoader();
|
||||
@@ -109,10 +122,17 @@
|
||||
var myXML:XML = XML(m_oLoader.data);
|
||||
//trace("Data loaded." + myXML);
|
||||
//trace("===========================");
|
||||
parseXMLData(null, myXML, 0);
|
||||
parseXMLData(null, myXML, 0, 0);
|
||||
m_sTitle.text = myXML.attribute("title");
|
||||
m_oZoomSlider.enabled = true;
|
||||
removeChild(m_oPreloader);
|
||||
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);
|
||||
//trace('======= Initial Posistions =========');
|
||||
//DumpPositions();
|
||||
}
|
||||
|
||||
function onXMLLoadError(event:IOErrorEvent):void
|
||||
@@ -120,11 +140,11 @@
|
||||
trace("An error occured:" + Event);
|
||||
}
|
||||
|
||||
function parseXMLData(oParentNode:GraphNode, oXMLData:XML, iChildIndex:Number)
|
||||
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);
|
||||
oNode = addNode(oParentNode, oXMLData.child("node")[0], iChildIndex, iChildCount);
|
||||
if (oParentNode != null)
|
||||
{
|
||||
AddLink(oParentNode.GetKey(), oNode.GetKey());
|
||||
@@ -138,30 +158,43 @@
|
||||
var oLink = oLinks.link;
|
||||
for each(var oChild:XML in oLink)
|
||||
{
|
||||
parseXMLData(oNode, oChild, iChildIndex);
|
||||
parseXMLData(oNode, oChild, iChildIndex, oLinks.link.length());
|
||||
iChildIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function addNode(oParent:GraphNode, oXMLData:XML, iChildIndex)
|
||||
function addNode(oParent:GraphNode, oXMLData:XML, iChildIndex:Number, iChildCount:Number)
|
||||
{
|
||||
var sClass = oXMLData.@obj_class;
|
||||
var sClass:String = oXMLData.@obj_class;
|
||||
var sClassName:String = oXMLData.@obj_class_name;
|
||||
var iId = oXMLData.@id;
|
||||
var sLabel = oXMLData.@name;
|
||||
var sIcon = oXMLData.@icon;
|
||||
var sLabel:String = oXMLData.@name;
|
||||
var sIcon:String = oXMLData.@icon;
|
||||
var oDetails:Object = new 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);
|
||||
var oPt:Point = GetNextFreePosition(oParent, iChildIndex, iChildCount);
|
||||
var sParentKey = null;
|
||||
if (oParent != null)
|
||||
{
|
||||
sParentKey = oParent.GetKey();
|
||||
}
|
||||
oNode = new GraphNode(this, oPt, sClass, iId, sLabel, sIcon, sParentKey, m_fZoom);
|
||||
// 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);
|
||||
this.m_aNodes[oNode.GetKey()] = oNode; //Keep it referenced
|
||||
if (oParent == null)
|
||||
{
|
||||
@@ -185,7 +218,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function GetNextFreePosition(oParent:GraphNode, iChildIndex:Number):Point
|
||||
function GetNextFreePosition(oParent:GraphNode, iChildIndex:Number, iChildCount:Number):Point
|
||||
{
|
||||
var oPt:Point = GetInitialPosition();
|
||||
var angle:Number = GetInitialAngle();
|
||||
@@ -208,13 +241,43 @@
|
||||
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;
|
||||
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 += m_RADIUS * Math.cos(angle);
|
||||
oPt.y += m_RADIUS * Math.sin(angle);
|
||||
oPt.x += radius * Math.cos(angle);
|
||||
oPt.y += radius * 0.7 * Math.sin(angle); // Ellipse because the labels are written horizontally !
|
||||
|
||||
trace("iChildIndex: "+iChildIndex+" x: "+oPt.x+" y: "+oPt.y+" sGdParentKey: "+sGrandParentKey);
|
||||
//trace("iChildIndex: "+iChildIndex+" (iChildCount: "+iChildCount+") x: "+oPt.x+" y: "+oPt.y+" sGdParentKey: "+sGrandParentKey);
|
||||
}
|
||||
return oPt;
|
||||
}
|
||||
@@ -280,8 +343,10 @@
|
||||
|
||||
function drawLines(event:Event):void
|
||||
{
|
||||
var color:uint = 0x666666;
|
||||
m_oCanvas.graphics.clear();
|
||||
m_oCanvas.graphics.lineStyle(2,0x666666,100);
|
||||
UpdatePositions();
|
||||
for (var index:String in m_aLinks)
|
||||
{
|
||||
var oStartNode:GraphNode = GetNode(m_aLinks[index].GetStart());
|
||||
@@ -289,18 +354,28 @@
|
||||
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);
|
||||
drawArrow(oMiddlePoint, oEndNode.x - oStartNode.x, oEndNode.y - oStartNode.y, color);
|
||||
}
|
||||
|
||||
if (this.m_FOCUS_DELAY_COUNTDOWN > 0)
|
||||
{
|
||||
this.m_FOCUS_DELAY_COUNTDOWN--;
|
||||
trace('FOCUS_DELAY:'+this.m_FOCUS_DELAY_COUNTDOWN);
|
||||
UpdatePanAndZoom(m_FOCUS_DELAY_COUNTDOWN / 30);
|
||||
}
|
||||
}
|
||||
function drawArrow(oPt:Point, dx:Number, dy:Number):void
|
||||
function drawArrow(oPt:Point, dx:Number, dy:Number, color:uint):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);
|
||||
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)
|
||||
@@ -316,6 +391,226 @@
|
||||
return sDefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public function ComputeElectrostaticForces():Array
|
||||
{
|
||||
var aForces:Array = new 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 d:Number = Math.sqrt(d2);
|
||||
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 = new 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)
|
||||
{
|
||||
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;
|
||||
// Links with more weight attached are more rigid !
|
||||
//weightCoeff = (aWeights[aLinks[l].start] + aWeights[aLinks[l].end])/2;
|
||||
var Fx = -this.m_K * dx;
|
||||
var Fy = -this.m_K * dy;
|
||||
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()
|
||||
{
|
||||
//trace('====== BEGIN UpdatePositions() =======');
|
||||
var aElasticForces:Array = ComputeElasticForces();
|
||||
var aElectrostaticForces:Array = ComputeElectrostaticForces();
|
||||
//DrawForces(aElectrostaticForces, 0xcc0000);
|
||||
//DrawForces(aElectrostaticForces, 0x0000cc);
|
||||
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
|
||||
{
|
||||
oNode.m_speed_x = oNode.m_speed_x*this.m_Kf + this.m_deltaT*Fx;
|
||||
oNode.m_speed_y = oNode.m_speed_y*this.m_Kf + this.m_deltaT*Fy;
|
||||
var dx:Number = oNode.m_speed_x * this.m_deltaT;
|
||||
var dy:Number = oNode.m_speed_y * this.m_deltaT;
|
||||
oNode.x = Math.round(oNode.x + dx);
|
||||
oNode.y = Math.round(oNode.y + dy);
|
||||
//trace('object '+i+' moves (Force: Fx='+Fx+', Fy='+Fy+')! ');
|
||||
}
|
||||
}
|
||||
}
|
||||
//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 = Math.round(oNode.x + oForce.FxTotal);
|
||||
oEndPoint.y = Math.round(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);
|
||||
|
||||
if ((sceneRect.width > stage.stageWidth) || (sceneRect.height > (stage.stageHeight - 50)))
|
||||
{
|
||||
var wRatio:Number = stage.stageWidth / sceneRect.width;
|
||||
var hRatio:Number = (stage.stageHeight - 50) / sceneRect.height;
|
||||
idealZoomLevel = Math.min(wRatio, hRatio);
|
||||
SetZoomLevel(idealZoomLevel);
|
||||
m_oZoomSlider.value = Math.round(100*idealZoomLevel);
|
||||
|
||||
}
|
||||
var xOffset:Number = 0;
|
||||
var yOffset:Number = 50;
|
||||
if (stage.stageWidth > sceneRect.width)
|
||||
{
|
||||
xOffset = (stage.stageWidth-sceneRect.width)/2
|
||||
}
|
||||
if (stage.stageHeight > sceneRect.height)
|
||||
{
|
||||
yOffset = 50 + (stage.stageHeight-50-sceneRect.height)/2
|
||||
}
|
||||
m_oCanvas.x = xOffset-sceneRect.x;
|
||||
m_oCanvas.y = yOffset-sceneRect.y;
|
||||
|
||||
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+')');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package iTop
|
||||
package iTop
|
||||
{
|
||||
import flash.display.Sprite;
|
||||
import flash.display.*;
|
||||
import flash.geom.*;
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFormat;
|
||||
import flash.text.TextFieldAutoSize;
|
||||
@@ -15,17 +16,18 @@
|
||||
// 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 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;
|
||||
private static const ALPHA_INC:Number = .1;
|
||||
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 / ALPHA_INC;
|
||||
// For fading in and out
|
||||
private var _timer:Timer;
|
||||
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
|
||||
@@ -51,7 +53,7 @@
|
||||
_tf.y += PADDING;
|
||||
addChild( _tf );
|
||||
// Draw the background
|
||||
graphics.beginFill( 0xF6F6F1, 1 );
|
||||
graphics.beginFill( 0xEEEE99, 0.95 );
|
||||
graphics.drawRoundRect( 0, 0, _tf.textWidth+PADDING*4, _tf.textHeight+PADDING*4, ROUND );
|
||||
graphics.endFill();
|
||||
this.alpha = MIN_ALPHA;
|
||||
@@ -65,28 +67,74 @@
|
||||
}
|
||||
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();
|
||||
// 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;
|
||||
_timer = new Timer( fadeSpeed, REFRESH );
|
||||
_timer.addEventListener( "timer", fadeOut );
|
||||
_timer.start();
|
||||
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
|
||||
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.alpha += ALPHA_INC;
|
||||
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
|
||||
{
|
||||
this.alpha -= ALPHA_INC;
|
||||
if (this.alpha > ALPHA_INC)
|
||||
{
|
||||
this.alpha -= ALPHA_INC;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.alpha = 0.0;
|
||||
}
|
||||
//trace("-- Tooltip alpha: "+this.alpha+" ALPHA_INC:"+ALPHA_INC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -37,7 +37,7 @@ define('MAX_RECURSION_DEPTH', 20);
|
||||
*/
|
||||
function AddNodeDetails(&$oNode, $oObj)
|
||||
{
|
||||
$aZlist = MetaModel::GetZListItems(get_class($oObj), 'details');
|
||||
$aZlist = MetaModel::GetZListItems(get_class($oObj), 'list');
|
||||
$aLabels = array();
|
||||
$index = 0;
|
||||
foreach($aZlist as $sAttCode)
|
||||
@@ -46,7 +46,7 @@ function AddNodeDetails(&$oNode, $oObj)
|
||||
$aLabels[] = $oAttDef->GetLabel();
|
||||
if (!$oAttDef->IsLinkSet())
|
||||
{
|
||||
$oNode->SetAttribute('att_'.$index, $oObj->Get($sAttCode));
|
||||
$oNode->SetAttribute('att_'.$index, $oObj->GetAsHTML($sAttCode));
|
||||
}
|
||||
$index++;
|
||||
}
|
||||
@@ -78,6 +78,7 @@ function GetRelatedObjects(DBObject $oObj, $sRelationName, &$oLinks, &$oXmlDoc,
|
||||
$oLinkedNode = $oXmlDoc->CreateElement('node');
|
||||
$oLinkedNode->SetAttribute('id', $oTargetObj->GetKey());
|
||||
$oLinkedNode->SetAttribute('obj_class', get_class($oTargetObj));
|
||||
$oLinkedNode->SetAttribute('obj_class_name', MetaModel::GetName(get_class($oTargetObj)));
|
||||
$oLinkedNode->SetAttribute('name', $oTargetObj->GetName());
|
||||
$oLinkedNode->SetAttribute('icon', BuildIconPath($oTargetObj->GetIcon(false /* No IMG tag */)));
|
||||
AddNodeDetails($oLinkedNode, $oTargetObj);
|
||||
@@ -104,11 +105,10 @@ function BuildIconPath($sIconPath)
|
||||
|
||||
require_once('../application/startup.inc.php');
|
||||
require_once('../application/loginwebpage.class.inc.php');
|
||||
//// For developping the Navigator
|
||||
// For developping the Navigator from within Flash
|
||||
//session_start();
|
||||
//$_SESSION['auth_user'] = 'admin';
|
||||
//$_SESSION['auth_pwd'] = 'admin2';
|
||||
//UserRights::Login($_SESSION['auth_user'], $_SESSION['auth_pwd']); // Set the user's language
|
||||
//UserRights::Login($_SESSION['auth_user']); // Set the user's language
|
||||
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
|
||||
|
||||
$oPage = new ajax_page("");
|
||||
@@ -134,6 +134,7 @@ if ($id != 0)
|
||||
$oXmlNode = $oXmlDoc->CreateElement('node');
|
||||
$oXmlNode->SetAttribute('id', $oObj->GetKey());
|
||||
$oXmlNode->SetAttribute('obj_class', get_class($oObj));
|
||||
$oXmlNode->SetAttribute('obj_class_name', MetaModel::GetName(get_class($oObj)));
|
||||
$oXmlNode->SetAttribute('name', $oObj->GetName());
|
||||
$oXmlNode->SetAttribute('icon', BuildIconPath($oObj->GetIcon(false /* No IMG tag */))); // Hard coded for the moment
|
||||
AddNodeDetails($oXmlNode, $oObj);
|
||||
|
||||
Reference in New Issue
Block a user