⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tree.as

📁 用于flash/flex的 as3的 2D图形图像图表的动态生成
💻 AS
字号:
package flare.vis.data
{
	import flare.vis.events.DataEvent;
		
	/**
	 * Data structure for managing a collection of visual data objects in a
	 * tree (hierarchy) structure. This class extends the functionality of
	 * the Data class to model a hierarchy. The class can be used as an
	 * alternative to the Data class when the data forms a strict tree, or to
	 * model a spanning tree over a general graph.
	 */
	public class Tree extends Data
	{	
		/**
		 * Sets the root node of this tree. This property can only be set
		 * when the tree does not yet have a root node. */
		public override function set root(n:NodeSprite):void {
			if (_root == null) {
				super.addNode(n); _root = n; _root.parentIndex = -1;
				addDescendants(_root);
			} else {
				throw new ArgumentError("Can't set root unless the tree is empty." +
				"If you want to set an entirely new root, call clear() first.");
			}
		}
		
		/** This property simply points back to this object. */
		public override function get tree():Tree { return this; }
		public override function set tree(t:Tree):void { /* do nothing */ }
		
		// -- Methods ---------------------------------------------------------
		
		/**
		 * Creates and returns a new root NodeSprite for the tree. If the
		 * tree already has a root, this method throws an error.
		 * @return the newly added root
		 */
		public function addRoot():NodeSprite
		{
			if (_root != null) throw new Error(
				"addRoot can only be called on an empty tree!");
			return (_root = super.addNode());
		}
		
		/**
		 * Add a node to the tree. If the child node argument is null,
		 * a new NodeSprite will be created. A new EdgeSprite connecting
		 * the nodes will be created. Returns the new child node.
		 * @param p the parent node
		 * @param c the child node. If null, a new child node is created.
		 * @return the new child node
		 */
		public function addChild(p:NodeSprite, c:NodeSprite=null):NodeSprite
		{			
			if (!_nodes.contains(p)) {
				throw new ArgumentError("Parent node must be in the tree!");
			}
			c = super.addNode(c);
			var e:EdgeSprite = newEdge(p, c, directedEdges, null);
			c.parentIndex = p.addChildEdge(e);
			c.parentEdge = e;
			super.addEdge(e);
			return c;
		}
		
		/**
		 * Adds the given edge as a child edge between a node already
		 * in the tree and another node not yet in the tree.
		 * @param e the edge to add to the tree
		 * @return the newly added edge
		 */
		public function addChildEdge(e:EdgeSprite):EdgeSprite
		{
			var n1:NodeSprite = e.source, b1:Boolean = _nodes.contains(n1);
			var n2:NodeSprite = e.target, b2:Boolean = _nodes.contains(n2);
			
			if (b1 && b2) {
				throw new ArgumentError("One node must not be in the tree");
			}
			if (!(b1 || b2))
				throw new ArgumentError("One node must already be in the tree");
				
			var p:NodeSprite = b1 ? n1 : n2;
			var c:NodeSprite = b1 ? n2 : n1;
			
			c.parentEdge = e;
			c.parentIndex = p.addChildEdge(e);
			
			super.addNode(c);
			return super.addEdge(e);
		}
		
		/**
		 * Registers all tree descendants with this Tree instance. 
		 * @param n a sub-tree root that has already been added to this Tree
		 */
		protected function addDescendants(n:NodeSprite):void
		{
			for (var i:int=0; i<n.childDegree; ++i) {
				var e:EdgeSprite = n.getChildEdge(i);
				var c:NodeSprite = e.other(n);
				c.parentEdge = e;
				c.parentIndex = i;
				super.addNode(c);
				super.addEdge(e);
				addDescendants(c);
			}
		}
		
		/**
		 * Clears the tree, removing all nodes and edges.
		 */
		public override function clear():void
		{
			super.clear(); _root = null;
		}
		
		/**
		 * Removes a node from the tree, removing the entire
		 * subtree rooted at that node.
		 * @param n the node to remove
		 * @return true if the node was successfully removed, false otherwise
		 */
		public override function removeNode(n:NodeSprite):Boolean
		{
			if (n==_root) {
				clear(); return true;
			} else {
				return removeEdge(n.parentEdge);
			}
		}
		
		/**
		 * Removes an edge from tree tree, removing the entire
		 * subtree rooted at the child node adjacent to the edge.
		 * @param e the edge to remove from the tree
		 * @return true if the edge was successfully removed, false otherwise
		 */
		public override function removeEdge(e:EdgeSprite):Boolean
		{
			if (e==null || !_edges.contains(e)) return false;
			
			// disconnect tree
			var c:NodeSprite = (e.target.parentNode==e.source ? e.target : e.source);
			var p:NodeSprite = c.parentNode;
			var i:int = c.parentIndex;
			p.removeChildEdge(e);
			
			// walk disconnected segment to fire updates
			c.visitTreeDepthFirst(function(n:NodeSprite):void {
				_edges.remove(n.parentEdge);
				_nodes.remove(n);
			});
			_edges.remove(e);
			
			// update parent index values
			for (; i<p.childDegree; ++i) {
				p.getChildNode(i).parentIndex = i;
			}
			return true;	
		}
		
		/** @private */
		protected override function onRemoveNode(evt:DataEvent):void
		{
			fireEvent(evt);
		}
		
		/** @private */
		protected override function onRemoveEdge(evt:DataEvent):void
		{
			fireEvent(evt);
		}

		// --------------------------------------------------------------------
		
		/**
		 * Counts the number of leaf nodes in the tree.
		 * @return the number of leaf nodes
		 */
		public function countLeaves():int
		{
			var leaves:int = 0;
			for each (var ns:NodeSprite in _nodes.list) {
				if (ns.childDegree == 0) ++leaves;
			}
			return leaves;
		}

		// --------------------------------------------------------------------

		/**
		 * Continuously swaps the given node with its parent node
		 * until it is the root.
		 * <p>
		 * <strong>WARNING:</strong> this method causes connecting edges to be
		 * reconfigured. If this tree is a spanning tree, this can cause havoc.
		 * </p>
		 * @param n the node to swap with its parent until it becomes the root
		 */
		public function swapToRoot(n:NodeSprite):void
		{
			while (n.parent != null) {
				swapWithParent(n);
			}
		}

		/**
		 * Swaps the given node with its parent node.
		 * <p>
		 * <strong>WARNING:</strong> this method causes connecting edges to be
		 * reconfigured. If this tree is a spanning tree, this can cause havoc.
		 * </p>
		 * @param n the node to swap with its parent
		 */
		public function swapWithParent(n:NodeSprite):void
		{
			var p:NodeSprite = n.parentNode, gp:NodeSprite;
			var e:EdgeSprite, ge:EdgeSprite, idx:int;
			if (p==null) return;
			
			gp = p.parentNode;
			ge = p.parentEdge;
			idx = p.parentIndex;
			
			// swap parent edge
			e = n.parentEdge;
			p.removeChild(n);
			p.parentEdge = e;
			p.parentIndex = n.addChildEdge(e);
			
			// connect to grandparents
			if (gp==null) {
				n.parentIndex = -1;
				n.parentEdge = null;
			} else {
				if (ge.source == gp) {
					ge.target = n;
				} else {
					ge.source = n;
				}
				n.parentIndex = idx;
				n.parentEdge = ge;
			}
		}

	} // end of class Tree
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -