src/org/un/cava/birdeye/ravis/graphLayout/visual/VisualNode.as
/*
* The MIT License
*
* Copyright (c) 2007 The SixDegrees Project Team
* (Jason Bellone, Juan Rodriguez, Segolene de Basquiat, Daniel Lang).
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.un.cava.birdeye.ravis.graphLayout.visual
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.geom.Point;
import mx.collections.ArrayCollection;
import mx.core.IDataRenderer;
import mx.core.UIComponent;
import org.un.cava.birdeye.ravis.graphLayout.data.IEdge;
import org.un.cava.birdeye.ravis.graphLayout.data.INode;
import org.un.cava.birdeye.ravis.utils.LogUtil;
import org.un.cava.birdeye.ravis.utils.events.VGraphEvent;
/**
* The VisualNode to be used in the Graph.
* */
public class VisualNode extends EventDispatcher implements IVisualNode, IDataRenderer {
private static const _LOG:String = "graphLayout.visual.VisualNode";
/* The associated VisualGraph */
private var _vgraph:IVisualGraph;
/* Internal id of the VisualNode */
private var _id:int;
/* Data object of the VisualNode */
private var _data:Object;
/* Indicates if the node shall be moveable or not
* current UNUSED !!! */
private var _moveable:Boolean;
/* Indicates of the node is currently visible */
private var _visible:Boolean;
/* the related Graph Node */
private var _node:INode;
/* the VisualNode's anticipated target X and Y coordinates.
* Will be applied using the commit() method */
private var _x:Number;
private var _y:Number;
/* The node's view which is the UIComponent that will
* be displayed in Flashplayer */
private var _view:UIComponent;
/* instead of a left/top corner orientation
* we can implicitly do a centered orientation
* this will be applied during the commit() method
* and will be reversed during refresh() */
private var _centered:Boolean;
/*
* A layouter can optionally set an orientation angle
* paramter in the node. Right now we hardcode this as
* one single parameter. If we need more in the future,
* we can replace this by a hash with multiple keys.
* This parameter may be accessed by the nodeRenderer for instance.
* The value is in degrees.
*/
private var _orientAngle:Number = 0;
/**
* The constructor presets the VisualNode's data structures
* and requires most parameters already present.
* @param vg The VisualGraph that this VisualNode lives in.
* @param node The associated Graph Node.
* @param id The internal id of this node.
* @param view The view/UIComponent of this node (if already present).
* @param data The VisualNode's associated data object.
* @param mv Indicator if the node is moveable (currently ignored).
* */
public function VisualNode(vg:IVisualGraph, node:INode, id:int, view:UIComponent = null, data:Object = null, mv:Boolean = true) {
_vgraph = vg;
_node = node;
_id = id;
_data = data;
_moveable = mv;
_visible = undefined;
_centered = true;
_x = 0;
_y = 0;
_view = view;
}
/**
* Access to the associated VisualGraph, that this VisualNode lives in.
* */
public function get vgraph():IVisualGraph {
return _vgraph;
}
/**
* Access to the internal id of this VisualNode.
* */
public function get id():int {
return _id;
}
/**
* Access to the indicator if the node is currently
* visible or not. If this is set to false, any
* associated view will be removed in order to
* save resources.
* */
public function get isVisible():Boolean {
return _visible;
}
/**
* @private
* */
public function set isVisible(v:Boolean):void {
_visible = v;
/* set the views visibility, if we currently
* have one */
if(_view != null) {
_view.visible = v;
}
}
/**
* @inheritDoc
* */
public function get node():INode {
return _node;
}
/**
* @inheritDoc
* */
[Bindable]
public function get data():Object {
return _data;
}
/**
* @private
* */
public function set data(o:Object):void {
_data = o;
}
/**
* @inheritDoc
* */
public function get centered():Boolean {
return _centered;
}
/**
* @private
* */
public function set centered(c:Boolean):void {
_centered = c;
}
/**
* @inheritDoc
* */
public function get x():Number {
return _x;
}
/**
* @private
* */
public function set x(n:Number):void {
if(!isNaN(n)) {
_x = n;
} else {
LogUtil.error(_LOG,"VNode "+_id+": set x tried to set NaN");
//throw Error("VNode "+_id+": set x tried to set NaN");
}
}
/**
* @inheritDoc
* */
public function get y():Number {
return _y;
}
/**
* @private
* */
public function set y(n:Number):void {
if(!isNaN(n)) {
_y = n;
} else {
LogUtil.error(_LOG,"VNode "+_id+": set y tried to set NaN");
//throw Error("VNode "+_id+": set y tried to set NaN");
}
}
/**
* @inheritDoc
* */
public function get viewX():Number {
return this.view.x;
}
/**
* @private
* */
public function set viewX(n:Number):void {
if(!isNaN(n)) {
if((n != this.view.x) && _moveable) {
this.view.x = n;
}
} else {
LogUtil.error(_LOG,"VNode "+_id+": set viewX tried to set NaN");
//throw Error("VNode "+_id+": set viewX tried to set NaN");
}
}
/**
* @inheritDoc
* */
public function get viewY():Number {
return this.view.y;
}
/**
* @private
* */
public function set viewY(n:Number):void {
if(!isNaN(n)) {
if((n != this.view.y) && _moveable) {
this.view.y = n;
}
} else {
LogUtil.error(_LOG,"VNode "+_id+": set viewY tried to set NaN");
//throw Error("VNode "+_id+": set viewY tried to set NaN");
}
}
/**
* @inheritDoc
* */
public function get rawview():UIComponent {
return _view;
}
/**
* @inheritDoc
* */
public function get view():UIComponent {
return _view;
}
/**
* @private
* */
public function set view(v:UIComponent):void {
_view = v;
}
/**
* @inheritDoc
* */
public function get viewCenter():Point {
if(_view != null) {
if(_centered) {
return new Point(_view.x + (_view.width / 2.0),
_view.y + (_view.height / 2.0));
} else {
return new Point(_view.x, _view.y);
}
} else {
return null;
}
}
/**
* @inheritDoc
* */
public function get moveable():Boolean {
return _moveable;
}
public function set moveable(value:Boolean):void {
_moveable = value;
}
/**
* @inheritDoc
* */
public function get orientAngle():Number {
return _orientAngle;
}
/**
* @private
* */
public function set orientAngle(oa:Number):void {
_orientAngle = oa;
if(this.view is IEventDispatcher) {
(this.view as IEventDispatcher).dispatchEvent(new VGraphEvent(VGraphEvent.VNODE_UPDATED));
}
}
/**
* @inheritDoc
* */
public function commit():void {
if(view == null)
return;
if(view.initialized == false)
{
view.callLater(commit);
return;
}
/* if we have the centered orientation we apply
* some corrections */
if(_centered) {
this.viewX = _x - (this.view.width / 2.0);
this.viewY = _y - (this.view.height / 2.0);
} else {
this.viewX = _x;
this.viewY = _y;
}
updateReleatedEdges();
if(this.view is IEventDispatcher) {
(this.view as IEventDispatcher).dispatchEvent(new VGraphEvent(VGraphEvent.VNODE_UPDATED));
}
}
/**
* @inheritDoc
* */
public function refresh():void {
if(view == null)
return;
if(view.initialized == false)
{
view.callLater(refresh);
return;
}
/* have to recompensate for centered */
if(_centered) {
_x = this.viewX + (this.view.width / 2.0);
_y = this.viewY + (this.view.height / 2.0);
} else {
_x = this.viewX;
_y = this.viewY;
}
updateReleatedEdges();
}
public function updateReleatedEdges():void
{
for each(var edge:IVisualEdge in vedges)
{
edge.edgeView.render();
}
}
public function get vedges():ArrayCollection
{
var edge:IEdge;
var retVal:ArrayCollection = new ArrayCollection();
for each(edge in node.inEdges)
{
if(!retVal.contains(edge.vedge))
retVal.addItem(edge.vedge);
}
for each(edge in node.outEdges)
{
if(!retVal.contains(edge.vedge))
retVal.addItem(edge.vedge);
}
return retVal;
}
}
}