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

📄 dependencygraph.as

📁 用于flash/flex的 as3的 2D图形图像图表的动态生成
💻 AS
字号:
package flare.apps
{
	import com.adobe.serialization.json.JSON;
	
	import flare.display.DirtySprite;
	import flare.display.TextSprite;
	import flare.query.methods.div;
	import flare.query.methods.eq;
	import flare.query.methods.neq;
	import flare.vis.Visualization;
	import flare.vis.controls.ClickControl;
	import flare.vis.controls.HoverControl;
	import flare.vis.data.Data;
	import flare.vis.data.DataSprite;
	import flare.vis.data.EdgeSprite;
	import flare.vis.data.NodeSprite;
	import flare.vis.data.Tree;
	import flare.vis.events.SelectionEvent;
	import flare.vis.legend.Legend;
	import flare.vis.operator.encoder.PropertyEncoder;
	import flare.vis.operator.label.RadialLabeler;
	import flare.vis.operator.layout.BundledEdgeRouter;
	import flare.vis.operator.layout.CircleLayout;
	import flare.widgets.ProgressBar;
	
	import flash.filters.DropShadowFilter;
	import flash.geom.Rectangle;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.text.TextFormat;
	import flash.utils.Dictionary;
	
	[SWF(backgroundColor="#ffffff", frameRate="30")]
	public class DependencyGraph extends App
	{
		/** We will be rotating text, so we embed the font. */
		[Embed(source="verdana.TTF", fontName="Verdana")]
		private static var _font:Class;
		
		private var _url:String = 
			"http://flare.prefuse.org/data/flare.json.txt";
			
		private var _vis:Visualization;
		private var _detail:TextSprite;
		private var _legend:Legend;
		private var _bar:ProgressBar;
		private var _bounds:Rectangle;
		
		private var _fmt:TextFormat = new TextFormat("Verdana", 7);
		private var _focus:NodeSprite;
		
		protected override function init():void
		{
			// create progress bar
			addChild(_bar = new ProgressBar());
			_bar.bar.filters = [new DropShadowFilter(1)];
			
			// load data file
			var ldr:URLLoader = new URLLoader(new URLRequest(_url));
			_bar.loadURL(ldr, function():void {
				var obj:Array = JSON.decode(ldr.data as String) as Array;
				var data:Data = buildData(obj);
	            visualize(data);
	            _bar = null;
			});
  		}
  		
  		private function visualize(data:Data):void
		{
			// place shorter names at the end of the data list
			// that way they will the easiest to mouse over later
			data.nodes.sortBy("-data.name.length");
			
			// prepare data with default settings
			data.nodes.setProperties({
				shape: null,                  // no shape, use labels instead
				visible: eq("childDegree",0), // only show leaf nodes
				buttonMode: true              // show hand cursor
			});
			data.edges.setProperties({
				lineWidth: 2,
				lineColor: 0xff0055cc,
				mouseEnabled: false,          // non-interactive edges
				visible: neq("source.parentNode","target.parentNode")
			});
						
			// define the visualization
			_vis = new Visualization(data);
			// place around circle by tree structure, radius mapped to depth
			// make a large inner radius so labels are closer to circumference
			_vis.operators.add(new CircleLayout("depth", null, true));
			CircleLayout(_vis.operators.last).startRadiusFraction = 3/5;
			// bundle edges to route along the tree structure
			_vis.operators.add(new BundledEdgeRouter(0.95));
			// set the edge alpha values
			// longer edge, lighter alpha: 1/(2*numCtrlPoints)
			_vis.operators.add(new PropertyEncoder(
				{alpha: div(1,"points.length")}, Data.EDGES));
			
			// add labels	
			_vis.operators.add(new RadialLabeler(
				// custom label function removes package names
				function(d:DataSprite):String {
					var txt:String = d.data.name;
					return txt.substring(txt.lastIndexOf('.')+1);
				}, true, _fmt, eq("childDegree",0))); // leaf nodes only
			_vis.operators.last.textMode = TextSprite.EMBED; // embed fonts!
			
			// update and add
			_vis.update();
			addChild(_vis);
			
			// add the legend and detail pane
			addDetail();
			
			// show all dependencies on single-click
			var linkType:int = NodeSprite.OUT_LINKS;
			_vis.controls.add(new ClickControl(NodeSprite, 1,
				function(evt:SelectionEvent):void {
					if (_focus && _focus != evt.node) {
						unhighlight(_focus);
						linkType = NodeSprite.OUT_LINKS;
					}
					_focus = evt.node;
					highlight(evt);
					showAllDeps(evt, linkType);
					_vis.controls.remove(hov);
					linkType = (linkType==NodeSprite.OUT_LINKS ?
						NodeSprite.IN_LINKS : NodeSprite.OUT_LINKS);
				},
				// show all edges and nodes as normal
				function(evt:SelectionEvent):void {
					if (_focus) unhighlight(_focus);
					_focus = null;
					_vis.data.edges["visible"] = 
						neq("source.parentNode","target.parentNode");
					_vis.data.nodes["alpha"] = 1;
					_vis.controls.add(hov);
					linkType = NodeSprite.OUT_LINKS;
				}
			));
			
			// add mouse-over details
			_vis.controls.add(new HoverControl(NodeSprite,
				HoverControl.DONT_MOVE,
				function(evt:SelectionEvent):void {
					_detail.text = evt.node.data.name;
				},
				function(evt:SelectionEvent):void {
					_detail.text = _vis.data.nodes.length + " files";
				}
			));
			
			// add mouse-over highlight
			var hov:HoverControl = new HoverControl(NodeSprite,
				HoverControl.DONT_MOVE, highlight, unhighlight);
			_vis.controls.add(hov);
			
			// compute the layout
			if (_bounds) resize(_bounds);
		}
		
		/** Add highlight to a node and connected edges/nodes */
		private function highlight(evt:SelectionEvent):void
		{
			// highlight mouse-over node
			evt.node.props.label.color = 0x0000cc;
			evt.node.props.label.bold = true;
			// highlight links for classes that depend on the focus in green
			evt.node.visitEdges(function(e:EdgeSprite):void {
				e.alpha = 0.5;
				e.lineColor = 0xff00ff00;
				e.source.props.label.color = 0x00cc00;
				_vis.marks.setChildIndex(e, _vis.marks.numChildren-1);
			}, NodeSprite.IN_LINKS);
			// highlight links the focus depends on in red
			evt.node.visitEdges(function(e:EdgeSprite):void {
				e.alpha = 0.5;
				e.lineColor = 0xffff0000;
				e.target.props.label.color = 0xff0000;
				_vis.marks.setChildIndex(e, _vis.marks.numChildren-1);
			}, NodeSprite.OUT_LINKS);
		}
		
		/** Remove highlight from a node and connected edges/nodes */
		private function unhighlight(n:*):void
		{
			var node:NodeSprite = n is NodeSprite ?
				NodeSprite(n) : SelectionEvent(n).node;
			// set everything back to normal
			node.props.label.color = 0;
			node.props.label.bold = false;
			node.setEdgeProperties({
				alpha: div(1, "points.length"),
				lineColor: 0xff0055cc,
				"source.props.label.color": 0,
				"target.props.label.color": 0
			}, NodeSprite.GRAPH_LINKS);
		}
		
		/** Traverse all dependencies for a given class */
		private function showAllDeps(evt:SelectionEvent, linkType:int):void
		{
			// first, do a breadth-first-search to compute closure
			var q:Array = evt.items.slice();
			var map:Dictionary = new Dictionary();
			while (q.length > 0) {
				var u:NodeSprite = q.shift();
				map[u] = true;
				u.visitNodes(function(v:NodeSprite):void {
					if (!map[v]) q.push(v);
				}, linkType);
			}
			// now highlight nodes and edges in the closure
			_vis.data.edges.visit(function(e:EdgeSprite):void {
				e.visible = map[e.source] && map[e.target];
			});
			_vis.data.nodes.visit(function(n:NodeSprite):void {
				n.alpha = map[n] ? 1 : 0.4;
			});
		}
		
		/** Show all reverse dependencies */
		
		
		private function addDetail():void
		{	
			var fmt:TextFormat = new TextFormat("Verdana",14);
			
			_legend = Legend.fromValues(null, [
				{color: 0xffff0000, size: 0.75, label: "Imports"},
				{color: 0xff00ff00, size: 0.75, label: "Is Imported By"}
			]);
			_legend.labelTextFormat = fmt;
			_legend.labelTextMode = TextSprite.EMBED;
			_legend.update();
			addChild(_legend);

			_detail = new TextSprite("", fmt, TextSprite.EMBED);
			_detail.textField.multiline = true;
			_detail.htmlText = _vis.data.nodes.length + " files";
			addChild(_detail);
		}
		
		public override function resize(bounds:Rectangle):void
		{
			_bounds = bounds;
			if (_bar) {
				_bar.x = _bounds.width/2 - _bar.width/2;
				_bar.y = _bounds.height/2 - _bar.height/2;
			}
			if (_vis) {
				// automatically size labels based on bounds
				var d:Number = Math.min(_bounds.width, _bounds.height);
				_vis.data.nodes.setProperty("props.label.size",
					(d <= 650 ? 7 : d <= 725 ? 8 : 9),
					null, eq("childDegree",0));
				
				// compute the visualization bounds
				_vis.bounds.x = _bounds.x;
				_vis.bounds.y = _bounds.y + (0.06 * _bounds.height);
				_vis.bounds.width = _bounds.width;
				_vis.bounds.height = _bounds.height - (0.05 * _bounds.height);
				// update
				_vis.update();
				
				// layout legend and details
				_legend.x = _bounds.width  - _legend.width;
				_legend.y = _bounds.height - _legend.border.height - 5;
				_detail.y = _bounds.height - _detail.height - 5;
				
				// forcibly render to eliminate partial update bug, as
				// the standard RENDER event routing can get delayed.
				// remove this line for faster but unsynchronized resizes
				DirtySprite.renderDirty();
			}
		}
		
		// --------------------------------------------------------------------
		
		/**
		 * Creates the visualized data.
		 */
		public static function buildData(tuples:Array):Data
		{
			var data:Data = new Data();
			var tree:Tree = new Tree();
			var map:Object = {};
			
			tree.root = data.addNode({name:"flare", size:0});
			map.flare = tree.root;
			
			var t:Object, u:NodeSprite, v:NodeSprite;
			var path:Array, p:String, pp:String, i:uint;
			
			// build data set and tree edges
			tuples.sortOn("name");
			for each (t in tuples) {
				path = String(t.name).split(".");
				for (i=0, p=""; i<path.length-1; ++i) {
					pp = p;
					p += (i?".":"") + path[i];
					if (!map[p]) {
						u = data.addNode({name:p, size:0});
						tree.addChild(map[pp], u);
						map[p] = u;
					}
				}
				t["package"] = p;
				u = data.addNode(t);
				tree.addChild(map[p], u);
				map[t.name] = u;
			}
			
			// create graph links
			for each (t in tuples) {
				u = map[t.name];
				for each (var name:String in t.imports) {
					v = map[name];
					if (v) data.addEdgeFor(u, v);
					else trace ("Missing node: "+name);
				}
			}
			
			// sort the list of children alphabetically by name
			for each (u in tree.nodes) {
				u.sortEdgesBy(NodeSprite.CHILD_LINKS, "target.data.name");
			}
			
			data.tree = tree;
			return data;
		}
		
	} // end of class DependencyGraph
}

⌨️ 快捷键说明

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