diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java
index a26641578f87cf33ca20d1216e71e0959b5098a5..8126c89cb6b97ee8c1f82f7535fd304523371433 100644
--- a/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java
+++ b/Kieker.WebGUI/src/main/java/kieker/webgui/service/impl/GraphLayoutServiceImpl.java
@@ -17,7 +17,11 @@
 package kieker.webgui.service.impl;
 
 import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import org.springframework.stereotype.Service;
 
@@ -29,7 +33,6 @@ import org.eclipse.emf.common.util.EList;
 import de.cau.cs.kieler.core.alg.BasicProgressMonitor;
 import de.cau.cs.kieler.core.alg.IKielerProgressMonitor;
 import de.cau.cs.kieler.core.kgraph.KEdge;
-import de.cau.cs.kieler.core.kgraph.KLabeledGraphElement;
 import de.cau.cs.kieler.core.kgraph.KNode;
 import de.cau.cs.kieler.core.kgraph.KPort;
 import de.cau.cs.kieler.kiml.AbstractLayoutProvider;
@@ -58,10 +61,97 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 		// No code necessary
 	}
 
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see kieker.webgui.service.impl.IGraphLayoutService#layoutGraph(java.lang.String, java.lang.String)
+	 */
+	@Override
+	public String layoutGraph(final String nodes, final String edges) {
+		try {
+			final LayoutInformation layoutInformation = GraphLayoutServiceImpl.assembleLayoutInformation(nodes, edges);
+
+			// Create a progress monitor
+			final IKielerProgressMonitor progressMonitor = new BasicProgressMonitor();
+
+			// Create the layout provider
+			final AbstractLayoutProvider layoutProvider = new LayeredLayoutProvider();
+
+			// Perform layout on the created graph
+			layoutProvider.doLayout(layoutInformation.getGraph(), progressMonitor);
+
+			// convert layouted graph positions to String
+			final String layoutedGraph = GraphLayoutServiceImpl.getPositions(layoutInformation);
+			final String bendPoints = GraphLayoutServiceImpl.getBendPoints(layoutInformation);
+
+			final StringBuilder sb = new StringBuilder("autoLayout#");
+			sb.append(layoutedGraph);
+			sb.append("#");
+			sb.append(bendPoints);
+
+			return sb.toString();
+		} catch (final GraphLayoutException e) {
+			e.printStackTrace();
+			return "Error#Empty Graph!";
+		} catch (final NumberFormatException e) {
+			e.printStackTrace();
+			return "Error#Invalid Graph Information String!";
+		} catch (final Exception e) { // NOCS
+			e.printStackTrace();
+			return "Error#Unknown Error!";
+		}
+	}
+
+	/**
+	 * Assembles the necessary layout information using the given parameters.
+	 * 
+	 * @param nodesStr
+	 *            The string containing the information about the nodes.
+	 * @param edgesStr
+	 *            The string containing the information about the edges.
+	 * 
+	 * @return An object containing the layout information for the graph.
+	 */
+	private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) throws NumberFormatException, GraphLayoutException {
+		final int firstSemicolon = nodesStr.indexOf(';');
+
+		// if there is no semicolon, we got an empty graph
+		if (firstSemicolon < 0) {
+			throw new GraphLayoutException();
+		}
+
+		final int scale = Integer.parseInt(nodesStr.substring(0, firstSemicolon));
+
+		final String[] nodeInfo = GraphLayoutServiceImpl.correctEmptyArray(nodesStr.substring(firstSemicolon + 1).split(";"));
+		final String[] edgeInfo = GraphLayoutServiceImpl.correctEmptyArray(edgesStr.split(";"));
+
+		final Map<String, List<Object>> children = new HashMap<String, List<Object>>();
+		final Object[][] edges = new Object[edgeInfo.length][5];
+		final LayoutInformation layoutInformation = new LayoutInformation(KimlUtil.createInitializedNode(), children, edges);
+
+		GraphLayoutServiceImpl.addNodes(scale, nodeInfo, layoutInformation);
+		GraphLayoutServiceImpl.addEdges(edgeInfo, layoutInformation);
+		return layoutInformation;
+	}
+
+	/**
+	 * Parses a String array, building a graph with nodes and fixed ports.
+	 * 
+	 * @param scale
+	 *            The scale factor of the graph.
+	 * @param nodeInfo
+	 *            Information about the nodes: isItCustom?, width, height, parent, portInformation
+	 * @param layoutInformation
+	 *            The necessary information about the graph.
+	 * 
+	 * @throws NumberFormatException
+	 *             The nodeInfo should mostly be space separated numbers. If it is however invalid, this
+	 *             Exception will be thrown
+	 */
 	private static void addNodes(final int scale, final String[] nodeInfo, final LayoutInformation layoutInformation) throws NumberFormatException {
-		// define node and port list
-		final List<List<KLabeledGraphElement>> nodesAndPorts = layoutInformation.getNodesAndPorts();
-		List<KLabeledGraphElement> nodeAndPortList;
+		// define node HashMap port list
+		final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts();
+		List<Object> nodeAndPortList;
 
 		// retrieve size modifier
 		final int dimHalf = scale;
@@ -70,7 +160,7 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 		// loop variables //
 		String[] nodeProps;
 		KNode node;
-		int parentIndex;
+		String parentId;
 		KNode parent;
 		KPort port;
 		KShapeLayout layout;
@@ -89,54 +179,46 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 		int lp;
 		final int l = nodeInfo.length;
 
-		// -- 1. initialize empty nodes --
-		for (n = 0; n < l; n++) {
-			// init node
-			node = KimlUtil.createInitializedNode();
+		// nodeID : KNode, ParentID
 
-			// create a list that will contain the node itself
-			// as well as its ports (should they exist)
-			nodeAndPortList = new ArrayList<KLabeledGraphElement>();
-			nodeAndPortList.add(node);
-
-			// add the list to the global 2 dimensional list
-			nodesAndPorts.add(n, nodeAndPortList);
-		}
-
-		// -- 2. Define nodes by the properties, given in the string --
+		// -- 1. Define nodes by the properties, given in the string --
 		for (n = 0; n < l; n++) {
-			nodeProps = nodeInfo[n].split(" ");
-
-			// get Node from global list
-			node = (KNode) nodesAndPorts.get(n).get(0);
 
 			// i is our property array-pointer
 			i = 0;
+			nodeProps = nodeInfo[n].split(" ");
 
-			// retrieve node information
-			isNodeFamily = "f".equals(nodeProps[i++]);
-			width = Integer.parseInt(nodeProps[i++]);
-			height = Integer.parseInt(nodeProps[i++]);
+			// add entry to map
+			nodeAndPortList = new ArrayList<Object>();
+			nodesAndPorts.put(nodeProps[i++], nodeAndPortList);
+			// create empty node
+			node = KimlUtil.createInitializedNode();
+			nodeAndPortList.add(node);
 
-			// determine the parent of the node
-			parentIndex = Integer.parseInt(nodeProps[i++]);
-			if (parentIndex > 0) {
-				parent = (KNode) nodesAndPorts.get(parentIndex).get(0);
-				node.setParent(parent);
-			} else {
+			// get parentID
+			parentId = nodeProps[i++];
+			if ("-1".equals(parentId)) {
+				parentId = "";
 				node.setParent(layoutInformation.getGraph());
 			}
+			nodeAndPortList.add(parentId);
+
+			// get width and height
+			width = Integer.parseInt(nodeProps[i++]);
+			height = Integer.parseInt(nodeProps[i++]);
+
+			// get Custom Node tag
+			isNodeFamily = "f".equals(nodeProps[i++]);
 
-			// set node dimensions
+			// set width and height of KNode
 			layout = node.getData(KShapeLayout.class);
 			layout.setWidth(width);
 			layout.setHeight(height);
 
-			// parse port data if it is a NodeFamily
+			// if node is a NodeFamily, go on and look for ports
 			if (isNodeFamily) {
 
-				// let the node size be fixed for now
-				// (resizable nodeFamilies may be implemented in the future)
+				// nodeFamily size is fixed
 				layout.setProperty(LayoutOptions.PORT_CONSTRAINTS, PortConstraints.FIXED_POS);
 				portX = -dimHalf;
 
@@ -155,7 +237,7 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 						// create port
 						port = KimlUtil.createInitializedPort();
 						port.setNode(node);
-						nodesAndPorts.get(n).add(port);
+						nodeAndPortList.add(port);
 
 						// set layout for Port
 						layout = port.getData(KShapeLayout.class);
@@ -171,26 +253,61 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 				}
 			}
 		}
+
+		// -- 2. resolve stored parentIDs to actual parents
+		final Iterator<Entry<String, List<Object>>> it = nodesAndPorts.entrySet().iterator();
+		while (it.hasNext()) {
+			nodeAndPortList = (List<Object>) ((Entry) it.next()).getValue();
+
+			// get KNode and its parentID
+			node = (KNode) nodeAndPortList.get(0);
+			parentId = nodeAndPortList.get(1).toString();
+
+			// set other KNode as parent
+			if (!parentId.isEmpty()) {
+				parent = (KNode) nodesAndPorts.get(parentId).get(0);
+				node.setParent(parent);
+			}
+		}
 	}
 
