废话先不多说,先上图;这是一个模拟设备状态的拓扑图;图中节点右上角的圆形图标绿色代表正常,红色代表设备一次;在图片的左上角 是用来获取节点的详细信息的。具体方法在js中有注释,
因为这只是个教程,所以在写代码上不是很规范。所以希望大家多多见谅。而且因为本人对这个插件的研究也有限,有什么不对的也希望多多交流 谢谢!
GoJS插件。 网址http://gojs.net/latest/index.html; 其中官网的包可以在这里下载:http://gojs.net/latest/doc/download.html;官网提供的包是英文的包括注释也是,而且不是很详细。所有我在本例子中 将关键的代码全部做了注释。基本上有点基础应该都能弄明白;为了直观,我直接将代码注释写在了代码所在的位置;这个插件在官网提供了很多例子。也有APS文档。但是本人觉得他的API文档写的有点杂。很难看懂,跟别说那些英语基础不好的人了。但是没关系,后面我会介绍一下如何巧妙不看文档也能做出不同效果的拓扑图;或者说实现你想要的拓扑图;
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
3 <html>
4 <head>
5 <title>安防点位拓扑图</title>
6 <!-- /* Copyright ?1998-2013 by Northwoods Software Corporation. */ -->
7 <link href="goSamples.css" rel="stylesheet" type="text/css" />
8 <script type="text/javascript" src="go.js"></script>
9 <!-- <script type="text/javascript" src="goSamples.js"></script>-->
10 <script src="../resources/scripts/jquery-1.7.1.min.js" type="text/javascript"></script>
11 <script type="text/javascript">
12 var AjaxRequestBack=false;
13 var IdList;
14 function init() {
15 if (window.goSamples) goSamples();
16 var $ = go.GraphObject.make;
17
18 myDiagram = $(go.Diagram, "myDiagram",
19 {
20 initialContentAlignment: go.Spot.Center //整个拓扑图的位置
21 });
22 //节点的图片,根据传进来的参数获取相对应的图片
23 function nodeTypeImage(type) {
24 if (type.charAt(0) === "1") return "images/1.png";
25 if (type.charAt(0) === "2") return "images/2.png";
26 if (type.charAt(0) === "3") return "images/3.png";
27 if (type.charAt(0) === "4") return "images/4.png";
28 if (type.charAt(0) === "5") return "images/5.png";
29 if (type.charAt(0) === "6") return "images/6.png";
30 if (type.charAt(0) === "7") return "images/7.png";
31 if (type.charAt(0) === "8") return "images/8.png";
32 return "images/0.png";
33 }
34
35 function nodeProblemConverter(msg) {
36 if (msg) return "red";
37 return null;
38 }
39 //判断节点左边形状
40 function nodeOperationConverter(s) {
41 if (s >= 2) return "TriangleDown";
42 if (s >= 1) return "Rectangle";
43 return "Circle";
44 }
45 //判断节点右边形状的颜色
46 function nodeStatusConverter(s) {
47 if (s >= 2) return "red";
48 if (s >= 1) return "green";
49 return "green";
50 }
51 //可以通过 problem控制节点的连线和边框的颜色
52 //data.status = 10.1;//控制节点内部图标的颜色
53 //data.operation //控制节点内图标的形状
54 myDiagram.nodeTemplate =
55 $(go.Node, "Vertical",
56 { selectable: false,//是否可以选择节点并移动
57 mouseOver: function (e, obj) {//鼠标进入响应的事件方法
58 nodeDoubleClick(e, obj) //事件调用方法
59 }
60 },
61 // { doubleClick: nodeDoubleClick },//鼠标双击事件函数
62 //{click: nodeDoubleClick }, //鼠标单击事件函数
63 {locationObjectName: "ICON" },
64 // new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), //这里使用节点的位置参数,也可以不知用,不使用的时候,就的使用插件的布局属性
65 $(go.Panel, "Spot",
66 $(go.Panel, "Auto",
67 { name: "ICON" }, //这个参数无所谓
68 $(go.Shape,
69 { fill: null, portId: "",
70 strokeWidth: 0,stroke: null },//这两个属性和起来去掉边框
71 new go.Binding("background", "problem", nodeProblemConverter)), //这里使用节点的问题描述 problem值为空时:控制线条和边框的颜色,即设备是否出现问题
72 $(go.Picture,
73 //{ stroke: ""},
74 { margin: 0 }, //这里控制图片和外围边框的边距
75 { desiredSize: new go.Size(60, 60) },
76 new go.Binding("source", "type", nodeTypeImage))), //这里是用节点的类型,即是用的图片
77 //这段代码是控制节点内部左边图标初始颜色 形状等,位子信息
78 // $(go.Shape, "Circle",
79 // { alignment: go.Spot.TopLeft, alignmentFocus: go.Spot.TopLeft, //TopLeft显示的位置
80 // width: 10, height: 10, fill: "Green"//这里的颜色是控制节点内部左边图标的颜色
81 // },
82
83 // new go.Binding("figure", "operation", nodeOperationConverter)) //这里是用节点形状参数
84
85 //这段代码是控制节点内部右边图标初始颜色 形状等,位子信息
86 $(go.Shape, "Circle",
87 { alignment: go.Spot.TopRight, alignmentFocus: go.Spot.TopRight, //TopLeft显示的位置
88 width: 15, height: 15, fill: "Green"
89 },
90 new go.Binding("fill", "status", nodeStatusConverter)) //这里是用节点状态参数
91 ),
92 //这里是节点文字的样式
93 $(go.TextBlock,
94 { font: "bold 7px Helvetica, bold Arial, sans-serif",
95 stroke: "black", margin: 3 },
96 new go.Binding("text")));
97
98 //设置线条的颜色
99 function linkProblemConverter(msg) {
100 if (msg) return "red";
101 return "#ccc";
102 }
103
104
105
106 myDiagram.linkTemplate =
107 $(go.Link, go.Link.AvoidsNodes,
108 { corner: 3 }, //控制线的转弯的弧度值越小 越呈现直角
109 $(go.Shape,
110 { strokeWidth: 1 }, //控制线条的粗细,值越大 线越粗
111 new go.Binding("stroke", "problem", linkProblemConverter)));
112
113 //节点的布局
114 myDiagram.layout = $(go.LayeredDigraphLayout,
115 { direction: 270, //拓扑图的方向
116 layerSpacing: 10,
117 columnSpacing: 15,
118 setsPortSpots: false
119 });
120
121
122 //在这里加载数据
123 load();
124 //利用随机数随机设备出现问题的方法
125 function randomProblems() {
126 if(AjaxRequestBack)
127 {
128
129
130 var model = myDiagram.model;
131 //nodeDataArray
132 //设置问题节的颜色
133 var arr = model.nodeDataArray;
134 for (var i = 0; i < arr.length; i++) {
135 data = arr[i];
136
137 //console.log(data.key);
138 for(var t=0;t<IdList.length;t++)
139 {
140 if(data.key==IdList[t])
141 {
142 data.status = 3;
143 }
144 else{
145 //data.status = 1;
146 }
147 }
148
149 //data.problem = (Math.random() < 0.8) ? "" : "Power loss due to ...";//0.8是一个零界点
150 //data.problem = ""; //当为空的时候就是没问题
151 //data.problem = "Power loss due to ...";//当这个的时候就是有问题
152 //data.status = 10.1;//这个数据是用于判断节点右边正方形 圆形 三角形还有形状的颜色(右边形状不变)
153 //data.operation = 0.1; //设置节点左边正方形 圆形 三角形还有形状的颜色(左边的形状颜色不变)
154
155 //data.operation = 0.3;
156 model.updateTargetBindings(data);
157 data.status = 1;
158 }
159
160
161 //获取JSON数据中的linkDataArray
162 //设置节点之间线的颜色
163 /*
164 arr = model.linkDataArray;
165 for (i = 0; i < arr.length; i++) {
166 data = arr[i];
167 data.problem = (0.1 < 0.7) ? "" : "No Power";
168 model.updateTargetBindings(data);
169 }
170 */
171 AjaxRequestBack=false;
172 }
173 }
174 //设置间隔时间获取设备的状态
175 function loop1()
176 {
177 setTimeout(function () { GetStatus(); loop1(); }, 4000);
178 }
179 loop1();
180 function loop() {
181 setTimeout(function () { randomProblems(); loop(); }, 5500);
182 }
183 loop(); // start the simulation
184 myDiagram.makeImage({
185 scale: 1,
186 background: "AntiqueWhite",
187 type: "image/jpeg",
188 details: 0.05
189 });
190 }
191 function load() {
192 var str = <%=Result%>;
193 myDiagram.model = go.Model.fromJson(str);
194
195 var arr = myDiagram.model.nodeDataArray;
196 for (var i = 0; i < arr.length; i++) {
197 // alert(arr[i].text);
198 }
199
200
201 }
202
203 function GetStatus() {
204 $.ajax({
205 url: 'GetEleStatus.ashx',
206 type:'post',
207 success: function (data) {
208 var result = eval("(" + data + ")");
209 IdList = result.IdList;
210
211 AjaxRequestBack=true;
212 }
213 });
214
215 }
216
217 function highlightNode(e, node) {
218 alert(node.data.text);
219 }
220
221 function nodeDoubleClick(e, node) {
222 $("#Loading").html("正在加载...");
223 $.ajax({
224 url: 'GetElementInfo.ashx',
225 data: { "ElementID": node.data.key },
226 success: function (data) {
227 if (data != "false") {
228 data = eval("(" + data + ")");
229 var name = data.name;
230 var commont = data.commont;
231
232 $("#Info").html("<span>点位名称:"+name+"</span></br><span>点位描述:"+commont+"</span>")
233
234 $("#Info").show();;
235 tag=true;
236
237 }
238 }
239 });
240 }
241
242 </script>
243 </head>
244 <body onload="init()">
245 <div id='Info' style="position: fixed; padding-top: 5px; margin: 1px; line-height: 20px;
246 border-radius: 3px; background-color: #FFC435; width: 150px; height: 50px; z-index: 999;
247 border: 1px solid #ccc; top: 7px; left: 7px;">
248 <div id="Loading" style="text-align: center; width: 150px; margin-top: 15px;">
249 选择点位</div>
250 </div>
251
252 <div id="myDiagram" style="border: solid 0px black; width: 100%; height: 900px;">
253 </div>
254
255 <br />
256 <%--</div>--%>
257 </body>
258 </html>
View Code
接下来是后台代码;后台代码的注释也写在代码所在的行了。
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.UI;
6 using System.Web.UI.WebControls;
7 using System.Text;
8 using System.Data;
9
10 namespace Maticsoft.Web.test
11 {
12 public partial class DrowNode : System.Web.UI.Page
13 {
14
15 public string Result;
16 protected void Page_Load(object sender, EventArgs e)
17 {
18 DataSet set = new DataSet();
19 set = new Maticsoft.BLL.RD_Element().Query("");//这里是写的SQL语句 去获取你数据库的数据。这里我删除掉了。而是利用下面构造的数据。这里你获取的数据必须包含两个字段,一个是父节点编号,一个是子节点编号。
20 if (set != null && set.Tables.Count > 0)
21 {
22
23 StringBuilder result = new StringBuilder();
24 StringBuilder node = new StringBuilder();//这个对象是存放着节点信息
25 StringBuilder link = new StringBuilder();//这个节点是存放每个节点的关联关系
26
27 //这两个是节点的位置。但是我用了另一种布局方式,这里已经没用了。
28 int y = 0;
29 int x = 0;
30 Random r = new Random();
31 int count = set.Tables[0].Rows.Count;
32 // 下面是构造的数据。该插件是利用后台生成的Json格式数据来解析的;
33 //key 是节点编号 text是节点下面的文字。type是节点的类型。在html代码有一个方法nodeTypeImage就是根据这个来返回图片路径的。problem则是用来标识节点数否异常。这里有一个可能会混淆,那就是节点异常和节点之间的连接异常。具体在js代码有注释,当然这里还有其他的属性,就不一一介绍了。
34 node.Append("{\"key\":\"0\", \"text\":\"北京\", \"type\":\"0\", \"problem\":\"\"},");
35 node.Append("{\"key\":\"-1\", \"text\":\"中国\", \"type\":\"0\", \"problem\":\"\"},");
36 node.Append("{\"key\":\"-2\", \"text\":\"福建\", \"type\":\"0\", \"problem\":\"\"},");
37 node.Append("{\"key\":\"10000\", \"text\":\"风扇\", \"type\":\"2\", \"problem\":\"\"},");
38 node.Append("{\"key\":\"10001\", \"text\":\"风扇风扇\", \"type\":\"2\", \"problem\":\"\"},");
39 node.Append("{\"key\":\"10002\", \"text\":\"风扇\", \"type\":\"4\", \"problem\":\"\"},");
40 node.Append("{\"key\":\"10003\", \"text\":\"风扇\", \"type\":\"5\", \"problem\":\"\"},");
41 node.Append("{\"key\":\"10004\", \"text\":\"发电机\", \"type\":\"1\", \"problem\":\"\"},");
42 node.Append("{\"key\":\"10005\", \"text\":\"水龙头\", \"type\":\"5\", \"problem\":\"\"},");
43 node.Append("{\"key\":\"10006\", \"text\":\"发电站\", \"type\":\"7\", \"problem\":\"\"},");
44 node.Append("{\"key\":\"10007\", \"text\":\"火箭\", \"type\":\"8\", \"problem\":\"\"},");
45 node.Append("{\"key\":\"10008\", \"text\":\"卫星\", \"type\":\"3\", \"problem\":\"\"},");
46 node.Append("{\"key\":\"10009\", \"text\":\"卫星\", \"type\":\"5\", \"problem\":\"\"},");
47 node.Append("{\"key\":\"100010\", \"text\":\"卫星\", \"type\":\"6\", \"problem\":\"\"},");
48 node.Append("{\"key\":\"100011\", \"text\":\"火箭\", \"type\":\"3\", \"problem\":\"\"},");
49 node.Append("{\"key\":\"100012\", \"text\":\"发电机\", \"type\":\"3\", \"problem\":\"\"},");
50 node.Append("{\"key\":\"100013\", \"text\":\"发电机\", \"type\":\"5\", \"problem\":\"\"},");
51 node.Append("{\"key\":\"100014\", \"text\":\"风扇\", \"type\":\"6\", \"problem\":\"\"},");
52 node.Append("{\"key\":\"100015\", \"text\":\"拖拉机\", \"type\":\"3\", \"problem\":\"\"},");
53 node.Append("{\"key\":\"100016\", \"text\":\"公交车\", \"type\":\"5\", \"problem\":\"\"},");
54 node.Append("{\"key\":\"100017\", \"text\":\"广场控灯\", \"type\":\"6\", \"problem\":\"\"},");
55 node.Append("{\"key\":\"100018\", \"text\":\"演出屏幕\", \"type\":\"3\", \"problem\":\"\"},");
56 node.Append("{\"key\":\"100019\", \"text\":\"话筒\", \"type\":\"3\", \"problem\":\"\"},");
57 node.Append("{\"key\":\"100020\", \"text\":\"音箱\", \"type\":\"5\", \"problem\":\"\"},");
58 node.Append("{\"key\":\"100021\", \"text\":\"核武器\", \"type\":\"6\", \"problem\":\"\"},");
59 //这里的数据是关联各个节点的。from是线出来的节点编号,to则是连线到达的节点编号。这样就能把两节点关联起来
60 link.Append("{\"from\":\"0\", \"to\":\"-1\",\"problem\":\"\"},");
61 link.Append("{\"from\":\"-2\", \"to\":\"-1\",\"problem\":\"\"},");
62 link.Append("{\"from\":\"10000\", \"to\":\"0\",\"problem\":\"\"},");
63 link.Append("{\"from\":\"10001\", \"to\":\"0\",\"problem\":\"\"},");
64 link.Append("{\"from\":\"10002\", \"to\":\"0\",\"problem\":\"\"},");
65 link.Append("{\"from\":\"10003\", \"to\":\"10002\",\"problem\":\"\"},");
66 link.Append("{\"from\":\"10004\", \"to\":\"10002\",\"problem\":\"\"},");
67 link.Append("{\"from\":\"10005\", \"to\":\"-2\",\"problem\":\"\"},");
68 link.Append("{\"from\":\"10006\", \"to\":\"-2\",\"problem\":\"\"},");
69 link.Append("{\"from\":\"10007\", \"to\":\"-2\",\"problem\":\"\"},");
70 link.Append("{\"from\":\"10008\", \"to\":\"100017\",\"problem\":\"\"},");
71 link.Append("{\"from\":\"10009\", \"to\":\"-2\",\"problem\":\"\"},");
72 link.Append("{\"from\":\"100010\", \"to\":\"-2\",\"problem\":\"\"},");
73 link.Append("{\"from\":\"100011\", \"to\":\"100019\",\"problem\":\"\"},");
74 link.Append("{\"from\":\"100012\", \"to\":\"10005\",\"problem\":\"\"},");
75 link.Append("{\"from\":\"100013\", \"to\":\"10005\",\"problem\":\"\"},");
76 link.Append("{\"from\":\"100014\", \"to\":\"10005\",\"problem\":\"\"},");
77 link.Append("{\"from\":\"100015\", \"to\":\"10007\",\"problem\":\"\"},");
78 link.Append("{\"from\":\"100016\", \"to\":\"10007\",\"problem\":\"\"},");
79 link.Append("{\"from\":\"100017\", \"to\":\"10009\",\"problem\":\"\"},");
80 link.Append("{\"from\":\"100018\", \"to\":\"10007\",\"problem\":\"\"},");
81 link.Append("{\"from\":\"100019\", \"to\":\"10009\",\"problem\":\"\"},");
82 link.Append("{\"from\":\"100020\", \"to\":\"100011\",\"problem\":\"\"},");
83 link.Append("{\"from\":\"100021\", \"to\":\"100011\",\"problem\":\"\"},");
84
85 //这段代码是我本来用来构造数据库中数据的JSON格式的,但是因为没用了。不过来是贴出来,如果你有用可以照着这个写
86 //foreach (DataRow row in set.Tables[0].Rows)
87 //{
88 // x = r.Next(count*20)+40;
89 // y = r.Next(count*20)+100;
90 // node.Append("{\"key\":\"" + row["id"] + "\", \"text\":\"" + row["name"] + "\", \"type\":\"" + row["type"] + "\", \"loc\":\"" + x + " "+y+"\",\"problem\":\"\"},");
91
92 // //elemodel = new BLL.RD_Element().GetModel(int.Parse(row["parentid"].ToString ()));
93 // link.Append("{\"from\":\"" + row["id"] + "\", \"to\":\"" + row["parentid"].ToString() + "\",\"problem\":\"\"},");
94 //}
95 string nodestr = node.ToString().Substring(0, node.ToString().Length - 1);
96 string linkstr = link.ToString().Substring(0, link.ToString().Length - 1);
97
98
99 result.Append("{\"nodeDataArray\": [ ");
100 result.Append(nodestr);
101 result.Append("],\"linkDataArray\": [ ");
102 result.Append(linkstr);
103 result.Append("]}");
104 Result = result.ToString();
105 }
106 }
107
108 }
109 }
View Code
然后是异步获取设备状态的C#代码。这里因为没有真正的设备信息。所以获取的异常设备都是利用随机函数构造出来的 代码如下 其中返回的是json格式的数据,数据为异常设备的编号
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5
6 namespace Maticsoft.Web.test
7 {
8 /// <summary>
9 /// GetEleStatus 的摘要说明
10 /// </summary>
11 public class GetEleStatus : IHttpHandler
12 {
13
14 public void ProcessRequest(HttpContext context)
15 {
16 context.Response.ContentType = "text/plain";
17
18 string result="{\"IdList\":[";
19
20 Random r = new Random();
21 for (int i = 0; i < 10; i++)
22 {
23 result += r.Next(100000,100022)+",";
24 }
25 result = result.Substring(0, result.Length - 1);
26 result += "]}";
27 context.Response.Write(result);
28 }
29
30 public bool IsReusable
31 {
32 get
33 {
34 return false;
35 }
36 }
37 }
38 }
View Code
最后是获取设备的详细信息,这个是在鼠标移动到设备节点上的时候异步请求获取的。这里就不详细说了,大家可以根据自己的需求来做,也不难。
然后做一下总结。插件首先是解析你构造的Json数据,然后放在myDiagram.model对象里。在数据中有两个数据:nodeDataArray和linkDataArray分别存放节点信息和节点关联信息;然后js去遍历迭代这是两个数组中的数据来构造拓扑图。那么在迭代的过程中。我们可以利用自己的需求去添加代码实现我们想要的拓扑图!
这里的话我分享下我是这么做的吧。首先 如果你的英语水平很好并且文档阅读能力较强,那么可以不用往下看了。因为直接去看文档理解得也深一些,也能明白一些实现原理。
首先 你的明白你的需求是什么。即你要实现什么样的拓扑图。然后 你去官网他的例子里面找。找到和你想要的差不多的拓扑图,或者某个拓扑图有你要的某个样式或者布局方式,或者交互方式等等。然后看他的代码。那么这里你有的先了解整个插件的实现过程。你可以通过详细分析我的代码和注释,应该就能大概明白某写代码是什么功能。某个功能是那个方法实现的,因为整个插件的实现原理都是一样的。所以一些方法和属性也是一样的,只不过根据属性的值,能得到不同的拓扑图;比如布局属性myDiagram.layout 比如节点连接属性:myDiagram.linkTemplate 那么这里就那布局属性说事,可能你想要的布局不是我这个例子中的样子,那么你就可以到其他拓扑图找到你想要的布局方式,然后把他的代码拿过来。替换掉现有的布局代码,当然这里布局有两种方式,一种是插件自动给你布局,就像我这个例子,还有一种是你自己构造每个节点的位置。 其他的也都大同小异。其实这就是一个组装拼接的过程。有时候一些外国插件没有什么文档的时候,我都是这干的,而且效果不错,速度也快。当然可能这样做对整个插件的理解就没有那么透彻了;
(这里插播一条广告:http://xiamiwage.taobao.com/这是本人的淘宝店。唉 苦逼的挨踢男。希望大家多多支持吧)
最后 因为这个插件是带有水印的。如果要去水印。就得到他的官网注册购买。当然我这也有一个破解版的,不过如果你真的要用,还是希望支持正版。
下载地址如下:http://pan.baidu.com/share/link?shareid=203307637&uk=370619680
最后 因为是第一次写博客,有什么需要改进的地方请多多批评 多多建议。谢谢,也希望多多交流。哈哈