src/org/un/cava/birdeye/ravis/graphLayout/layout/BaseLayouter.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.layout {
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
import flash.utils.Dictionary;
import org.un.cava.birdeye.ravis.graphLayout.data.Graph;
import org.un.cava.birdeye.ravis.graphLayout.data.IGTree;
import org.un.cava.birdeye.ravis.graphLayout.data.IGraph;
import org.un.cava.birdeye.ravis.graphLayout.data.INode;
import org.un.cava.birdeye.ravis.graphLayout.visual.IVisualGraph;
import org.un.cava.birdeye.ravis.graphLayout.visual.IVisualNode;
import org.un.cava.birdeye.ravis.graphLayout.visual.events.VisualGraphEvent;
import org.un.cava.birdeye.ravis.utils.LogUtil;
/**
* This is an base class to various layout implementations
* it does not really do any layouting but implements
* everything required by the Interface.
* */
public class BaseLayouter extends EventDispatcher implements ILayoutAlgorithm {
private static const _LOG:String = "graphLayout.layout.BaseLayouter";
/**
* The default minimum node height to be used if the exact node
* height cannot be determined yet.
* */
public static const MINIMUM_NODE_HEIGHT:Number = 5;
/**
* The default minimum node width to be used if the exact node
* height cannot be determined yet.
* */
public static const MINIMUM_NODE_WIDTH:Number = 5;
/**
* If set to true, animation is disabled and direct
* node location setting occurs (instantaneously).
* @default false
* */
protected var _disableAnimation:Boolean = false;
/**
* All layouters need access to the VisualGraph.
* */
protected var _vgraph:IVisualGraph = null;
/**
* All layouters need access to the Graph.
* */
protected var _graph:IGraph = null;
/**
* This keeps track if the layout has changed
* and can be accessed by any derived layouter.
* */
protected var _layoutChanged:Boolean = false;
/**
* A spanning tree of the graph, since probably every layout
* will work on a spanning tree, we keep this one in this
* base class.
* */
protected var _stree:IGTree;
/**
* The current root node of the layout.
* */
protected var _root:INode;
/**
* The indicator if AutoFit should currently be used or not.
* */
protected var _autoFitEnabled:Boolean = false;
/**
* this holds the data for a layout drawing.
* */
private var _currentDrawing:BaseLayoutDrawing;
/**
* The default margin to be considered when using
* autoFit.
* */
private var _margin:Number = 30;
protected var _bounds:Rectangle;
/**
* The constructor initializes the layouter and may assign
* already a VisualGraph object, but this can also be set later.
* @param vg The VisualGraph object on which this layouter should work on.
* */
public function BaseLayouter(vg:IVisualGraph = null) {
_vgraph = vg;
if(vg) {
_graph = _vgraph.graph;
} else {
_graph = new Graph("dummyID");
}
/* this is required to smooth the animation */
if(_vgraph)
_vgraph.addEventListener("forceRedrawEvent",forceRedraw);
}
public function get margin():Number {
return _margin;
}
public function set margin(value:Number):void {
_margin = value;
}
/**
* @inheritDoc
* */
public function resetAll():void {
_layoutChanged = true;
}
public function get vgraph():IVisualGraph {
return _vgraph;
}
/**
* @inheritDoc
* @throws An error if the vgraph was already set.
* */
public function set vgraph(vg:IVisualGraph):void {
if(_vgraph == null) {
_vgraph = vg;
_graph = _vgraph.graph;
} else {
LogUtil.warn(_LOG, "vgraph was already set in layouter");
}
}
/**
* @inheritDoc
* */
public function set graph(g:IGraph):void {
_graph = g;
}
/**
* @inheritDoc
* */
public function get layoutChanged():Boolean {
return _layoutChanged;
}
/**
* @private
* */
public function set layoutChanged(lc:Boolean):void {
_layoutChanged = lc;
}
/**
* @inheritDoc
* */
[Bindable]
public function get autoFitEnabled():Boolean {
return _autoFitEnabled;
}
/**
* @private
* */
public function set autoFitEnabled(af:Boolean):void {
_autoFitEnabled = af;
}
/**
* This is a NOP in the BaseLayouter class. It does not set
* anything and always returns 0.
*
* @inheritDoc
* */
[Bindable]
public function set linkLength(r:Number):void {
/* NOP */
}
/**
* @private
* */
public function get linkLength():Number {
/* NOP
* but must not return 0, since some layouter
* do not care about LL, but the vgraph will
* not draw if LL is 0
* so default is something else, like 1
*/
return 1;
}
/**
* @inheritDoc
* */
public function get animInProgress():Boolean {
/* since the base layouter is ignorant of animation
* it would always return false. The AnimatedBaseLayouter
* though needs to override this to always return the
* correct value. */
return false;
}
/**
* @inheritDoc
* */
public function set disableAnimation(d:Boolean):void {
_disableAnimation = d;
};
/**
* @private
* */
public function get disableAnimation():Boolean {
return _disableAnimation;
}
/**
* This always returns true, dispatches the graph updated event.
*
* @inheritDoc
* */
public function layoutPass():Boolean {
_bounds = null;
dispatchEvent(new VisualGraphEvent(VisualGraphEvent.GRAPH_UPDATED));
return true;
}
private function calculateBounds():Rectangle
{
var retVal:Rectangle = new Rectangle(NaN,NaN,NaN,NaN);
for each(var node:INode in _graph.nodes)
{
var p:Point = _currentDrawing.getAbsCartCoordinates(node);
if(p.x > retVal.right || isNaN(retVal.right))
retVal.right = p.x;
if(p.y > retVal.bottom || isNaN(retVal.bottom))
retVal.bottom = p.y;
if(p.x < retVal.left || isNaN(retVal.left))
retVal.left = p.x;
if(p.y < retVal.top || isNaN(retVal.top))
retVal.top = p.y;
}
return retVal;
}
public function get bounds():Rectangle
{
if(_bounds)
return _bounds;
_bounds = calculateBounds();
return _bounds;
}
/**
* This is a NOP for this layouter.
* @inheritDoc
* */
public function refreshInit():void {
/* NOP */
}
/**
* This is a NOP for this layouter.
* @inheritDoc
* */
public function dragEvent(event:MouseEvent, vn:IVisualNode):void {
_bounds = null;
}
/**
* This is a NOP for this layouter.
* @inheritDoc
* */
public function dragContinue(event:MouseEvent, vn:IVisualNode):void {
// LogUtil.debug(_LOG, "Node: " + vn.node.stringid + " being DRAGGED...");
_bounds = null;
}
/**
* This is a NOP for this layouter.
* @inheritDoc
* */
public function dropEvent(event:MouseEvent, vn:IVisualNode):void {
_bounds = null;
}
/**
* This is a NOP for this layouter.
* @inheritDoc
* */
public function bgDragEvent(event:MouseEvent):void {
_bounds = null;
}
/**
* This is a NOP for this layouter.
* @inheritDoc
* */
public function bgDragContinue(event:MouseEvent):void {
_bounds = null;
}
/**
* This is a NOP for this layouter.
* @inheritDoc
* */
public function bgDropEvent(event:MouseEvent):void {
_bounds = null;
}
/**
* Allow to set the reference to the drawing object from
* derived classes. This is important because of the
* type issue, the _currentDrawing variable will be declared
* separately in each derived layouter, but this one must
* have access to it anyway, to do the animation
* @param dr The drawing object that needs to be assigned.
* */
protected function set currentDrawing(dr:BaseLayoutDrawing):void {
_currentDrawing = dr;
}
/**
* Sets the current absolute target coordinates of a node
* in the node's vnode. This does not yet move the node,
* as for this the vnode's commit() method must be called.
* @param n The node to get its target coordinates updated.
* */
protected function applyTargetCoordinates(n:INode):void {
var coords:Point;
/* add the points coordinates to its origin */
coords = _currentDrawing.getAbsCartCoordinates(n);
n.vnode.x = coords.x;
n.vnode.y = coords.y;
}
/**
* Applies the target coordinates to all nodes that
* are in the Dictionary object passed as argument.
* The items are expected to be VNodes (as typically
* a list of currently visible VNodes is passed).
* */
protected function applyTargetToNodes(vns:Array):void {
var vn:IVisualNode;
for each(vn in vns) {
/* should be visible otherwise somethings wrong */
if(!vn.isVisible) {
throw Error("received invisible vnode from list of visible vnodes");
}
applyTargetCoordinates(vn.node);
vn.commit();
}
}
private function forceRedraw(e:MouseEvent):void {
//e.updateAfterEvent();
}
}
}