+	/**
+	 * Parses an array which must contain quadruples of numbers.<br/>
+	 * The first number must be the index of the children-array, where
+	 * the source node is located.<br/>
+	 * The second number must be the index of the children-array, where
+	 * the target node is located.<br/>
+	 * The third number must be the index of the source node List, where
+	 * the source port is located.<br/>
+	 * The fourth number must be the index of the target node List, where
+	 * the target port is located.
+	 * 
+	 * @param edgeInfo
+	 *            The single elements for the edges.
+	 * @param layoutInformation
+	 *            The necessary information about the graph.
+	 * @throws UninitializedGraphException
+	 *             If the graph has not yet been initialized.
+	 */
 	private static void addEdges(final String[] edgeInfo, final LayoutInformation layoutInformation) throws NumberFormatException {
-		final List<List<KLabeledGraphElement>> nodesAndPorts = layoutInformation.getNodesAndPorts();
+		final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts();
 
 		// set up loop variables
 		String[] edgeProps;
 		KEdge edge;
 
-		int id;
+		String id;
 		boolean hasSourcePort;
+		Object[] edgeList;
 
 		KNode sourceNode;
 		int sourcePortIndex;
 		KPort sourcePort = null;
-		List<KLabeledGraphElement> sourceList;
+		List<Object> sourceList;
 
 		int targetPortIndex;
 		KPort targetPort;
-		List<KLabeledGraphElement> targetList;
+		List<Object> targetList;
 
 		int ea = 0;
 		int p;
@@ -200,48 +317,59 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 		for (final String element : edgeInfo) {
 
 			// get edge info of a single source
+			edgeList = layoutInformation.getEdges()[ea++];
 			edgeProps = element.split(" ");
 			p = 0;
 
 			// get source index and port
-			id = Integer.parseInt(edgeProps[p++]);
+			id = edgeProps[p++];
 			sourceList = nodesAndPorts.get(id);
 			sourceNode = (KNode) sourceList.get(0);
 
-			sourcePortIndex = Integer.parseInt(edgeProps[p++]) + 1;
-			hasSourcePort = sourcePortIndex != 0;
+			sourcePortIndex = Integer.parseInt(edgeProps[p++]);
+			edgeList[2] = sourcePortIndex;
+
+			hasSourcePort = ++sourcePortIndex != 0;
 
 			if (hasSourcePort) {
-				sourcePort = (KPort) sourceList.get(sourcePortIndex);
+				sourcePort = (KPort) sourceList.get(++sourcePortIndex);
 			}
 
 			// get target ports
 			epl = edgeProps.length;
 			while (p < epl) {
 
+				// init edge
+				edge = KimlUtil.createInitializedEdge();
+				edgeList[0] = edge;
+				edgeList[1] = id;
+
 				// get target index and port
-				id = Integer.parseInt(edgeProps[p++]);
+				id = edgeProps[p++];
+				edgeList[3] = id;
 				targetList = nodesAndPorts.get(id);
 
-				// define edge
-				edge = KimlUtil.createInitializedEdge();
+				// select connected nodes
 				edge.setSource(sourceNode);
 				edge.setTarget((KNode) targetList.get(0));
 
-				targetPortIndex = Integer.parseInt(edgeProps[p++]) + 1;
-				if (targetPortIndex != 0) {
-					targetPort = (KPort) targetList.get(targetPortIndex);
+				targetPortIndex = Integer.parseInt(edgeProps[p++]);
+				edgeList[4] = targetPortIndex;
+
+				if (++targetPortIndex != 0) {
+					targetPort = (KPort) targetList.get(++targetPortIndex);
 
 					// set target port of edge
 					edge.setTargetPort(targetPort);
 					targetPort.getEdges().add(edge);
 				}
+
 				if (hasSourcePort) {
 					// set source port of edge
 					edge.setSourcePort(sourcePort);
 					sourcePort.getEdges().add(edge);
 				}
-				layoutInformation.getEdges().add(ea++, edge);
+
 			}
 
 		}
@@ -255,90 +383,45 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 		}
 	}
 
-	private static LayoutInformation assembleLayoutInformation(final String nodesStr, final String edgesStr) throws GraphLayoutException {
-		final int firstSemicolon = nodesStr.indexOf(';');
-
-		// if there is no semicolon, we got an empty graph
-		if (firstSemicolon < 0) {
-			throw new GraphLayoutException("Empty graph");
-		}
-
-		final int scale = Integer.parseInt(nodesStr.substring(0, firstSemicolon));
-
-		final String[] nodeInfo = GraphLayoutServiceImpl.correctEmptyArray(nodesStr.substring(firstSemicolon + 1).split(";"));
-		final String[] edgeInfo = GraphLayoutServiceImpl.correctEmptyArray(edgesStr.split(";"));
-
-		final List<List<KLabeledGraphElement>> children = new ArrayList<List<KLabeledGraphElement>>(nodeInfo.length - 1);
-		final List<KEdge> edges = new ArrayList<KEdge>(edgeInfo.length);
-		final LayoutInformation layoutInformation = new LayoutInformation(KimlUtil.createInitializedNode(), children, edges);
-
-		GraphLayoutServiceImpl.addNodes(scale, nodeInfo, layoutInformation);
-		GraphLayoutServiceImpl.addEdges(edgeInfo, layoutInformation);
-
-		return layoutInformation;
-	}
-
-	/*
-	 * (non-Javadoc)
+	/**
+	 * Reads the (layouted) positions of a constructed KGraph and writes them as integers to a string, seperating each number with a space.
 	 * 
-	 * @see kieker.webgui.service.impl.IGraphLayoutService#layoutGraph(java.lang.String, java.lang.String)
+	 * @param layoutInformation
+	 *            The object containing the necessary information about the graph.
+	 * 
+	 * @return The constructed string.
 	 */
