Using layouts

Using existing layouts

Layouts are used to position a graph nodes in a certain way. To use a layout in Visualizer or Diagrammer, the property layout should be set to the id of the layout to apply. In order to set a layout properties, you have to listen creationComplete event and set them in the event handler. The following example explain more how this should be done:
<fx:Script>
	<![CDATA[
		import fr.kapit.layouts.constants.EdgeDrawType;
		import mx.events.FlexEvent;
		
		private function onVisualizerCreationComplete(event:FlexEvent):void
		{
			visualizer.hierarchicalCyclicLayout.edgeDrawing = EdgeDrawType.ORTHOGONAL_CURVED_POLYLINE;
			visualizer.radialLayout.nodesSpacing = 40;
		}
	]]>
</fx:Script>
<mx:Panel width="100%" height="100%" title="Diagrammer">
	<visualizer:Visualizer id="visualizer" width="100%" height="100%" creationComplete="onVisualizerCreationComplete(event)"/>
</mx:Panel>

Creating custom layouts

To create a custom layout you have to implement the ILayout interface. A simple way to do it is to extend the Layout and override the following methods: The following code is a custom layout implementation that places nodes randomly according to the graph center.
package fr.kapit.tests.views.layouts
{
	import fr.kapit.layouts.algorithms.basic.Layout;
	import fr.kapit.layouts.model.Graph;
	import fr.kapit.layouts.model.Node;
	
	public class RandomLayout extends Layout
	{
		public static const ID:String = "random";
		/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
		*                         Properties                        *
		* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */	
		public override function get layoutID():String
		{
			return ID;
		}
		/**
		 * Constructor.
		 * @param graph The graph associated with this layout.
		 * @param root User defined root Node (Focus Node).
		 * 
		 */
		public function RandomLayout(g:Graph)
		{
			super(g);
		}
		protected override function preLayoutProcessing():void
		{
			super.preLayoutProcessing();
			_graph = _originalGraph;
		}
		/**
		 * @inheritDoc 
		 * 
		 */		
		protected override function performComputation():void
		{
			var node:Node;
			var w:Number = _graph.width;
			var h:Number = _graph.height;
			for each(node in _graph.nodes)
			{
				//Placing nodes randomly in the graph
				node.x = w*Math.random();
				node.y = h*Math.random();
			}
			if(enableMoveToCenter)
				moveToCenter();  // Moving graph to its previous center
			if(!graph.isRootGraph)
				graph.fitToContent(); // If the layouted group is a subgroup it should be autofitted to its content.
			updateStraightEdges(); // Assigning Edges paths
		}
		public override function getNewInstance(graph:Graph):Layout
		{
			return new RandomLayout(graph);
		}
	}
}
The custom layout should be then registered to be used in the Visualizer. In the following example, the layout has been registered and used to perform graph layout.
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx"
		 xmlns:visualizer="fr.kapit.visualizer.*"
		 implements="fr.kapit.tests.views.ITestUnit"
		 width="100%" height="100%">
	<fx:Script>
		<![CDATA[
			import fr.kapit.tests.views.ITestUnit;
			import mx.events.FlexEvent;
			public function get visualizer():Visualizer
			{
				return viz;
			}

			protected function viz_creationCompleteHandler(event:FlexEvent):void
			{
				viz.registerLayout(RandomLayout); // Registering the layout to be used.
				viz.layout = RandomLayout.ID;
			}

		]]>
	</fx:Script>
	<fx:Declarations>
		<fx:XML id="dataProvider" xmlns="">
			<graphml>
				<node id="n0" name="node0"/>
				<node id="n1" name="node1"/>
				<node id="n2" name="node2"/>
				<node id="n3" name="node3"/>
				<node id="n4" name="node4"/>
				<node id="n5" name="node5">
					<graph id="n5:" edgedefault="undirected">
						<node id="n5::n0" name="node5-0"/>
						<node id="n5::n1" name="node5-1"/>
						<node id="n5::n2" name="node5-2"/>
						<edge id="e0" source="n5::n0" target="n5::n2" type="type0"/>
						<edge id="e1" source="n5::n1" target="n5::n2" type="type1"/>
					</graph>
				</node>
				<node id="n6" name="node6">
					<graph id="n6:" edgedefault="undirected">
						<node id="n6::n0" name="node6-0">
							<graph id="n6::n0:" edgedefault="undirected">
								<node id="n6::n0::n0" name="node6-0-0"/>
							</graph>
						</node>
						<node id="n6::n1" name="node6-1"/>
						<node id="n6::n2" name="node6-2"/>
						<edge id="e10" source="n6::n1" target="n6::n0::n0" type="type10"/>
						<edge id="e11" source="n6::n1" target="n6::n2" type="type11"/>
					</graph>
				</node>
				<edge id="e2" source="n5::n2" target="n0" type="type2"/>
				<edge id="e3" source="n0" target="n2" type="type3"/>
				<edge id="e4" source="n0" target="n1" type="type4"/>
				<edge id="e5" source="n1" target="n3" type="type5"/>
				<edge id="e6" source="n3" target="n2" type="type6"/>
				<edge id="e7" source="n2" target="n4" type="type7"/>
				<edge id="e8" source="n3" target="n6::n1" type="type8"/>
				<edge id="e9" source="n6::n1" target="n4" type="type9"/>
			</graphml>
		</fx:XML>
	</fx:Declarations>
	
	<visualizer:Visualizer
		id="viz"
		top="50"
		width="100%" height="100%" 
		dataProvider="{dataProvider}"
		nodeLabelFields="id"
		creationComplete="viz_creationCompleteHandler(event)">
	</visualizer:Visualizer>
