Flex开源组件Birdeye中的关系型图表(Ravis),

因为比较适合我这种对flash构图能力有限,但能写写代码的菜鸟。

一、直接上效果图

grafana绘制网络拓扑 绘制网络拓扑结构_数据结构与算法

二、项目的目录结构:

 

grafana绘制网络拓扑 绘制网络拓扑结构_测试_02

 三.需要的测试datasource  data/graph.xml



1 <Graph>
 2   <Node id="1" name="Switch" desc="This is a Switch"  nodeSize="40" nodeClass="earth" nodeIcon="swtich" />
 3   <Node id="2" name="computerA"   nodeSize="40" nodeClass="tree" nodeIcon="computer" />
 4   <Node id="3" name="computerB"  nodeSize="40" nodeClass="tree" nodeIcon="computer"" />
 5   <Node id="4" name="computerC"  nodeSize="40" nodeClass="tree" nodeIcon="computer" />
 6   <Node id="5" name="computerD"  nodeSize="40" nodeClass="tree" nodeIcon="computer" />
 7   <Node id="6" name="computerE"  nodeSize="40" nodeClass="tree" nodeIcon="computer" />
 8   <Node id="7" name="computerF"   nodeSize="40" nodeClass="tree" nodeIcon="computer" />
 9   <Edge fromID="1" toID="2" edgeLabel="No Change" flow="50" color="0x556b2f" edgeClass="sun" edgeIcon="NoChange" />
10   <Edge fromID="1" toID="3" edgeLabel="Bad" flow="400" color="0xcd5c5c" edgeClass="sun" edgeIcon="Bad" />
11   <Edge fromID="1" toID="4" edgeLabel="Good" flow="80" color="0xb22222" edgeClass="sun" edgeIcon="Good" />
12   <Edge fromID="1" toID="5" edgeLabel="Good" flow="100" color="0x607b8b" edgeClass="sun" edgeIcon="Good" />
13   <Edge fromID="1" toID="6" edgeLabel="No Change" flow="120" color="0x333333" edgeClass="sun" edgeIcon="NoChange" />
14   <Edge fromID="1" toID="7" edgeLabel="Bad" flow="150" color="0x6b8e23" edgeClass="sun" edgeIcon="Bad" />
15   
16 </Graph>



datasource的简单说明:(首次看略过)  nodeClass:节点样式    nodeIcon:节点的图标,这个节点要显示图标必须在指明VisualGraph的呈示器为:IconNodeRenderer

eg:itemRenderer="org.un.cava.birdeye.ravis.components.renderers.nodes.IconNodeRenderer"

这个还不够,我们需要让人renderer知道我们所要加载的图片在哪里?通过查看源码发现,在IconNodeRenderer.as这个类里是这样对图片渲染的:
img = RendererIconFactory.createIcon(this.data.data.@nodeIcon,32);

再往上跟踪: icon = EmbeddedIcons.generateImage(suffix,size);

打开EmdeddedIcons.as这个类,恍然大悟,原来在datasource中的 nodeIcon="10",这个10是图片的别名,工作原理是这样的:



[Bindable]
 [Embed(source="nodes/10.png")]
  static public var n10Icon:Class;

    public static function generateImage(type:String, size:int = 32):Image {
             
             var img:Image = new Image();
             img.width = size;
             img.height = size;
             
            switch(type) {
                case "10":
                    img.source = EmbeddedIcons.n10Icon;
                    break;

                .....

                 }

       return img;

    }



为了熟悉源码,我修改了这个源码,把自己找的两张图片放到:org.un.cava.birdeye.ravis/assets/icons文件夹下,并加上对自己的图片的注入,这样就可以显示我们自定义的图片了,修改后的源码为:



/**
         * 扩展
         * **/
        [Bindable]
        [Embed(source="nodes/my_switch.png")]
        static public var swtichIcon:Class;
        
        [Bindable]
        [Embed(source="nodes/my_computer.png")]
        static public var computerIcon:Class;