-	@Override
-	public String layoutGraph(final String nodes, final String edges) {
-		final String layoutedGraph;
-		final String bendPoints;
-
-		try {
-			final LayoutInformation layoutInformation = GraphLayoutServiceImpl.assembleLayoutInformation(nodes, edges);
-
-			// Create a progress monitor
-			final IKielerProgressMonitor progressMonitor = new BasicProgressMonitor();
-
-			// Create the layout provider
-			final AbstractLayoutProvider layoutProvider = new LayeredLayoutProvider();
-
-			// Perform layout on the created graph
-			layoutProvider.doLayout(layoutInformation.getGraph(), progressMonitor);
-
-			// convert layouted graph positions to String
-			layoutedGraph = GraphLayoutServiceImpl.getPositions(layoutInformation);
-			bendPoints = GraphLayoutServiceImpl.getBendPoints(layoutInformation);
-
-		} catch (final NumberFormatException e) {
-			throw new GraphLayoutException("Invalid Graph Information String", e);
-		}
-
-		return layoutedGraph + "#" + bendPoints;
-	}
-
 	private static String getPositions(final LayoutInformation layoutInformation) {
-
-		final List<List<KLabeledGraphElement>> nodesAndPorts = layoutInformation.getNodesAndPorts();
+		final Map<String, List<Object>> nodesAndPorts = layoutInformation.getNodesAndPorts();
 		final StringBuilder sb = new StringBuilder();
-		KShapeLayout layout;
-		KNode node;
-		int x;
-		int y; // position of node
-		int width;
-		int height;
 
-		for (final List<KLabeledGraphElement> list : nodesAndPorts) {
-			node = (KNode) list.get(0);
-			layout = node.getData(KShapeLayout.class);
-			x = Math.round(layout.getXpos() + (layout.getWidth() / 2));
+		// Run through all available entries
+		for (final Map.Entry<String, List<Object>> entry : nodesAndPorts.entrySet()) {
+			final String id = entry.getKey();
+			final List<Object> nodeAndPortList = entry.getValue();
 
-			// hotFix: wrong nodeFamily position: needs to be half the height lower
-			if (list.size() > 1) {
-				y = Math.round(layout.getYpos() + (layout.getHeight()));
+			final KShapeLayout layout = ((KNode) nodeAndPortList.get(0)).getData(KShapeLayout.class);
+
+			// Get the position of the node
+			final int posX = Math.round(layout.getXpos() + (layout.getWidth() / 2));
+			final int posY;
+			// HotFix: wrong nodeFamily position: needs to be half the height lower
+			if (nodeAndPortList.size() > 2) {
+				posY = Math.round(layout.getYpos() + (layout.getHeight()));
 			} else {
-				y = Math.round(layout.getYpos() + (layout.getHeight() / 2));
+				posY = Math.round(layout.getYpos() + (layout.getHeight() / 2));
 			}
 
-			width = Math.round(layout.getWidth());
-			height = Math.round(layout.getHeight());
-			sb.append(x);
+			// Get the size of the node
+			final int width = Math.round(layout.getWidth());
+			final int height = Math.round(layout.getHeight());
+
+			// Put everything into the string
+			sb.append(id);
 			sb.append(" ");
-			sb.append(y);
+			sb.append(posX);
+			sb.append(" ");
+			sb.append(posY);
 			sb.append(" ");
 			sb.append(width);
 			sb.append(" ");
@@ -349,21 +432,46 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 		return sb.toString();
 	}
 
+	/**
+	 * This method iterates through all edges of the given object and creates a semicolon separated String containing bend points of all edges.
+	 * 
+	 * @param layoutInformation
+	 *            The object containing the information about the graph and the layout.
+	 * @return The string containing the bend points.
+	 */
 	private static String getBendPoints(final LayoutInformation layoutInformation) {
 		final StringBuilder sb = new StringBuilder();
+		final Object[][] edges = layoutInformation.getEdges();
+
+		KEdge edge;
+		int e;
+
+		final int l = edges.length;
+		final int el = 4;
 
 		// iterate edges
-		for (final KEdge edge : layoutInformation.getEdges()) {
+		for (int i = 0; i < l; i++) {
+			e = 0;
+			edge = (KEdge) edges[i][e];
 
 			final KEdgeLayout layout = edge.getData(KEdgeLayout.class);
 			final EList<KPoint> bendPoints = layout.getBendPoints();
 
+			// add IDs and portIndices
+			while (++e < el) {
+				sb.append(edges[i][e].toString());
+				sb.append(" ");
+			}
+			sb.append(edges[i][4].toString());
+
 			// iterate bend points
 			final int bl = bendPoints.size();
 			KPoint point;
 
 			if (bl > 0) {
+
 				point = bendPoints.get(0);
+				sb.append(" ");
 				sb.append(Math.round(point.getX()));
 				sb.append(" ");
 				sb.append(Math.round(point.getY()));
@@ -391,8 +499,14 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 	private static class LayoutInformation {
 
 		private final KNode graph;
-		private final List<List<KLabeledGraphElement>> children;
-		private final List<KEdge> edges;
+		/**
+		 * An array containing the child node and the ports from left to right.
+		 */
+		private final Map<String, List<Object>> children;
+		/**
+		 * An array containing edges. This way we can return edge information in the same order.
+		 */
+		private final Object[][] edges;
 
 		/**
 		 * Creates a new instance of this class.
@@ -404,7 +518,7 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 		 * @param edges
 		 *            The edges of the graph.
 		 */
-		public LayoutInformation(final KNode graph, final List<List<KLabeledGraphElement>> children, final List<KEdge> edges) {
+		public LayoutInformation(final KNode graph, final Map<String, List<Object>> children, final Object[][] edges) { // NOPMD (array)
 			this.graph = graph;
 			this.children = children;
 			this.edges = edges;
@@ -416,16 +530,31 @@ public final class GraphLayoutServiceImpl implements IGraphLayoutService {
 
 		}
 
+		/**
+		 * Getter for the property {@link LayoutInformation#graph}.
+		 * 
+		 * @return The current value of the property.
+		 */
 		public KNode getGraph() {
 			return this.graph;
 		}
 
-		public List<List<KLabeledGraphElement>> getNodesAndPorts() {
+		/**
+		 * Getter for the property {@link LayoutInformation#children}.
+		 * 
+		 * @return The current value of the property.
+		 */
+		public Map<String, List<Object>> getNodesAndPorts() {
 			return this.children;
 		}
 
-		public List<KEdge> getEdges() {
-			return this.edges;
+		/**
+		 * Getter for the property {@link LayoutInformation#edges}.
+		 * 
+		 * @return The current value of the property.
+		 */
+		public Object[][] getEdges() {
+			return this.edges; // NOPMD (array)
 		}
 
 	}
diff --git a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
index 803f22fb73d1d2859a29d6fc12d6f522ba5c9e76..0a086156a9a2a7c00ac0e5927595e307e12209fe 100644
--- a/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
+++ b/Kieker.WebGUI/src/main/webapp/js/flowEditor.js
@@ -48,8 +48,6 @@ var Log = {
 };
 
 
-var testVar = "no";
-
 function GraphFlow(){
 	/////////////////////////////////////////////
 	//				VARIABLES				   //
@@ -62,14 +60,14 @@ function GraphFlow(){
 	
 	/** Colors */
 	var nodeFillColor = [];
-		nodeFillColor['nodeFamily']		= "#DEDEDE";
+	nodeFillColor['nodeFamily']		= "#DEDEDE";
 	
 	var nodeStrokeColor = [];
-		nodeStrokeColor['inputPort']   	  = "#AA0000";
-		nodeStrokeColor['outputPort']	  = "#AA0000";
-		nodeStrokeColor['repositoryPort'] = "#AA0000";
-		nodeStrokeColor['nodeFamily'] 	  = "#4D4D4D";
-		nodeStrokeColor['crossBox'] 	  = "#4D4D4D";
+	nodeStrokeColor['inputPort']   	  = "#AA0000";
+	nodeStrokeColor['outputPort']	  = "#AA0000";
+	nodeStrokeColor['repositoryPort'] = "#AA0000";
+	nodeStrokeColor['nodeFamily'] 	  = "#4D4D4D";
+	nodeStrokeColor['crossBox'] 	  = "#4D4D4D";
 		
 	var nodeColorFocus	  = "#0098BE",
 		edgeColor 		  = "#114270",
@@ -137,25 +135,44 @@ function GraphFlow(){
 		This information is needed to correctly draw the Grid and may come in handy in
 		future functions.
 		*/
-	var navi = { // screen position
-				 'centerX' : 0,
-				 'centerY' : 0,
-				 // these determine when the screen should move with a dragged node
-				 'borderLeft' : 0,
-				 'borderRight' : 0,
-				 'borderTop' : 0,
-				 'borderBottom' : 0,
-				 // memorize where we touch a node upon dragging
-				 'nodeOffsetX' : 0,
-				 'nodeOffsetY' : 0,
-				 // how far a node will be dragged
-				 'dragX' : null,
-				 'dragY' : null};
+	var navi = { 
+		 // screen position
+		 'centerX' : 0,
+		 'centerY' : 0,
+		 // these determine when the screen should move with a dragged node
+		/* 'borderLeft' : 0,
+		 'borderRight' : 0,
+		 'borderTop' : 0,
+		 'borderBottom' : 0,
+		 */
+		 // how far a the screen is dragged / where a dragged node is touched
+		 'dragX' : null,
+		 'dragY' : null};
+	
+	var animation = {
+		'enabled' : true,
+		'duration' : 1000
+	};
 	
 	/////////////////////////////////////////////
 	//				FUNCTIONS				   //
 	/////////////////////////////////////////////
 
+	
+	/**
+	 * Enables / Disables graph animation.
+	 * 
+	 * @param enabled - if true, animation is enabled
+	 * @param duration - the duration of animations
+	 */
+	this.setAnimation = function(enabled, duration){
+		
+		animation.enabled = enabled;
+		if(duration){
+			animation.duration = duration;
+		}
+	}
+	
 	/**
 	 * Measures the width of a text on the canvas
 	 * 
@@ -165,11 +182,13 @@ function GraphFlow(){
 	 */
 	this.getTextWidth = function(text, font){
 		
+		/*
 		// validate arguments
 		if(!validArg("getTextWidth()", text, "string") ||
 		   !validArg("getTextWidth()", font, "string")){
 			return;
 		}
+		*/
 			
 		// get canvas context
 		var ctx = fd.canvas.getCtx(),
@@ -203,12 +222,17 @@ function GraphFlow(){
 	this.addCustomNode = function(xPosition, yPosition, node, type, forced){
 		
 		// validate arguments
-		if(!validArg("addCustomNode()", xPosition, "number") ||
-		   !validArg("addCustomNode()", yPosition, "number") ||
-		   !validArg("addCustomNode()", type, "string") ||
-		   !validArgNode("addCustomNode()", node)){
+		var myName = "addCustomNode()";
+		
+		/*
+		if(!validArg(myName, xPosition, "number") ||
+		   !validArg(myName, yPosition, "number") ||
+		   !validArg(myName, type, "string") ||
+		   !validArgNode(myName, node) ||
+		   !validArgID(myName, node.id)){
 			return false;
 		}
+		*/
 		
 		var nodeType = 'Custom';
 		
@@ -262,12 +286,14 @@ function GraphFlow(){
 	 */
 	this.zoom = function(factor){
 		
+		/*
 		// check argument
 		if(!validArg("zoom()", factor, "number")){
 			return;
 		}else if(factor < 0){
 			callListener("onError", ["Error in function zoom(): Argument factor must be a positive number!"]);
 		}
+		*/
 		
 		// zoom
 		var canvas = fd.canvas;
@@ -310,8 +336,6 @@ function GraphFlow(){
 		}
 	}
 	
-	
-	
 	/**
 		Changes one or more properties of an edge immediately.
 		Converts label strings to arrays.
@@ -322,11 +346,13 @@ function GraphFlow(){
 	*/
 	this.setEdgeData = function(sourceID, targetID, properties){
 		
+		/*
 		// check arguments
 		if(!validArg("setEdgeData()", sourceID, "string") ||
 		   !validArg("setEdgeData()", targetID, "string")){
 			return;
 		}
+		*/
 		
 		var edge = fd.graph.getAdjacence(sourceID, targetID);
 		setObjectData(edge, properties);
@@ -341,10 +367,13 @@ function GraphFlow(){
 				  must start with a $.
 	 */
 	this.setNodeData = function(nodeID, properties){
+		
+		/*
 		// check argument
 		if(!validArg("setNodeData()", nodeID, "string")){
 			return;
 		}
+		*/
 		
 		var node = fd.graph.getNode(nodeID);
 		setObjectData(node, properties);
@@ -511,14 +540,171 @@ function GraphFlow(){
 	*/
 	this.autoLayout = function(){
 		
-	    // link node IDs to their index in the graph
-		var indexMap = {},
-			index = 0,
-			c;
-		
 		// link port IDs to their family index
-		var portMap = {};
+		var c, id, children, portMap = {};
+		
+		// list all parents of custom nodes
+		var data, parentMap = {};
+		iterateAllNodes(function(node){
+			
+			id = node.id;
+			data = node.data;
+			
+			if(data.$custom){
+				children = data.$children;
+				for(c in children){
+					c = children[c];
+					parentMap[c.id] = id;
+				}
+			}
+		});
+		
+		var nodes = [vertexLabelSize];
+		var edge, edgeMap = {};
+		var	nf, parentID, srcId;
+		var nodeY, height;
+		// map nodeIDs to indices
+		iterateAllNodes(function(node){
+			
+			data = node.data;
+			height = data.$height;
+			c = data.$custom;
+			nf = data.$type == 'nodeFamily';
+			
+			if(nf || c){
+				id = node.id;
+				
+				// check for parent
+				if(!(parentID = parentMap[id])){
+					parentID = -1;
+				}
+				localArr = [id,
+				            parentID,
+							data.$width,
+							height];
+				
+				// is Custom Node
+				if(c){
+					localArr.push('c'); 	// custom tag
+					
+					// create entry in edges
+					if(!(edge = edgeMap[id])){
+						edgeMap[id] = [id, -1];
+					}else{
+						edge[0] = id;
+						edge[1] = -1;
+					}
+					
+					// save edge info in edges-object
+					adja = node.adjacencies;
+					
+					for(a in adja){
+						a = adja[a].data.$direction;
+						srcId = a[0];
+						
+						// fill in info for all edges that have this node
+						// as a target
+						if(a[1] == id){
+							
+							if(!edgeMap[srcId]){
+								edgeMap[srcId] = ["", -1]
+							}
+							// add target info to edge
+							edgeMap[srcId].push(id, -1);
+						}
+					}
+				}
+				
+				// is NodeFamily
+				else{ 
+					localArr.push('f'); 	// family tag
+					// inputCount, inputYPos, repoCount...
+					localArr.push(0,0, 0,0, 0,0);
+					
+					// iterate ports and children
+					children = data.$children;
+					nodeY = node.pos.y;
+					pIndex = -1;
+					
+					for(c in children){
+						child = children[c];
+						
+						// increment node count and get relative y position of the topmost ports
+						switch(child.data.$type){
+							case "inputPort" : 
+								if(localArr[5]++ == 0){ 
+									localArr[6] = Math.round(child.pos.y - nodeY + height);
+								}
+								break;
+						
+							case "repositoryPort" : 
+								if(localArr[7]++ == 0){ 
+									localArr[8] = Math.round(child.pos.y - nodeY + height);
+								}
+								break;
+								
+							case "outputPort" : 
+								if(localArr[9]++ == 0){ 
+									localArr[10] = Math.round(child.pos.y - nodeY + height);
+								}
+								break;
+								
+							default : break;
+						}
+						
+						if(pIndex != -1){
+							// create entry in edges
+							if(!(edge = edgeMap[child.id])){
+								edgeMap[child.id] = [id, pIndex];
+							}else{
+								edge[0] = id;
+								edge[1] = pIndex;
+							}
+							
+							// save edge info in edges-object
+							adja = child.adjacencies;
+							
+							for(a in adja){
+								a = adja[a].data.$direction;
+								srcId = a[0];
+								
+								// fill in info for all edges that have this port
+								// as a target
+								if(a[1] == child.id){
+									
+									if(!edgeMap[srcId]){
+										edgeMap[srcId] = ["", -1]
+									}
+									// add target info to edge
+									edgeMap[srcId].push(id, pIndex);
+								}
+							}
+						}
+						pIndex++;
+					}
+				}
+				// convert node data to string and push it to Array
+				nodes.push(localArr.join(" "));
+			}
+		});
+		
+		// merge arrays to strings
+		var edges = [];
+		var t, source;
+		for(c in edgeMap){
+			c = edgeMap[c];
+			
+			if(c.length > 2){
+				source = c[0] + " " + c[1];
+				t = 2;
+				while(t < c.length){
+					target = " " + c[t++] + " " + c[t++];
+					edges.push(source + target);
+				}
+			}
+		}
 		
+		/*
 		// map nodeIDs to indices
 		iterateAllNodes(function(node){
 			
@@ -680,7 +866,7 @@ function GraphFlow(){
 			// convert node data to string and push it to Array
 			nodes.push(localArr.join(" "));
 			
-		}
+		}*/
 		
 		// fuse nodes array to a single string
 		nodes = nodes.join(";");
@@ -704,136 +890,188 @@ function GraphFlow(){
 	this.loadPositions = function(input){
 		console.log(input);
 		
+		// check if animation is in progress
+		var isAnimated = animation.enabled;
+		var usePortIndex;
 		var edgeInfo, nodeInfo;
+		var p = 0;
+		
 		{
 			var inputSplit = input.split("#");
-			
 			// catch Java Errors here
 			if(inputSplit[0] == "Error"){
 				callListener("onError", ["Error in GraphFlowLayouter.jar : " + inputSplit[1]]);
 				return;
 			}
 			
-			nodeInfo = inputSplit[0].split(";");
+			// check to see if we got the layout string from
+			// the autolayouter, because it looks a bit different
+			usePortIndex = inputSplit[0] == "autoLayout";
+			if(usePortIndex){
+				p++;
+			}
 			
+			nodeInfo = inputSplit[p++].split(";");
 			// bend points are optional
-			if(inputSplit[1] && inputSplit[1].length > 0){
-				edgeInfo = inputSplit[1].split(";");
+			if(inputSplit[p] && inputSplit[p].length > 0){
+				edgeInfo = inputSplit[p].split(";");
 			}
 
 		}
 		
-		// link node IDs to their index in the graph
-		var indexMap = {},
-			index = 0,
-			c;
-		
-		// map indices to nodeIDs
-		iterateAllNodes(function(node){
-			
-			c = node.data.$custom;
-			if(c || node.data.$type == 'nodeFamily'){
-				indexMap[index] = [c, node];
-				index++;
-			}
-		});
-		
 		// prepare loop variables
-		var node, data, adja, x, y, p = 0;
+		var node, data, adja, x, y;
 		
-		var width, height;
+		var left  	= Number.POSITIVE_INFINITY,
+			right 	= Number.NEGATIVE_INFINITY, 
+			top		= Number.POSITIVE_INFINITY, 
+			bottom	= Number.NEGATIVE_INFINITY;
 		
+		var id, width, height;
 		var xOffset = -grid.data.$width/2,
 			yOffset = -grid.data.$height/2;
 		
 		var nodeProps;
-		var gn, n, l;
+		var n, l;
+		
+		var endPos = new $jit.Complex(0,0);
+		var g = fd.graph;
 		
-		// iterate nodefamiles
+		// iterate node positions
 		for(n = 0, l = nodeInfo.length - 1; n < l; n++){
 			
-			// catch a layout String which is too long
-			if(!indexMap[n]){
-				callListener("onError", ["Error in loadGraphPositions() : Non-existent Nodes in layout string!"]);
-				fd.plot();
-				return;
-			}
-			
 			nodeProps = nodeInfo[n].split(" ");
 			p = 0;
 			
-			// extract positions from string array
-			x = parseFloat(nodeProps[p++]) + xOffset;
-			y = parseFloat(nodeProps[p++]) + yOffset;
-			width = parseFloat(nodeProps[p++]);
-			height = parseFloat(nodeProps[p]);
+			// lookup node in graph
+			id = nodeProps[p++];
+			node = g.getNode(id);
 			
-			// find node in graph and move/resize it
-			node = indexMap[n][1];
-			
-			// is custom node
-			if(indexMap[n][0]){
-				node.pos.setc(x, y);
-				node.setData('width', width, 'end');
-				node.setData('height', height, 'end');
+			if(!node){
+				callListener("onError", ["Error in loadGraphPositions() : Node with ID '"+ id + "' does not exist!"]);
 			}
-			// is nodeFamily
 			else{
-				moveNode(node, x, y);
-			}			
+				// extract positions from string array
+				x = parseFloat(nodeProps[p++]) + xOffset;
+				y = parseFloat(nodeProps[p++]) + yOffset;
+				width = parseFloat(nodeProps[p++]);
+				height = parseFloat(nodeProps[p]);
+				
+				// calculate new center of graph
+				left = Math.min(left, x - width / 2);
+				right = Math.max(right, x + width / 2);
+				top = Math.min(top, y - height / 2);
+				bottom = Math.max(bottom, y + height / 2);
+				
+				// is custom node
+				if(node.data.$custom){
+					
+					// set new position and dimensions
+					if(isAnimated){
+						endPos.x = x;
+						endPos.y = y;
+						node.setPos(endPos, "end");
+						node.setData('width', width, 'end');
+						node.setData('height', height, 'end');
+					}else{
+						node.pos.setc(x, y);
+						node.data.$width = width;
+						node.data.$height = height;
+					}
+				}
+				// is nodeFamily
+				else{
+					moveNode(node, x, y, isAnimated);
+				}	
+			}
 		}
 		
 		if(edgeInfo){
-			var adja, a;
-			
-			var e = 0;
-			var b, bendArray, bendPoints;
-			var el = edgeInfo.length;
-			
-			// iterate all nodes, looking for adjacencies
-			iterateAllNodes(function(node){
+			var adja;
+			var from, to;
+			var bl, b, bendArray, bendPoints;
+			var portIndex;
+			
+			for(n = 0, l = edgeInfo.length - 1; n < l; n++){
+				bendArray = edgeInfo[n].split(" ");
+				bl = bendArray.length;
+				b = 0;
 				
-				// stop if we have more edges than
-				// defined by out layout string
-				if(e >= el){
-					fd.plot();
-					return;
-				}
+				// get portIDs, using the familyID and the portIndex
+				if(usePortIndex){
+					node = g.getNode(bendArray[b++]);
+					data = node.data;
+					if(data.$custom){
+						from = node.id;
+					}else{
+						portIndex = parseInt(bendArray[b]);
+						from = data.$children[++portIndex].id
+					}
+					b++;
+					
+					node = g.getNode(bendArray[b++]);
+					data = node.data;
+					if(data.$custom){
+						to = node.id;
+					}else{
+						portIndex = parseInt(bendArray[b]);
+						to = data.$children[++portIndex].id
+					}
+					b++;
 				
-				adja = node.adjacencies;
+				// simply read the exact portIDs
+				}else{
+					from = bendArray[b++];
+					to = bendArray[b++];
+				}
 				
-				for(a in adja){
-					a = adja[a].data.$direction;
-					if(a[0] == node.id){
-						if(edgeInfo[e] != "" ){
-							// read from bend point string
-							bendArray = edgeInfo[e].split(" ");
-							bendPoints = [];
-							b = 0;
-							l = bendArray.length;
-							
-							while(b < l && bendArray[b] != "" ){
-								x = parseFloat(bendArray[b++]) + xOffset;
-								y = parseFloat(bendArray[b++]) + yOffset;
-								bendPoints.push({'x':x, 'y':y});
-							}
-							setBendPoints(a[0], a[1], bendPoints);	
-						}else{
-							setBendPoints(a[0], a[1], null);	
+				adja = g.getAdjacence(from, to);
+				if(!adja){
+					callListener("onError", ["Error in loadGraphPositions() : Edge between '"
+					                         + from + "' and '" + to + "' does not exist!"]);
+				}else{
+					// new bend points exist
+					if(b < bl){
+						
+						// read from bend point string
+						bendPoints = [];
+						while(b < bl){
+							x = parseFloat(bendArray[b++]) + xOffset;
+							y = parseFloat(bendArray[b++]) + yOffset;
+							bendPoints.push({'x':x, 'y':y});
 						}
-						e++;
+						adja.data.$bendPoints = bendPoints;	
+					}
+					// remove bend points
+					else{
+						adja.data.$bendPoints = null;	
 					}
 				}
-			});
+			}
+			
 		}
 		
-		/*
-		fd.animate({  
-			modes: ['node-property:width:height'],
-			transition: $jit.Trans.Cubic.easeInOut,
-			duration: 1000
-		}); */
-		fd.plot();
+		// translation values
+		var scale = fd.canvas.scaleOffsetX,
+			midX = - (left + right) / 2,
+			midY = - (top + bottom) / 2;
+		
+		if(isAnimated){
+			fd.canvas.translateOffsetXEnd = midX * scale;
+		  	fd.canvas.translateOffsetYEnd = midY * scale;
+		  	
+			fd.animate({  
+				modes: ['node-property:width:height', 'linear', 'canvas'],
+				transition: $jit.Trans.Cubic.easeInOut,
+				duration: animation.duration
+			}); 
+		}
+		else{
+			midX -= fd.canvas.translateOffsetX/scale;
+			midY -= fd.canvas.translateOffsetY/scale;
+			fd.canvas.translate(midX, midY);
+			fd.plot();
+		}
 		return;
 	}
 	
@@ -862,6 +1100,7 @@ function GraphFlow(){
 				nodePos = node.pos.getc(true);
 				
 				nodeProps = [
+				   node.id,
 				   Math.round(nodePos.x),
 				   Math.round(nodePos.y),
 				   data.$width,
@@ -876,8 +1115,13 @@ function GraphFlow(){
 				data = adja[a].data;
 				
 				if(data.$direction[0] == node.id){
-					// extract bendPoints
 					edgeProps = [];
+					
+					// save connected ids
+					edgeProps.push(node.id);
+					edgeProps.push(data.$direction[1]);
+					
+					// extract bendPoints
 					bendPoints = data.$bendPoints;
 					
 					for(b in bendPoints){
@@ -885,7 +1129,9 @@ function GraphFlow(){
 						edgeProps.push(bendPoints[b].y);
 					}
 					
-					edgeLayout.push(edgeProps.join(" "));
+					if(edgeProps.length > 2){
+						edgeLayout.push(edgeProps.join(" "));
+					}
 				}
 			}
 		});
@@ -910,8 +1156,8 @@ function GraphFlow(){
 		@returns - false if the string is not a well formed color string 
 	*/
 	this.validArgColor = function(callFunction, color){
-		var valid = false;
 		
+		var valid = false;
 		// is it a string at all ?
 		if(typeof color == "string"){
 			// does the string match "#RRGGBB" ?
@@ -937,11 +1183,13 @@ function GraphFlow(){
 	*/
 	this.validArgNode = function(callFunction, node){
 		var valid = false;
+		var id = node.id; 
 		
 		// is it an object at all ?
+		
 		if(node && typeof node == "object"){
 			// does the object have an id
-			valid = (typeof node.id != "undefined");
+			valid = (typeof id == "string");
 		}
 		
 		if(!valid){
@@ -951,7 +1199,13 @@ function GraphFlow(){
 			return valid;
 		}
 		
-		var id = node.id; 
+		valid = id[0] != "#";
+		if(!valid){
+			callListener("onError", ["Error in function "+ callFunction 
+										+ ": Invalid NodeID '"+ id 
+										+ "'. IDs may not start with #."]);
+			return valid;
+		}
 		
 		return valid;
 	}
@@ -968,7 +1222,6 @@ function GraphFlow(){
 	this.validArg = function(callFunction, arg, type){
 		var valid = (typeof arg == type);
 		if(!valid){
-			console.log(typeof arg);
 			callListener("onError", ["Error in function "+ callFunction 
 										+ ": Invalid argument type for argument '"
 										+ arg + "'. Must be of type " + type + "."]);
@@ -976,16 +1229,44 @@ function GraphFlow(){
 		return valid;
 	}
 	
+	
+	/**
+	Checks if a node ID is correct and non-existent in the graph.
+	Sends an onError-event if the argument ID not valid.
+	@param callFunction - the function where the argument needs to be checked
+	@param id - the id which is checked
+	@returns - false if the id is not a string or exists already
+	 */
+	this.validArgID = function(callFunction, id){
+		
+		// check if id is a string first
+		if (!validArg(callFunction, id, "string")){
+			return false;
+		}
+		
+		// check if node id is occupied
+		var nodeExists = fd.graph.getNode(id);
+		if(nodeExists){
+			callListener("onError", ["Error in function "+ callFunction 
+										+ ": Duplicate Node ID '"
+										+ id + "'."]);
+		}
+		return !nodeExists;
+	}
+	
 	/**
 		Changes the color of the grid.
 		@param newColor - the new color of the grid
 	*/
 	this.setGridColor = function(newColor){
-		if(validArgColor('setGridColor()', newColor)){
-			
-			grid.data.$color = newColor;
-			fd.plot();
+		/*
+		if(!validArgColor('setGridColor()', newColor)){
+			return;
 		}
+		*/
+			
+		grid.data.$color = newColor;
+		fd.plot();
 	}
 	
 	/**
@@ -993,10 +1274,14 @@ function GraphFlow(){
 		@param newSize - the new size of the grid
 	*/
 	this.setGridSize = function(newSize){
-		if(validArg('setGridSize()', newSize, 'number')){
-			grid.data.$dim = newSize;
-			fd.plot();
+		/*
+		if(!validArg('setGridSize()', newSize, 'number')){
+			return;
 		}
+		*/
+		grid.data.$dim = newSize;
+		fd.plot();
+		
 	}
 	
 	/**
@@ -1012,8 +1297,29 @@ function GraphFlow(){
 		@param visibility - must be true to display the graph
 	*/
 	this.setGridVisible = function(visibility){
-		grid.data.$visible = visibility;
-		fd.plot();
+		
+		isAnimated = animation.enabled;
+		var setter = 'current';
+		
+		if(isAnimated){
+			setter = 'end';
+		}
+		
+		if(visibility){
+			grid.setData('alpha', 1, setter);
+		}else{
+			grid.setData('alpha', 0, setter);
+		}
+		
+		if(isAnimated){
+			fd.animate({  
+				modes: ['node-property:alpha'],
+				transition: $jit.Trans.Cubic.easeInOut,
+				duration: animation.duration
+			});
+		}else{
+			fd.plot();
+		}
 	}
 	
 	/**
@@ -1021,81 +1327,82 @@ function GraphFlow(){
 		in which it is drawn.
 	*/
 	this.scaleToFit = function(){
-	// do nothing if the graph is empty
-	if(fd.graph.nodes.length == 1){
-		return;
-	}
-	
-	// init loop variables
-	var data,
-		width  = 0,
-		height = 0;
-	
-	var left  	= Number.POSITIVE_INFINITY,
-		right 	= Number.NEGATIVE_INFINITY, 
-		top		= Number.POSITIVE_INFINITY, 
-		bottom	= Number.NEGATIVE_INFINITY;
-	
-	// init the outer bounds of the displayed graph
-	var leftMost = left,
-		rightMost = right,
-		topMost = top,
-		bottomMost = bottom;
-	
-	// check nodeFamilies for position
-	iterateAllNodes(function(node){
-		data = node.data;
+		// do nothing if the graph is empty
+		if(fd.graph.nodes.length == 2){
+			return;
+		}
 		
-		if(data.$custom || data.$type == "nodeFamily"){
+		// init loop variables
+		var data,
+			width  = 0,
+			height = 0;
 		
-			width  = data.$width/2;
-			height = data.$height/2;
+		var left  	= Number.POSITIVE_INFINITY,
+			right 	= Number.NEGATIVE_INFINITY, 
+			top		= Number.POSITIVE_INFINITY, 
+			bottom	= Number.NEGATIVE_INFINITY;
 		
-			left  	= node.pos.x - width,
-			right 	= node.pos.x + width, 
-			top		= node.pos.y - height, 
-			bottom	= node.pos.y + height;
+		// init the outer bounds of the displayed graph
+		var leftMost = left,
+			rightMost = right,
+			topMost = top,
+			bottomMost = bottom;
+		
+		// check nodeFamilies for position
+		iterateAllNodes(function(node){
+			data = node.data;
 			
-			// update bounds
-			if(left < leftMost){
-				leftMost = left;
-			}
-			if(right > rightMost){
-				rightMost = right;
-			}
-			if(top < topMost){
-				topMost = top;
-			}
-			if(bottom > bottomMost){
-				bottomMost = bottom;
+			if(data.$custom || data.$type == "nodeFamily"){
+			
+				width  = data.$width/2;
+				height = data.$height/2;
+			
+				left  	= node.pos.x - width,
+				right 	= node.pos.x + width, 
+				top		= node.pos.y - height, 
+				bottom	= node.pos.y + height;
+				
+				// update bounds
+				if(left < leftMost){
+					leftMost = left;
+				}
+				if(right > rightMost){
+					rightMost = right;
+				}
+				if(top < topMost){
+					topMost = top;
+				}
+				if(bottom > bottomMost){
+					bottomMost = bottom;
+				}
 			}
-		}
-	});
-	
-	// scaling values
-	var canvas = fd.canvas,
-		oldScale = canvas.scaleOffsetX,
-		scaleX = grid.data.$width / (rightMost - leftMost + 4*vertexLabelSize),
-		scaleY = grid.data.$height / (bottomMost - topMost + 4*vertexLabelSize)
-		scale = Math.min(scaleX, scaleY) / oldScale;
+		});
 		
-	// translation values
-	var midX = (leftMost + rightMost) / 2,
-		midY = (topMost + bottomMost) / 2 - vertexLabelSize;
+		// scaling values
+		var canvas = fd.canvas,
+			oldScale = canvas.scaleOffsetX,
+			scaleX = grid.data.$width / (rightMost - leftMost + 4*vertexLabelSize),
+			scaleY = grid.data.$height / (bottomMost - topMost + 4*vertexLabelSize)
+			scale = Math.min(scaleX, scaleY) / oldScale;
+			
+		// translation values
+		var midX = (leftMost + rightMost) / 2,
+			midY = (topMost + bottomMost) / 2;
+			
 		
-	
-	// translate to origin, scale, and translate to the center of the graph
-	canvas.translate( -canvas.translateOffsetX/oldScale, -canvas.translateOffsetY/oldScale);
-	canvas.scale(scale, scale);
-	canvas.translate( -midX, -midY);
-	
-	// show text only if it is big enough
-	canvas.showLabels = (canvas.scaleOffsetX > canvas.labelThreshold);
-	
-	fd.plot();
+		// translate to origin, scale, and translate to the center of the graph
+		canvas.translate( -canvas.translateOffsetX/oldScale, -canvas.translateOffsetY/oldScale);
+		canvas.scale(scale, scale);
+		canvas.translate( -midX, -midY);
+		
+		// show text only if it is big enough
+		canvas.showLabels = (canvas.scaleOffsetX > canvas.labelThreshold);
+		
+		fd.plot();
 	}
 	
 	
+	
 	/**
 	Assigns an iconPath to a type of node.
 	@param nodeType - the type of the node. Typically 'Repository',
@@ -1109,9 +1416,11 @@ function GraphFlow(){
 	*/
 	this.setNodeIcon = function(nodeType, path, resizeImmediately){
 		// TODO: give refrence instead of icon to nodes
+		/*
 		if(!validArg('setNodeIcon()', nodeType, 'string')){
 			return;
 		}
+		*/
 	
 		if(path == null){
 			delete nodeIcons[nodeType];
@@ -1133,9 +1442,11 @@ function GraphFlow(){
 			return;
 		}
 		
+		/*
 		if(!validArg('setNodeIcon()', path, 'string')){
 			return;
 		}
+		*/
 		
 		var prevImage = nodeIcons[nodeType];
 		
@@ -1194,8 +1505,13 @@ function GraphFlow(){
 	this.setMouseCursor = function(newCursor){
 		if(newCursor == null){
 			fd.canvas.getElement().style.cursor = '';
-			
-		}else if(validArg('setMouseCursor()', newCursor, 'string')){
+		}
+		/*
+		else if(!validArg('setMouseCursor()', newCursor, 'string')){
+			return;
+		}
+		*/
+		else{
 			fd.canvas.getElement().style.cursor = newCursor;
 		}
 	}
@@ -1222,11 +1538,13 @@ function GraphFlow(){
 		@param listenerFunction - a function that may alter the graph
 	*/
 	this.addListener = function(eventName, listenerFunction){
+		/*
 		// check arguments
 		if(!validArg('addListener()', eventName, 'string') ||
 			!validArg('addListener()', listenerFunction, 'function')){
 				return;
 		}
+		*/
 	
 		if(listener[eventName] == undefined){
 			listener[eventName] = [];
@@ -1313,15 +1631,16 @@ function GraphFlow(){
 	@param nodeFunction - a single parameter function, called on a node.
 	*/
 	this.iterateAllNodes = function(nodeFunction){
-		
+		/*
 		// check arguments
 		if(!validArg('iterateAllNodes()', nodeFunction, 'function')){
 			return;
 		}
+		*/
 		
 		// filter out dummy nodes
 		fd.graph.eachNode(function(node){
-			if(node && node.id != "#DUMMY_MOUSE_NODE" && node.id != "#DUMMY_GRID_NODE"){
+			if(node && node.id[0] != "#"){
 				nodeFunction(node);
 			}
 		});
@@ -1337,20 +1656,20 @@ function GraphFlow(){
 	@param highlightColor - the of highlighted objects. If null, restore Edge Color from global Array.
 	*/
 	this.setNodeStyle = function(nodeType, fillColor, strokeColor, edgeColor, focusColor){
-		if(validArg('setNodeStyle()', nodeType, 'string')){
-		
-			if(fillColor && validArgColor('setNodeStyle()', fillColor)){
-				nodeFillColor[nodeType] = fillColor;
-			}
-			if(strokeColor && validArgColor('setNodeStyle()', strokeColor)){
-				nodeStrokeColor[nodeType] = strokeColor;
-			}
+		if(!validArg('setNodeStyle()', nodeType, 'string')){
+			return;
 		}
 		
-		if(edgeColor && validArgColor('setNodeStyle()', edgeColor)){
+		if(fillColor /*&& validArgColor('setNodeStyle()', fillColor)*/){
+			nodeFillColor[nodeType] = fillColor;
+		}
+		if(strokeColor /*&& validArgColor('setNodeStyle()', strokeColor)*/){
+			nodeStrokeColor[nodeType] = strokeColor;
+		}
+		if(edgeColor /*&& validArgColor('setNodeStyle()', edgeColor)*/){
 			edgeColor = edgeColor;
 		}
-		if(focusColor && validArgColor('setNodeStyle()', focusColor)){
+		if(focusColor /*&& validArgColor('setNodeStyle()', focusColor)*/){
 			edgeColorFocus = focusColor;
 			nodeColorFocus = focusColor;
 		}
@@ -1427,25 +1746,26 @@ function GraphFlow(){
 	if(repositoryPorts){
 		countRepo = repositoryPorts.length;
 		// check if it is an array
-		if(!validArg(caller, repositoryPorts, 'object') || !countRepo){
+		if(/*!validArg(caller, repositoryPorts, 'object') ||*/ !countRepo){
 			countRepo = 0;
 		}
 	}
 	if(inputPorts){
 		countInput = inputPorts.length;
 		// check if it is an array
-		if(!validArg(caller, inputPorts, 'object') || !countInput){
+		if(/*!validArg(caller, inputPorts, 'object') ||*/ !countInput){
 			countInput = 0;
 		}
 	}
 	if(outputPorts){
 		countOutput = outputPorts.length;
 		// check if it is an array
-		if(!validArg(caller, outputPorts, 'object') || !countOutput){
+		if(/*!validArg(caller, outputPorts, 'object') ||*/ !countOutput){
 			countOutput = 0;
 		}
 	}
 	
+	/*
 	// check for other illegal arguments
 	var caller = 'addNode()';
 	if(!validArg(caller, xPosition, 'number')){
@@ -1460,6 +1780,10 @@ function GraphFlow(){
 	if(!validArgNode(caller, nodeFamily)){
 		return;
 	}
+	if(!validArgID(caller, nodeFamily.id)){
+		return;
+	}
+	*/
 	
 	var maxPorts = Math.max(countInput, countRepo+countOutput+0.5),
 		size = vertexLabelSize*2;
@@ -1541,7 +1865,7 @@ function GraphFlow(){
 	
 	// set node positions
 	newNode.pos.setc(xPosition, yPosition);
-	closeButton.pos.setc(xPosition + width/2, yPosition - height/2);
+	closeButton.pos.setc(xPosition + (width - vertexLabelSize) / 2 , yPosition - height / 2 + size);
 	newNode.data.$children.push(closeButton);
 	
 	// Loop Info: 
@@ -1589,13 +1913,14 @@ function GraphFlow(){
 		
 			x = xPosition + relativeX;
 			y = yPosition + relativeY;
-			
+			var port, portID;
 			for(var p=0; p < loopPorts.length; p++){
-				var port = loopPorts[p];
+				port = loopPorts[p];
 				
-				// only attempt to add a node if it has an id
-				if(validArgNode(caller, port)){
+				// only attempt to add a node if it has a valid id
+				portID = nodeFamily.id+"."+port.id;
 				
+				//if(validArgNode(caller, port) && validArgID(caller, portID)){
 					var newPort ={
 						  "adjacencies": [], 
 						  "data": {
@@ -1606,20 +1931,16 @@ function GraphFlow(){
 							"$tooltip": port.tooltip,
 							"$movable" : false,
 							"$symbol": port.symbol}, 
-						  "id": nodeFamily.id+"."+port.id, 
+						  "id": portID, 
 						  "name": port.name};
-						  
-					/*if(p == 0){
-						newPort.data.$relativeX= relativeX;
-						newPort.data.$relativeY= relativeY;
-					}*/
+					
 					g.addNode(newPort);
 					newPort = g.getNode(newPort.id);
 					newPort.pos.setc(x, y);
 					newNode.data.$children.push(newPort);
 					
 					y += size;
-				}
+				//}
 			}
 		}
 	}
@@ -1640,11 +1961,14 @@ function GraphFlow(){
 						event listeners will be called
 	*/
 	this.removeNode =  function(nodeFamily, removeChildren, forced){
-	
+		
+		/*
 		// check for valid arguments
 		if(!validArgNode("removeNode()", nodeFamily)){
 			return;
 		}
+		*/
+		
 		// call listener
 		if(!forced && !callListener("onRemoveNode", [nodeFamily])){
 			return;
@@ -1679,9 +2003,12 @@ function GraphFlow(){
 		@param node - the node to be moved
 		@param xPos - the horizontal position of the moved node. 0 is the center of the canvas' starting position
 		@param yPos - the vertical position of the moved node. 0 is the center of the canvas' starting position
+		@param smoothMove - used for smooth animation in autoLayout
 	 */
-	 function moveNode(node, x, y){
+	 function moveNode(node, x, y, smoothMove){
 	
+		var isAnimated = smoothMove;
+		 
 		// snap to grid
 		if(grid.data.$snap){
 			var gridDim = grid.data.$dim,
@@ -1747,9 +2074,12 @@ function GraphFlow(){
 			deltaY = y - pos.y;
 		
 		// move parent
-		node.pos.setc(x, y);
+		if(isAnimated){
+			node.setPos(new $jit.Complex(x, y), "end");
+		}else{
+			node.pos.setc(x, y);
+		}
 		
-		//customEdgeMap[sourcePort.data.$type].getOffset(sourcePort, targetPort, true, edgeData)
 		 
 		// move children in relation to their parent
 		var children = node.data.$children,
@@ -1759,8 +2089,7 @@ function GraphFlow(){
 				 
 				 child = children[c];
 				 pos = child.pos.getc(true);
-				 moveNode(child, pos.x + deltaX, pos.y + deltaY);
-				 //child.pos.setc(pos.x + deltaX, pos.y + deltaY);
+				 moveNode(child, pos.x + deltaX, pos.y + deltaY, isAnimated);
 			 }
 		}
 	 }
@@ -1777,6 +2106,7 @@ function GraphFlow(){
    *  @return true - if the edge was successfully added
    */
 	this.addEdge = function(sourceID, targetID, edgeLabel, edgeData, forced){
+		/*
 		// check for valid arguments
 		if(!validArg("addEdge()", sourceID, "string")){
 			return false;
@@ -1784,6 +2114,11 @@ function GraphFlow(){
 		if(!validArg("addEdge()", targetID, "string")){
 			return false;
 		}
+		*/
+		if(edgeLabel && typeof edgeLabel == "string"){
+			edgeLabel = edgeLabel.split('\n');
+		}
+		/*
 		if(edgeLabel){
 			if(typeof edgeLabel == 'object'){
 				// do nothing
@@ -1793,6 +2128,7 @@ function GraphFlow(){
 				edgeLabel = null;
 			}
 		}
+		*/
 		
 		// look up the nodes which are to be connected
 		var g = fd.graph;
@@ -1940,6 +2276,7 @@ function GraphFlow(){
 		@param bendPoints - an array of {"x":..., "y":...} objects
   */
   this.setBendPoints = function(sourceID, targetID, bendPoints){
+	  	/*
 		// check for valid arguments
 		if(!validArg("setBendPoints()", sourceID, "string")){
 			return false;
@@ -1947,6 +2284,7 @@ function GraphFlow(){
 		if(!validArg("setBendPoints()", targetID, "string")){
 			return false;
 		}
+		*/
 		
 		// change data
 		fd.graph.getAdjacence(sourceID, targetID).data.$bendPoints = bendPoints;
@@ -1963,6 +2301,7 @@ function GraphFlow(){
 					does not trigger a listener event
 	*/
   this.removeEdge = function(sourceID, targetID, forced){
+	/*
 	// check for valid arguments
 	if(!validArg("removeEdge()", sourceID, "string")){
 		return;
@@ -1970,6 +2309,7 @@ function GraphFlow(){
 	if(!validArg("removeEdge()", targetID, "string")){
 		return;
 	}
+	*/
   
 	// look up the source node and the nodeFamilies of both nodes
 	var g = fd.graph,
@@ -2023,11 +2363,12 @@ function GraphFlow(){
   @return - the node object or null if the node does not exist
   */
   this.getNode = function(nodeID){
-	  
+	/*
 	// check for valid arguments
 	if(!validArg("getNode()", nodeID, "string")){
 		return;
 	}
+	*/
 	
 	return fd.graph.getNode(nodeID);
   }
@@ -2038,30 +2379,38 @@ function GraphFlow(){
 	Highlights exactly one node or edge, and un-highlights the previously highlighted
 	node or edge.
 	@param node - the node or edge object which will be highlighted
+	@param noAnim - does not animate the highlight. Used by loadPositions()
 	*/
-  function setHighlight(node){
+  function setHighlight(node, noAnim){
+	  
+	  var setter = 'current';
+	  var isAnimated = animation.enabled;
+	  if(isAnimated){
+		  setter = 'end';
+	  }
+	  
 		// animation parameters
 		var trans = $jit.Trans.Quint.easeOut, 
-			dur= 200;
+			dur = animation.duration / 4;
 		
 		// clean up the old highlight
 		if(hover){
 			
 			if(hover.nodeFrom){
-				hover.setData('lineWidth', 1, 'end');
-				hover.setData('color', edgeColor, 'end');
+				hover.setData('lineWidth', 1, setter);
+				hover.setData('color', edgeColor, setter);
 			}
 			else{
 				var type = hover.data.$type;
 				if(markedNode != null && hover.id == markedNode.node.id){
-					hover.setData('color', markedNode.strokeColor, 'end');
+					hover.setData('color', markedNode.strokeColor, setter);
 				}
 				else{
-					hover.setData('color', nodeStrokeColor[type], 'end');
+					hover.setData('color', nodeStrokeColor[type], setter);
 				}
 				// decrease size of ports and cross button
 				if(type == 'inputPort' || type == 'outputPort' || type == 'repositoryPort'){
-					hover.setData('dim', vertexLabelSize*2, 'end');
+					hover.setData('dim', vertexLabelSize*2, setter);
 				}
 				
 			}
@@ -2071,33 +2420,42 @@ function GraphFlow(){
 		// do we highlight something new?
 		if(node != null){
 			if(node.nodeFrom != undefined){
-				node.setData('color', edgeColorFocus, 'end');
-				node.setData('lineWidth', 2, 'end');
+				node.setData('color', edgeColorFocus, setter);
+				node.setData('lineWidth', 2, setter);
 			}else{
-				node.setData('color', nodeColorFocus, 'end');
+				node.setData('color', nodeColorFocus, setter);
 				
 				// increase size of ports and cross button
 				var type = node.data.$type;
 				if(type == 'inputPort' || type == 'outputPort' || type == 'repositoryPort'){
-					node.setData('dim', vertexLabelSize*3, 'end');
+					node.setData('dim', vertexLabelSize*3, setter);
 				}
 			}
 			hover = node;
 		}else{
 			// slower fade away transition
 			trans = $jit.Trans.Quint.easeIn;
-			dur = 400;
+			dur *= 2;
+		}
+		
+		if(noAnim){
+			return;
 		}
 		
 		// Animations overwrite each other. If we let this animation
 		// execute while we delete an edge, the onComplete() function
 		// of the edge animation will not be called
-		fd.animate({  
-				modes: ['edge-property:lineWidth:color',
-						'node-property:color:dim'],
-				transition: trans,  
-				duration: dur
-		}); 
+		if(isAnimated){
+			fd.animate({  
+					modes: ['edge-property:lineWidth:color',
+							'node-property:color:dim'],
+					transition: trans,  
+					duration: dur
+			});
+		}else{
+			fd.plot();
+		}
+		
   }
   
   /**
@@ -2112,7 +2470,14 @@ function GraphFlow(){
 	*/
   this.markNode = function(node, strokeColor, fillColor){
   
+	  	var isAnimated = animation.enabled;
+	  	var setter = 'current';
+	  	if(isAnimated){
+	  		setter = 'end';
+	  	}
+	  
 		// check for valid arguments
+		/*
 		if(node && !validArgNode("markNode()", node)){
 			return;
 		}
@@ -2122,6 +2487,7 @@ function GraphFlow(){
 		if(fillColor && !validArgColor("markNode()", fillColor)){
 			return;
 		}
+		*/
 		
 		// clean up the old marking
 		if(markedNode){
@@ -2131,11 +2497,11 @@ function GraphFlow(){
 			}
 			else{
 				var type = markedNode.node.data.$type;
-				markedNode.node.setData('color', nodeStrokeColor[type], 'end');
+				markedNode.node.setData('color', nodeStrokeColor[type], setter);
 				
 				// change FillColor only if it exists
 				if(nodeFillColor[type]){
-					markedNode.node.setData('fillColor', nodeFillColor[type], 'end');
+					markedNode.node.setData('fillColor', nodeFillColor[type], setter);
 				}
 			}
 			markedNode = null;
@@ -2148,24 +2514,28 @@ function GraphFlow(){
 				// ignore edges
 			}else{
 				if(strokeColor != null){
-					node.setData('color', strokeColor, 'end');
+					node.setData('color', strokeColor, setter);
 				}
 				
 				// change FillColor only if it exists
 				if(fillColor != null  && nodeFillColor[node.data.$type]){
-					node.setData('fillColor', fillColor, 'end');
+					node.setData('fillColor', fillColor, setter);
 				}
 			}
 			markedNode = { 'strokeColor' : strokeColor, 'fillColor' : fillColor, 'node' : node};
 		}
 		
-		// we need a 0-frame animation to change the colors
-		fd.animate({  
-			modes: ['edge-property:color',
-					'node-property:color'],
-			transition: $jit.Trans.Quint.easeOut,  
-			duration: 0
-		}); 
+		// animate
+		if(isAnimated){
+			fd.animate({  
+				modes: ['edge-property:color',
+						'node-property:color'],
+				transition: $jit.Trans.Quint.easeOut,  
+				duration: animation.duration / 2
+			}); 
+		}else{
+			fd.plot();
+		}
   }
   
   /**
@@ -2210,29 +2580,32 @@ function GraphFlow(){
 	json.push({
 	  "adjacencies": [], 
 	  "data": {
-		"$dim": 0,
-		"$type": "none",
-		"&xPos": 0,
-		"&typeSelected" : null,
-		"&yPos": 0
+		"$type": "none"
 	  }, 
-	  "id": "#DUMMY_MOUSE_NODE", 
-	  "name": "",
-	  "alpha": 0
-	});
+	  "id": "#DUMMY_MOUSE_NODE"
+	},
 	
 	// define gridNode
-	json.push({ 
-		'data': {
-			'$dim' : vertexLabelSize*4,
-			'$type'	 : 'grid',
-			'$color'  : '#AAAAFF',
-			'$width' : document.getElementById(visContainer).clientWidth,
-			'$height': document.getElementById(visContainer).clientHeight,
-			'$visible' : false,
-			'$snap'   : false
-		},
-		'id':	'#DUMMY_GRID_NODE',
+	{ 
+	'data': {
+		'$dim' : vertexLabelSize*4,
+		'$type'	 : 'grid',
+		'$color'  : '#AAAAFF',
+		'$width' : document.getElementById(visContainer).clientWidth,
+		'$height': document.getElementById(visContainer).clientHeight,
+		'$alpha' : 0,
+		'$snap'   : false
+	},
+	'id':	'#DUMMY_GRID_NODE'
+	},
+	
+	// define canvas node
+	{ 
+	'data': {
+		'$dim' 	 : vertexLabelSize*4,
+		'$type'	 : 'none'
+	},
+	'id':	'#DUMMY_NAV_NODE'
 	});
 	
 	
@@ -2294,6 +2667,7 @@ function GraphFlow(){
 			  }
 			}  
 		 },  
+		 
 		// Add node events
 		Events: {
 		  enable: true,
@@ -2375,7 +2749,7 @@ function GraphFlow(){
 		  var mousePos = eventInfo.getPos();
 		  
 		  // dragging the canvas
-			if(node == false || node.id == mouseNode.id ||
+			if(!node || node.id == mouseNode.id ||
 			   !node.data.$movable){
 				
 			    navi.dragX = e.layerX; //e.pageX;
@@ -2391,8 +2765,8 @@ function GraphFlow(){
 				var	nodePos = node.pos.getc(true);
 				// the offset between the center of the node and the actual position
 				// where we grabbed the node
-				navi.nodeOffsetX = nodePos.x - mousePos.x;
-				navi.nodeOffsetY = nodePos.y - mousePos.y;
+				navi.dragX = nodePos.x - mousePos.x;
+				navi.dragY = nodePos.y - mousePos.y;
 				
 				/*
 				// memorize the node position before node movement
@@ -2419,8 +2793,8 @@ function GraphFlow(){
 			
 			// move node
 			var pos = eventInfo.getPos(),
-				x = pos.x + navi.nodeOffsetX,
-				y = pos.y + navi.nodeOffsetY;
+				x = pos.x + navi.dragX,
+				y = pos.y + navi.dragY;
 			moveNode(node, x, y);
 			
 			// move screen if near edge
@@ -2591,7 +2965,6 @@ function GraphFlow(){
 	  // load JSON data.
 	  fd.loadJSON(json, 0);
 	  
-	  
 	  // set pointers to grid and mouse node
 	  mouseNode = fd.graph.getNode("#DUMMY_MOUSE_NODE");
 	  grid = fd.graph.getNode("#DUMMY_GRID_NODE");
@@ -2600,6 +2973,7 @@ function GraphFlow(){
 	  fd.canvas.labelThreshold = 1/vertexLabelSize;
 	  fd.canvas.showLabels = true;
 	  
+	  console.log(fd.canvas);
 	  console.log(fd.graph);
 	}
 	
diff --git a/Kieker.WebGUI/src/main/webapp/js/jit.js b/Kieker.WebGUI/src/main/webapp/js/jit.js
index 16a120d2e10205cc91e9d42de407d63ff57efe83..f4626464f35bd6f3c73e2207400e39b61fbbb33c 100644
--- a/Kieker.WebGUI/src/main/webapp/js/jit.js
+++ b/Kieker.WebGUI/src/main/webapp/js/jit.js
@@ -816,7 +816,7 @@ var Animation = new Class( {
   initialize: function(options){
     this.setOptions(options);
   },
-
+  
   setOptions: function(options){
     var opt = {
       duration: 2500,
@@ -2905,6 +2905,7 @@ var Canvas;
         this.canvases[i].translate(x, y, disablePlot);
       }
     },
+    
     /*
       Method: scale
       
@@ -4622,6 +4623,7 @@ Graph.Node = new Class({
   */
   setPos: function(value, type) {
       type = type || "current";
+      
       var pos;
       if(type == "current") {
         pos = this.pos;
@@ -16978,6 +16980,12 @@ $jit.GraphFlow = new Class( {
     this.json = null;
     this.busy = false;
     
+    this.animationFix = {
+    	'duration' : 0,
+    	'busy' : false,
+    	'map' : undefined
+    };
+    
     //overwrite faulty click function
     this.Classes.Events.prototype.onMouseDown = function(e, win, event) {
         var evt = $.event.get(e, win);
@@ -16989,10 +16997,30 @@ $jit.GraphFlow = new Class( {
         }
         this.config.onDragStart(this.pressed, event, evt);
       };
+      
+    // extend Interpolator for new values
+    var that = this;
+    var iMap = this.fx.Interpolator.map;
+    
+    this.fx.Interpolator.canvas = 
+    	function(c, delta){
+    		var scale = c.scaleOffsetX;
+	    	var fromX = c.translateOffsetX/scale,
+				fromY = c.translateOffsetY/scale;
+			var toX = c.translateOffsetXEnd/scale,
+				toY = c.translateOffsetYEnd/scale;
+		  
+			var newX = that.fx.Interpolator.compute(fromX, toX, delta),
+				newY = that.fx.Interpolator.compute(fromY, toY, delta);
+			
+			c.translate(newX-fromX, newY-fromY);
+    	};
+    	
+    iMap.fillColor = "color"; 
+    // "number", "array-number"
     
     // initialize extras
     this.initializeExtras();
-	
   },
   
   /* 
@@ -17113,7 +17141,7 @@ $jit.GraphFlow = new Class( {
 $jit.GraphFlow.$extend = true;
 
 (function(GraphFlow) {
-
+	
   /*
      Class: GraphFlow.Op
      
@@ -17156,32 +17184,56 @@ $jit.GraphFlow.$extend = true;
 	 */
 	animate: function(opt, versor) {
 	    opt = $.merge(this.viz.config, opt || {});
+	    
 	    var that = this,
 	        viz = this.viz,
+	        animFix = viz.animationFix,
 	        graph  = viz.graph,
 	        interp = this.Interpolator,
 	        animation =  opt.type === 'nodefx'? this.nodeFxAnimation : this.animation;
-	    //prepare graph values
-	    var m = this.prepare(opt.modes);
 	    
+	    // merge animation properties
+	    if(animFix.busy){
+	    	animFix.map = $.merge(animFix.map, this.prepare(opt.modes));
+			
+	    }else{
+	    	animFix.map = this.prepare(opt.modes);
+	    	animFix.busy = true;
+	    }
+	    
+	    //prepare graph values
+		var m = animFix.map;
+		var moveCanvas = !!m.canvas;
+		var iterNodes = !!Object.keys(m).length;
+		delete m.canvas;
+		
 	    //animate
 	    animation.setOptions($.merge(opt, {
 	      $animating: false,
 	      compute: function(delta) {
-	        graph.eachNode(function(node) { 
-	          for(var p in m) {
-	            interp[p](node, m[p], delta, versor);
-	          }
-	        });
+	    	  
+	    	if(iterNodes){
+		        graph.eachNode(function(node) { 
+		          for(var p in m) {
+		            interp[p](node, m[p], delta, versor);
+		          }
+		        });
+	    	}
 	        viz.canvas.clear();
+	        if(moveCanvas){
+	    		interp.canvas(viz.canvas, delta);
+	    	}
+	        
 	        that.plot(opt, this.$animating, delta);
 	        this.$animating = true;
 	      },
+	      link: 'cancel',
 	      complete: function() {
 	    	viz.canvas.clear();
 	        that.plot(opt);
 	        opt.onComplete();
 	        opt.onAfterCompute();
+	        animFix.busy = false;
 	      }       
 	    })).start();
 	  },
@@ -17777,7 +17829,7 @@ $jit.GraphFlow.$extend = true;
 	
 	'grid': {
 			'render': function(grid, canvas){
-				if(!grid.data.$visible){
+				if(!grid.data.$alpha){
 					return;
 				}
 				var scale = 1/canvas.scaleOffsetX,
@@ -17863,6 +17915,7 @@ $jit.GraphFlow.$extend = true;
 		if(bend){
 			for(var b = 0, l = bend.length; b < l; b++){
 				toBend = bend[b];
+				//if (EdgeHelper.line.contains(from, toBend, pos, dim)){
 				if (GraphFlow.EdgeHelper.isOverEdge(from, toBend, pos, dim)){
 					return true;
 				}
@@ -17870,6 +17923,7 @@ $jit.GraphFlow.$extend = true;
 			}
 			
 		}
+		//return EdgeHelper.line.contains(from, to, pos, dim);
 		return GraphFlow.EdgeHelper.isOverEdge(from, to, pos, dim);
       },