Handling decorators rendering

Decorator rendering refers to the way nodes and links decorators are populated with a specific content extracted from the data they represent. When using Visualizer, nodes content can be defined using :

DefaultDecorator customization

The node (respectively link) decorator item renderer is by default set to DefaultDecorator, a renderer implementing the IDecoratorRenderer and ISelectable interface. The content of nodes are defined via several Visualizer properties.

Label properties

Look and feel properties

Decorators look and feel can be specified using visualizer style properties such as nodeDecoratorFontColor,linkDecoratorFontColor, nodeDecoratorBorderColor, linkDecoratorBorderColor, etc.

Using custom decorator renderer

A custom rendering class for nodes (respectively links) decorators can be specified through the nodeDecoratorRendererClass (respectively linkDecoratorRendererClass) property which contains a factory for node renderers. The Class must extend the DisplayObject class and implement IDecoratorRenderer for :

Combined with the nodeDecoratorRendererDataSource (respectively linkDecoratorRendererDataSource) class, the custom decorator renderer will be used to feed each node (respectively link) decorator with its visual content according to node (respectively link) data or some part of it.

As for node rendering, decorator renderer can implement the ISelectable interface in order to be able to change the decorator rendering according to its selection and highlight status. The following example shows how to use a custom node decorator renderer:
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
			   xmlns:s="library://ns.adobe.com/flex/spark" 
			   xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:visualizer="fr.kapit.visualizer.*">
	<fx:Script>
		<![CDATA[
			import fr.kapit.layouts.constants.EdgeDrawType;
			import mx.events.FlexEvent;
			import rendering.nodeRendering.decoratorRendering.CustomDecoratorRenderer;
			

			protected function visualizer_creationCompleteHandler(event:FlexEvent):void
			{
				visualizer.hierarchicalTreeLayout.edgeDrawing = EdgeDrawType.ORTHOGONAL_CURVED_POLYLINE;
				visualizer.hierarchicalTreeLayout.defaultNodeDistance = 60;
				visualizer.hierarchicalTreeLayout.layerDistance = 60;
			}

		]]>
	</fx:Script>
	<fx:Declarations>
		<fx:XML id="dp" xmlns="">
			<graphml>
				<node id="n1" name="Michael" colors="default,red,green,blue"/>	
				<node id="n2" name="Jack" colors="default,red,yellow,blue"/>	
				<node id="n3" name="Steeve" colors="default,red,green"/>
				<node id="n4" name="Ilyes" colors="default,red,green,yellow"/>
				<node id="n5" name="Cyril" colors="default,red,green"/>
				<edge id="e1" source="n5" target="n2"/>
				<edge id="e2" source="n2" target="n1"/>
				<edge id="e3" source="n2" target="n3"/>
				<edge id="e4" source="n5" target="n4"/>
			</graphml>
		</fx:XML>
	</fx:Declarations>
	
	<visualizer:Visualizer  id="visualizer"
							width="100%" height="100%"
						    layout="hierarchicalTree"
						    dataProvider="{dp}" 
						    nodeDecoratorRendererClass="{CustomDecoratorRenderer}"
						    nodeDecoratorRendererDataSource="colors"
						    nodeLabelFields="name"
						    creationComplete="visualizer_creationCompleteHandler(event)"
						   />
</s:Application>
The following file defines the CustomDecoratorRenderer used in the previous example:
<?xml version="1.0" encoding="utf-8"?>
<s:ComboBox xmlns:fx="http://ns.adobe.com/mxml/2009" 
			xmlns:s="library://ns.adobe.com/flex/spark" 
			xmlns:mx="library://ns.adobe.com/flex/mx" 
			implements="fr.kapit.visualizer.renderers.IDecoratorRenderer"
			labelField="colorName"
			change="combobox_changeHandler(event)"
			width="60"
			height="25"
			selectedIndex="0">
	<fx:Script>
		<![CDATA[
			import fr.kapit.visualizer.base.IItem;
			import fr.kapit.visualizer.base.ISprite;
			import fr.kapit.visualizer.renderers.DefaultItemRenderer;
			import fr.kapit.visualizer.renderers.IDecoratorRenderer;
			
			import mx.collections.ArrayCollection;
			import mx.utils.ColorUtil;
			
			import spark.events.IndexChangeEvent;
			private var _data:Object;
			public function get data():Object
			{
				return _data;
			}

			public function set data(value:Object):void
			{
				_data = value;
				dataProvider = new ArrayCollection(value.split(','));
			}
			
			private var _item:IItem;
			public function get item():IItem
			{
				return _item;
			}

			public function set item(value:IItem):void
			{
				_item = value;
			}

			private var _anchorX:Number=0;

			public function get anchorX():Number
			{
				return _anchorX;
			}

			public function set anchorX(value:Number):void
			{
				_anchorX =  value;
			}

			private var _anchorY:Number=0;
			public function get anchorY():Number
			{
				return _anchorY;
			}

			public function set anchorY(value:Number):void
			{
				_anchorY = value;
			}

			private var _isFixed:Boolean=true;
			public function get isFixed():Boolean
			{
				return _isFixed;
			}

			public function set isFixed(value:Boolean):void
			{
				_isFixed = value;
			}

			

			protected function combobox_changeHandler(event:IndexChangeEvent):void
			{
				var firstColor:uint;
				switch(selectedItem)
				{
					case "red" : firstColor=0xff0000;break;
					case "blue" : firstColor=0x0000ff;break;
					case "green" : firstColor=0x00ff00;break;
					case "yellow" : firstColor=0xfdfda7;break;
					default : firstColor=ISprite(_item).visualizer.firstColor;break;
					
				}
				if(_item is ISprite)
				{
					DefaultItemRenderer(ISprite(_item).itemRenderer).backgroundColors = [ColorUtil.adjustBrightness(firstColor,70),firstColor];
					DefaultItemRenderer(ISprite(_item).itemRenderer).update();
				}
			}

		]]>
	</fx:Script>
</s:ComboBox>

The output of this integration can be shown through this graph:

Using a rendering function

A node (respectively link) decorator rendering function can be specified via the nodeDecoratorRendererFunction (respectively linkDecoratorRendererFunction) property. The function takes as input the node data and according to it returns a custom DisplayObject instance (that implements IDecoratorRenderer interface as recommended). It is called at rendering time for each node (respectively link) decorator or when setting this property. The following snippet describes a nodeDecoratorRendererFunction used to return different components for node decoration according to data type property.
protected function myNodeDecoratorRendererFunction(data:Object):UIComponent 
{
	var myCustomComponent:MyNodeDecoratorRenderer; // A component extending Label class and implementing IDecoratorRenderer or IDataRenderer (for setting data).
	switch(data.type)
	{
		case 'blue' : myCustomComponent = new MyBlueNodeDecoratorRenderer();break; // MyBlueLinkDecoratorRenderer extends MyNodeDecoratorRenderer with blue font.
		case 'red' : myCustomComponent = new MyRedNodeDecoratorRenderer();break; // MyRedLinkDecoratorRenderer extends MyNodeDecoratorRenderer with red font.
		case 'gray' : myCustomComponent = new MyGrayNodeDecoratorRenderer();break; // MyGrayLinkDecoratorRenderer extends MyNodeDecoratorRenderer with gray font.
	}
	myCustomComponent.data=data;
	myCustomComponent.label=data.name;
   	myCustomComponent.width = 60;
	myCustomComponent.height = 25;
	return myCustomComponent;
 }