.........................
switch(type) {
                case "swtich":
                    img.source=EmbeddedIcons.swtichIcon;
                    break;
                case "computer":
                    img.source=EmbeddedIcons.computerIcon;
                    break;
                    
                case "ravis":
                    img.source = EmbeddedIcons.ravisIcon;    
                    break;
.................



四.  主程序: network.mxml    为了简单为这里没有使用MVC



<?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:layouterControls="org.un.cava.birdeye.ravis.components.ui.controls.layouterControls.*" 
               xmlns:vgraphControls="org.un.cava.birdeye.ravis.components.ui.controls.vgraphControls.*" 
               xmlns:ravis="org.un.cava.birdeye.ravis.graphLayout.visual.*"
                creationComplete="init()"
               >
    <fx:Script>
        <![CDATA[    
            import org.un.cava.birdeye.ravis.graphLayout.data.Graph;
            import org.un.cava.birdeye.ravis.graphLayout.data.IGraph;
            import org.un.cava.birdeye.ravis.graphLayout.layout.HierarchicalLayouter;
            import org.un.cava.birdeye.ravis.graphLayout.layout.ILayoutAlgorithm;
            import org.un.cava.birdeye.ravis.graphLayout.visual.IEdgeRenderer;
            import org.un.cava.birdeye.ravis.graphLayout.visual.IVisualNode;
            import org.un.cava.birdeye.ravis.graphLayout.visual.edgeRenderers.BaseEdgeRenderer;    
            private var graph:IGraph;//图表Graph对象
            private var layouter:ILayoutAlgorithm;//布局对象,对所有的vgraph
            private var selectedEdgeRenderer:IEdgeRenderer;//连线方式
            private var startRoot:IVisualNode;
           
          private  static var xmlData:XML;
            private function init():void
            {
                /*一、加载xml文件
                 */

                
                var url:URLRequest=new URLRequest("data/graph.xml");
                //创建URLLoader对象。
                var loader:URLLoader=new URLLoader();
                /**
                 * 为新创建的对象注册事件监听, 
                 *  我们需要监听的是Event.COMPLETE事件,如果xml load完成调用 onComplete函数。
                 *  
                **/
                loader.addEventListener(Event.COMPLETE,onComplete)
                /***
                 * 
                 * 3.调用load()函数,只有调用load函数加载完成后才会发生onComplete函数
                 * 
                 * **/    
                loader.load(url); 
            }
            
            /***
             * 
             * 事件处理函数onComplete
             * 
             * 
             * */
            public function onComplete(event:Event):void{
              /**
              * 下来的问题就是怎么得到取到的xml数据了。
              * 首先把onComplete函数的参数event的target属性转换成URLLoader对象
              * 注意flex中的强制类型转化有别于java
              * **/
             var result:URLLoader=URLLoader(event.target);
             /**
             * 然后再把这个对象的data属性转换成xml对象
             * **/
              xmlData=XML(result.data);
            
/*** * 二、绘制Graph * 1.创建IGraph对象,用来组织数据结构 * */
              this.graph=new Graph("graphId",false,xmlData);
              /***
               * 2.把Graph这个数据结构给VisualGraph这个显示器
               * */
              
              vgraph.graph=graph;
             
            
              /***
               * 3.创建布局对象,这里创建的布局类型为tree,并设置自动适应屏幕来展开
               * */
              this.layouter=new HierarchicalLayouter(vgraph);    
              layouter.autoFitEnabled=true;// automatically fit the layout to the screen
              
              /**
               * 4.把这个布局对象set给二维矢量绘图工具
               * **/
              this.vgraph.layouter=this.layouter;
              
              //
              //this.vgraph.edgeRendererFactory=new ClassFactory(BaseEdgeRenderer);
              /**
               * 
               * **/
              
              vgraph.maxVisibleDistance =2;    
              /** *从load过来的数据中通过ID来查找节点id为 1的节点,并赋值为startRoot
               * **/
              startRoot = this.graph.nodeByStringId("1").vnode;
              
              vgraph.displayEdgeLabels =false;
/** *指定root节点
               * **
              vgraph.currentRootVNode = startRoot; //
               vgraph.draw();
            }
            
        ]]>
    </fx:Script>
    <fx:Declarations>
        <!-- 将非可视元素(例如服务、值对象)放在此处 -->
    
    </fx:Declarations>
    
    <s:Panel width="100%" height="100%" horizontalCenter="center" borderColor="#CCCCCC">
        <!--Group标签管理其他可视组件-->
        <s:Group id="graphGroup" width="100%" height="100%" >
       <ravis:VisualGraph id="vgraph" width="100%" height="100%"
                                left="0"  right="0" top="0" bottom="5"
                                 backgroundColor="#FFFFFF" alpha="1"
                                 itemRenderer="org.un.cava.birdeye.ravis.components.renderers.nodes.IconNodeRenderer" 
                         edgeLabelRenderer="org.un.cava.birdeye.ravis.components.renderers.edgeLabels.BaseEdgeLabelRenderer"
                                 visibilityLimitActive="true" />       
                
        </s:Group>
    </s:Panel>
</s:Application>



由于时间原因,网络拓扑图今晚就研究到这里。对于线的样式、动态的从数据库里读取数据来显示节点,对节点的监听。以后慢慢扩展。