</s:Group>

Assigning specific layouts for subgroups

When applying a given layout on a graph, the layout is applied recursively on all groups at all levels. But, in some application scenarios, it is needed to assign different layouts for each group or for a specific group. There three ways for applying different layout for a given group (organized by priority) :
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009" 
		 xmlns:s="library://ns.adobe.com/flex/spark" 
		 xmlns:mx="library://ns.adobe.com/flex/mx"
		 xmlns:visualizer="fr.kapit.visualizer.*"
		 implements="fr.kapit.tests.views.ITestUnit"
		 width="100%" height="100%">
	<fx:Script>
		<![CDATA[
			import fr.kapit.layouts.algorithms.balloon.BalloonLayout;
			import fr.kapit.layouts.algorithms.bidirectionalHierarchical.BidirectionalHierarchicalLayout;
			import fr.kapit.layouts.algorithms.circular.SingleCycleCircularLayout;
			import fr.kapit.layouts.algorithms.forcedirected.fade.ProgressiveFadeLayout;
			import fr.kapit.layouts.algorithms.forcedirected.gem.StaticGEMLayout;
			import fr.kapit.layouts.algorithms.hierarchical.HierarchicalLayout;
			import fr.kapit.layouts.algorithms.mindmap.MindMapLayout;
			import fr.kapit.layouts.algorithms.orthogonal.OrthogonalLayout;
			import fr.kapit.layouts.algorithms.radial.RadialLayout;
			import fr.kapit.layouts.algorithms.sugiyama.SugiyamaLayout;
			import fr.kapit.tests.views.ITestUnit;
			import fr.kapit.visualizer.base.IGroup;
			
			import mx.collections.ArrayCollection;
			
			import spark.events.IndexChangeEvent;
			public function get visualizer():Visualizer
			{
				return viz;
			}
			
			protected function layoutCbx_changeHandler(event:IndexChangeEvent):void
			{
				var sprite:IGroup = viz.selection[0] as IGroup;
				if(!sprite)
					viz.layout = layoutCbx.selectedItem;
				else
					sprite.layout = layoutCbx.selectedItem;
			}
			

			protected function useGroupLayoutField_changeHandler(event:Event):void
			{
				if(useGroupLayoutField.selected)
					viz.groupLayoutField = "layout";
				else
					viz.groupLayoutField = null;
				
				viz.reLayout();
			}

		]]>
	</fx:Script>
	<fx:Declarations>
		<fx:XML id="dataProvider" xmlns="">
			<graphml>
				<node id="n0" name="node0"/>
				<node id="n1" name="node1"/>
				<node id="n2" name="node2"/>
				<node id="n3" name="node3"/>
				<node id="n4" name="node4"/>
				<node id="n5" name="node5" layout="forceDirected">
					<graph id="n5:" edgedefault="undirected">
						<node id="n5::n0" name="node5-0"/>
						<node id="n5::n1" name="node5-1"/>
						<node id="n5::n2" name="node5-2"/>
						<edge id="e0" source="n5::n0" target="n5::n2" type="type0"/>
						<edge id="e1" source="n5::n1" target="n5::n2" type="type1"/>
					</graph>
				</node>
				<node id="n6" name="node6" layout="singleCircular">
					<graph id="n6:" edgedefault="undirected">
						<node id="n6::n0" name="node6-0">
							<graph id="n6::n0:" edgedefault="undirected">
								<node id="n6::n0::n0" name="node6-0-0"/>
							</graph>
						</node>
						<node id="n6::n1" name="node6-1"/>
						<node id="n6::n2" name="node6-2"/>
						<edge id="e10" source="n6::n1" target="n6::n0::n0" type="type10"/>
						<edge id="e11" source="n6::n1" target="n6::n2" type="type11"/>
					</graph>
				</node>
				<edge id="e2" source="n5::n2" target="n0" type="type2"/>
				<edge id="e3" source="n0" target="n2" type="type3"/>
				<edge id="e4" source="n0" target="n1" type="type4"/>
				<edge id="e5" source="n1" target="n3" type="type5"/>
				<edge id="e6" source="n3" target="n2" type="type6"/>
				<edge id="e7" source="n2" target="n4" type="type7"/>
				<edge id="e8" source="n3" target="n6::n1" type="type8"/>
				<edge id="e9" source="n6::n1" target="n4" type="type9"/>
			</graphml>
		</fx:XML>
	</fx:Declarations>
	<s:HGroup width="100%" height="25" top="25">
		<s:ComboBox id="layoutCbx" dataProvider="{new ArrayCollection([SingleCycleCircularLayout.ID, HierarchicalLayout.ID, SugiyamaLayout.ID, OrthogonalLayout.ID, 
					RadialLayout.ID, BalloonLayout.ID,MindMapLayout.ID, BidirectionalHierarchicalLayout.ID, 
					StaticGEMLayout.ID, ProgressiveFadeLayout.ID])}" change="layoutCbx_changeHandler(event)"/>
		<s:CheckBox id="useGroupLayoutField" change="useGroupLayoutField_changeHandler(event)"/>
	</s:HGroup>
	<visualizer:Visualizer
		id="viz"
		top="50"
		width="100%" height="100%" 
		dataProvider="{dataProvider}"
		nodeLabelFields="name"
		linkDecoratorLabelFields="type"
		groupLabelField="name"
		coloringPolicy="bichromatic">
	</visualizer:Visualizer>
</s:Group>