├── .gitignore ├── README.md ├── css ├── consolepanel.css └── consolepanel.png ├── demo ├── ctopo示例API版.html ├── ctopo示例全配置版.html ├── ctopo示例简写版.html ├── data_big.json ├── data_small.json ├── data_small_api.json └── 控制台示例.html ├── image ├── ctopobg.png ├── demo.png └── skin.jpg └── src ├── consolepanel.js └── ctopo.js /.gitignore: -------------------------------------------------------------------------------- 1 | # 这个文件是git的标识忽略文件的配置文件, 标识的文件将不会提交到git 2 | 3 | **/node_modules 4 | .idea/ 5 | dist/ 6 | npm-debug.log* 7 | .DS_Store* 8 | .project 9 | .vs 10 | net-poc-web.iml 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ctopo 2 | ===== 3 | 4 | canvas版的拓扑图(topo)展示工具. 5 | 6 | 起因 7 | ----- 8 | 总在使用别人的开源插件来绘制拓扑,总是不能满足公司各个项目的各种需求,痛定思痛自己搞一套吧.
9 | 10 | ps: 感谢[UI设计师yoki](http://www.zcool.com.cn/u/968707)对topo图做的UI设计,很赞!!! 11 | 12 | ps: 因为ff,chrome不支持本地请求json文件, 将整体工程放到本服务器下运行最为适宜. 13 | 14 | 适用场景和环境 15 | ----- 16 | (1)适用于监控网络ip节点互联关系的场景
17 | (2)适用于社交网络的群组互联访问关系 18 | 19 | 兼容性 20 | ----- 21 | ie9+,firefox,chrome,safari. 22 | 23 | 性能说明 24 | ----- 25 | 300+节点毫无压力,顺畅的没有朋友,正常使用尽量控制在300左右. 26 | 27 | 节点的碰撞检测5千节点1ms左右,连线的碰撞检测5千连线1ms左右,(ff,chrome一样) 28 | 29 | 如果需要展示上千节点请参考以下调优方案 30 | 31 | 调优方案参考 32 | 33 | (1)将力导向布局的迭代次数从300次下降到150次,布局时间缩小一倍,例:10s---优化后5s 34 | (2)将布局算法放在后台执行,将前台布局设置为[预设],按java举例,例:10s---优化后2s 35 | (3)将节点的显示标签Label隐藏,下面列举了绘制label的性能影响,例:10s---优化后3s 36 | (4)用空间换时间,将坐标保留,不用每次draw都要重新计算布局 37 | 38 | 39 | ps: 绘制节点标签还是挺吃性能的 40 | 41 | 绘制节点不带label 42 | //ff (浏览器卡死, 建议使用服务器端计算) 43 | //chrome nodes count=1000,edges count=1000,layout time=4838,draw time=9 44 | 45 | //ff nodes count=500,edges count=500,layout time=9543,draw time=19 46 | //chrome nodes count=500,edges count=500,layout time=1272,draw time=6 47 | 48 | //ff nodes count=300,edges count=300,layout time=3445,draw time=11 49 | //chrome nodes count=300,edges count=300,layout time=475,draw time=4 50 | 51 | //ff nodes count=200,edges count=200,layout time=1551,draw time=7 52 | //chrome nodes count=200,edges count=200,layout time=233,draw time=4 53 | 54 | 绘制节点带label 55 | //ff (浏览器卡死, 建议使用服务器端计算) 56 | //chrome nodes count=1000,edges count=1000,layout time=4838,draw time=39 57 | 58 | //ff nodes count=500,edges count=500,layout time=9543,draw time=125 59 | //chrome nodes count=500,edges count=500,layout time=1272,draw time=23 60 | 61 | //ff nodes count=300,edges count=300,layout time=3445,draw time=77 62 | //chrome nodes count=300,edges count=300,layout time=475,draw time=16 63 | 64 | //ff nodes count=200,edges count=200,layout time=1551,draw time=49 65 | //chrome nodes count=200,edges count=200,layout time=233,draw time=10 66 | 缺点 67 | ----- 68 | (1)力导向布局算法性能差一点,还需要进一步优化
69 | (2)不支持节点图片和图标
70 | (3)不支持框选操作 71 | 72 | 特性 73 | ----- 74 | (1)提供控制面板;
75 | (2)支持鼠标滑轮和拖拽的放大,缩小;
76 | (3)上下左右键盘平移;
77 | (4)拖拽单个节点和屏幕;
78 | (5)支持点击和悬停节点;
79 | (6)支持点击和悬停连线;
80 | (7)支持悬停节点的关联节点高亮;
81 | (8)提供事件回调接口;
82 | (9)支持连线箭头;
83 | (10)支持连线的流动动画;
84 | (11)支持力导向布局定位,即每次刷新页面,坐标不变; 85 | 86 | 实现原理 87 | ----- 88 | (1)使用html5的canvas标签来实现的;
89 | (2)布局算法使用力导向布局(库仑斥力公式和胡克定律公式)[来自网络](http://zhenghaoju700.blog.163.com/blog/static/13585951820114153548541/?suggestedreading&wumii);
90 | (3)节点的碰撞检测使用勾股定理测距;
91 | (4)连线的碰撞检测使用反正切计算夹角;
92 | 93 | 界面展示 94 | ----- 95 | ![github](https://github.com/tm-roamer/ctopo/blob/master/image/demo.png?raw=true "示例图片") 96 | ![github](https://github.com/tm-roamer/ctopo/blob/master/image/skin.jpg?raw=true "UI皮肤") 97 | 98 | 版权 99 | ----- 100 | MIT(随意使用,免费开源) 101 | 102 | 基础实例 103 | ----- 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 129 | 130 | 131 | 132 | 133 | api接口 134 | ----- 135 | ### 使用方法 136 | //取得ctopo对象, 点出api方法即可 137 | var ctopo = ctopo({..各种基础配置..}); 138 | var nodeA = ctopo.node("1108"); //获取节点A 139 | var nodeB = ctopo.node("0724"); //获取节点B 140 | var edge = ctopo.edge("1108","0724"); //获取连线 141 | 142 | ### 属性和方法 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 |
属性名描述
version版本
option配置对象
canvas画布对象
context画布上下文对象
nodes节点数组
edges连线对象
156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 169 | 170 | 171 | 172 | 173 | 174 | 178 | 179 | 180 | 181 | 182 | 183 | 186 | 187 | 188 | 189 | 190 | 191 | 195 | 196 | 197 | 198 | 199 | 203 | 207 | 211 | 212 | 213 | 214 | 215 | 218 | 219 | 220 | 221 | 222 | 223 | 226 | 233 | 234 | 235 | 236 | 237 | 240 | 244 | 245 | 246 | 247 | 248 | 251 | 255 | 256 | 257 | 258 | 259 | 262 | 263 | 264 | 265 | 266 | 267 | 270 | 271 | 272 | 273 | 274 | 275 | 278 | 279 | 280 | 281 | 282 | 283 | 286 | 287 | 288 | 289 | 290 | 291 | 294 | 295 | 296 | 297 | 298 | 299 | 302 | 303 | 304 | 305 | 306 | 307 | 310 | 311 | 312 | 313 | 314 | 315 | 318 | 319 | 320 | 321 | 322 | 323 | 328 | 329 | 330 | 331 | 332 | 333 | 337 | 338 | 339 | 340 | 341 | 342 | 346 | 347 | 348 | 349 | 350 | 351 | 355 | 356 | 357 | 358 | 359 | 360 | 363 | 367 | 368 | 369 | 370 | 371 | 374 | 378 | 379 | 380 |
方法名描述参数返回值
addEdge(edge,isDrawNow)添加连线 166 | 参数1:
edge添加的连线对象
167 | 参数2:
isDrawNow是否立刻渲染到屏幕 168 |
addNode(node,isDrawNow)添加节点 175 | 参数1:
edge添加的节点对象
176 | 参数2:
isDrawNow是否立刻渲染到屏幕 177 |
draw(option)重新绘制画布,
用法等于ctopo(option)
184 | 参数1:
option初始的配置对象 185 |
drawData(data,isApplyLayout)局部刷新,只刷新数据 192 | 参数1:
data格式=optioin.data
193 | 参数2:
isApplyLayout是否重新应用布局 194 |
成功true,失败false
edge(sid,tid) 200 | 取得连线对象
201 | ps:区分方向 202 |
204 | 参数1:
开始节点id
205 | 参数2:
结束节点id 206 |
208 | 查到: 连线对象
209 | 没查到: null 210 |
edgeArray()取得所有的连线对象数组 216 | 无 217 | 连线对象数组
firstNeighbors(nid)返回与之关联的连线和节点数组对象 224 | 参数1:
nid待匹配的节点id 225 |
查到:关联数据对象;
227 | 没查到:空数组对象
228 | {
229 | edgeNeighbors:[],
230 | nodeNeighbors:[]
231 | }
232 |
layout(layout)重置切换布局 238 | (可选)参数1:
layout==option.layout 239 |
241 | 无参数:
返回option.layout
242 | 有参数:
重置布局,
成功true,失败false 243 |
node(id)取得节点对象 249 | 参数1:
节点id 250 |
252 | 查到:节点对象
253 | 没查到:null 254 |
nodeLabelsVisible(visible)设置节点标签是否显示 260 | 参数1:
visible是否显示标签,
布尔型true,false 261 |
edgeLabelsVisible(visible)设置连线标签是否显示 268 | 参数1:
visible是否显示标签,
布尔型true,false 269 |
edgeArrowsVisible(visible)设置连线箭头是否显示 276 | 参数1:
visible是否显示箭头,
布尔型true,false 277 |
nodeArray()取得所有节点对象数组 284 | 无 285 | 节点对象数组
nodeTooltipsVisible(visible)设置节点提示框是否显示 292 | 参数1:
visible是否显示提示框,
布尔型true,false 293 |
edgeTooltipsVisible(visible)设置连线提示框是否显示 300 | 参数1:
visible是否显示提示框,
布尔型true,false 301 |
edgeAnimateBallsVisible(visible)设置连线动画球是否显示 308 | 参数1:
visible是否显示动画球,
布尔型true,false 309 |
consolePanelVisible(visible)设置控制台是否显示 316 | 参数1:
visible是否显示控制台,
布尔型true,false 317 |
removeEdge(sid,tid,isDrawNow)删除连线 324 | 参数1:
开始节点id
325 | 参数2:
结束节点id
326 | 参数3:
是否立刻渲染到屏幕 327 |
removeNode(id,isDrawNow)删除节点,与之关联的线也删除 334 | 参数1:
节点id
335 | 参数2:
是否立刻渲染到屏幕 336 |
updateEdge(edge,isDrawNow)更新连线 343 | 参数1:
连线对象
344 | 参数3:
是否立刻渲染到屏幕 345 |
updateNode(node,isDrawNow)更新节点 352 | 参数1:
节点对象
353 | 参数2:
是否立刻渲染到屏幕 354 |
style(style)重置切换样式 361 | (可选)参数1:
style==option.style 362 |
364 | 无参数:
返回option.style 365 | 有参数:
重置样式,
成功true,失败false 366 |
zoom(scale)设置缩放比例(0-1) 372 | (可选)参数1:
scale比例0-1,100%=0.5
373 |
375 | 无参数:
返回比例值
376 | 有参数:
设置比例值,
成功ture,失败false 377 |
381 | 382 | -------------------------------------------------------------------------------- /css/consolepanel.css: -------------------------------------------------------------------------------- 1 | /** 2 | * console_panel为控制台的顶层div 3 | * 以下所有的样式均下层级选择器下,不会污染其他样式文件 4 | */ 5 | .console_panel{ 6 | position:absolute; 7 | top:5px; 8 | left:5px; 9 | } 10 | /* 方向盘 控制上下左右的样式 */ 11 | .console_panel .steerwheel_panel { 12 | position:absolute; 13 | width: 86px; 14 | height: 86px; 15 | overflow: hidden; 16 | background: url(consolepanel.png) no-repeat; 17 | cursor:pointer; 18 | } 19 | .console_panel .steer_default{ 20 | background-position: 0px 0px; 21 | } 22 | /* 键盘触发 23 | 37==left 24 | 38==up 25 | 39==right 26 | 40==down 27 | */ 28 | .console_panel .steer_37{ 29 | background-position: 0px -344px; 30 | } 31 | .console_panel .steer_38{ 32 | background-position: 0px -86px; 33 | } 34 | .console_panel .steer_39{ 35 | background-position: 0px -172px; 36 | } 37 | .console_panel .steer_40{ 38 | background-position: 0px -258px; 39 | } 40 | /* 触发上下左右的div块 */ 41 | .console_panel .steer_btn{ 42 | position:absolute; 43 | height: 30px; 44 | width: 30px; 45 | } 46 | .console_panel .steer_btn_up{ 47 | top: 0; 48 | left: 28px; 49 | } 50 | .console_panel .steer_btn_down{ 51 | bottom: 0; 52 | left: 28px; 53 | } 54 | .console_panel .steer_btn_left{ 55 | top: 28px; 56 | left: 0px; 57 | } 58 | .console_panel .steer_btn_right{ 59 | top: 28px; 60 | right: 0px; 61 | } 62 | /* 放大缩小的面板 */ 63 | .console_panel .zoom_panel{ 64 | position:absolute; 65 | top:86px; 66 | left:30px; 67 | } 68 | /* 放大缩小按钮*/ 69 | .console_panel .zoom { 70 | cursor:pointer; 71 | width: 26px; 72 | height: 26px; 73 | overflow: hidden; 74 | background: url(consolepanel.png) no-repeat; 75 | } 76 | /* 放大 */ 77 | .console_panel .zoom_out{ 78 | position:absolute; 79 | top:0px; 80 | left:0px; 81 | background-position: 0px -430px; 82 | } 83 | .console_panel .zoom_out:hover{ 84 | background-position: 0px -456px; 85 | } 86 | /* 缩小 */ 87 | .console_panel .zoom_in{ 88 | position:absolute; 89 | top:166px; 90 | left:0px; 91 | background-position: 0px -482px; 92 | } 93 | .console_panel .zoom_in:hover{ 94 | background-position: 0px -508px; 95 | } 96 | /* 比例尺条 */ 97 | .console_panel .scale_bar{ 98 | position:absolute; 99 | top:26px; 100 | left:0px; 101 | height:140px; 102 | width:26px; 103 | } 104 | /* 比例尺的槽 */ 105 | .console_panel .scale_ruler { 106 | position:absolute; 107 | top:0px; 108 | left:4px; 109 | z-index: 10; 110 | width: 18px; 111 | height: 140px; 112 | overflow: hidden; 113 | background: url(consolepanel.png) no-repeat -26px -430px; 114 | } 115 | /* 比例尺的滑块 */ 116 | .console_panel .scale_slider { 117 | position:absolute; 118 | top:60px; 119 | left:0px; 120 | z-index: 12; 121 | width: 26px; 122 | height: 20px; 123 | overflow: hidden; 124 | background: url(consolepanel.png) no-repeat 0px -534px; 125 | cursor:pointer; 126 | } 127 | /* 比例尺的当前比例(已经选中的比例) */ 128 | .console_panel .scale_ruler_current { 129 | position:absolute; 130 | top:70px; 131 | left:4px; 132 | z-index: 11; 133 | width: 18px; 134 | /*height: 140px;*/ 135 | height:70px; 136 | overflow: hidden; 137 | background: url(consolepanel.png) no-repeat -44px -500px; 138 | } -------------------------------------------------------------------------------- /css/consolepanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tm-roamer/ctopo/5fe44fee1b23e12813227f5e21b86ba277cf33b5/css/consolepanel.png -------------------------------------------------------------------------------- /demo/ctopo示例API版.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starter Template for Bootstrap 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 339 | 340 | -------------------------------------------------------------------------------- /demo/ctopo示例全配置版.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Starter Template for Bootstrap 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 168 | 169 | 170 | 171 | -------------------------------------------------------------------------------- /demo/ctopo示例简写版.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ctopo示例简写版 6 | 7 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /demo/data_big.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "838644321", 5 | "x": 0, 6 | "y": 0, 7 | "label": "192.168.12.164", 8 | "color": "#00adee", 9 | "size": 20, 10 | "textColor": "#878787", 11 | "textSize": 10, 12 | "customField1": "自定义字段1", 13 | "customField2": [ 14 | "自定义字段2_1", 15 | "自定义字段2_2" 16 | ], 17 | "customField3": { 18 | "field3_1": "自定义字段3_1", 19 | "field3_2": "自定义字段3_2" 20 | } 21 | }, 22 | { 23 | "id": "-2051156877", 24 | "x": 0, 25 | "y": 0, 26 | "label": "192.168.12.38", 27 | "color": "#00adee", 28 | "size": 20, 29 | "textColor": "#878787", 30 | "textSize": 10, 31 | "customField1": "自定义字段1", 32 | "customField2": [ 33 | "自定义字段2_1", 34 | "自定义字段2_2" 35 | ], 36 | "customField3": { 37 | "field3_1": "自定义字段3_1", 38 | "field3_2": "自定义字段3_2" 39 | } 40 | }, 41 | { 42 | "id": "838644324", 43 | "x": 0, 44 | "y": 0, 45 | "label": "192.168.12.167", 46 | "color": "#00adee", 47 | "size": 20, 48 | "textColor": "#878787", 49 | "textSize": 10, 50 | "customField1": "自定义字段1", 51 | "customField2": [ 52 | "自定义字段2_1", 53 | "自定义字段2_2" 54 | ], 55 | "customField3": { 56 | "field3_1": "自定义字段3_1", 57 | "field3_2": "自定义字段3_2" 58 | } 59 | }, 60 | { 61 | "id": "-2051156755", 62 | "x": 0, 63 | "y": 0, 64 | "label": "192.168.12.76", 65 | "color": "#00adee", 66 | "size": 20, 67 | "textColor": "#878787", 68 | "textSize": 10, 69 | "customField1": "自定义字段1", 70 | "customField2": [ 71 | "自定义字段2_1", 72 | "自定义字段2_2" 73 | ], 74 | "customField3": { 75 | "field3_1": "自定义字段3_1", 76 | "field3_2": "自定义字段3_2" 77 | } 78 | }, 79 | { 80 | "id": "838644171", 81 | "x": 0, 82 | "y": 0, 83 | "label": "192.168.12.119", 84 | "color": "#00adee", 85 | "size": 20, 86 | "textColor": "#878787", 87 | "textSize": 10, 88 | "customField1": "自定义字段1", 89 | "customField2": [ 90 | "自定义字段2_1", 91 | "自定义字段2_2" 92 | ], 93 | "customField3": { 94 | "field3_1": "自定义字段3_1", 95 | "field3_2": "自定义字段3_2" 96 | } 97 | }, 98 | { 99 | "id": "838645127", 100 | "x": 0, 101 | "y": 0, 102 | "label": "192.168.12.214", 103 | "color": "#00adee", 104 | "size": 20, 105 | "textColor": "#878787", 106 | "textSize": 10, 107 | "customField1": "自定义字段1", 108 | "customField2": [ 109 | "自定义字段2_1", 110 | "自定义字段2_2" 111 | ], 112 | "customField3": { 113 | "field3_1": "自定义字段3_1", 114 | "field3_2": "自定义字段3_2" 115 | } 116 | }, 117 | { 118 | "id": "838645126", 119 | "x": 0, 120 | "y": 0, 121 | "label": "192.168.12.213", 122 | "color": "#00adee", 123 | "size": 20, 124 | "textColor": "#878787", 125 | "textSize": 10, 126 | "customField1": "自定义字段1", 127 | "customField2": [ 128 | "自定义字段2_1", 129 | "自定义字段2_2" 130 | ], 131 | "customField3": { 132 | "field3_1": "自定义字段3_1", 133 | "field3_2": "自定义字段3_2" 134 | } 135 | }, 136 | { 137 | "id": "1734948971", 138 | "x": 0, 139 | "y": 0, 140 | "label": "192.168.12.9", 141 | "color": "#00adee", 142 | "size": 20, 143 | "textColor": "#878787", 144 | "textSize": 10, 145 | "customField1": "自定义字段1", 146 | "customField2": [ 147 | "自定义字段2_1", 148 | "自定义字段2_2" 149 | ], 150 | "customField3": { 151 | "field3_1": "自定义字段3_1", 152 | "field3_2": "自定义字段3_2" 153 | } 154 | }, 155 | { 156 | "id": "-2051156759", 157 | "x": 0, 158 | "y": 0, 159 | "label": "192.168.12.72", 160 | "color": "#00adee", 161 | "size": 20, 162 | "textColor": "#878787", 163 | "textSize": 10, 164 | "customField1": "自定义字段1", 165 | "customField2": [ 166 | "自定义字段2_1", 167 | "自定义字段2_2" 168 | ], 169 | "customField3": { 170 | "field3_1": "自定义字段3_1", 171 | "field3_2": "自定义字段3_2" 172 | } 173 | }, 174 | { 175 | "id": "838644166", 176 | "x": 0, 177 | "y": 0, 178 | "label": "192.168.12.114", 179 | "color": "#00adee", 180 | "size": 20, 181 | "textColor": "#878787", 182 | "textSize": 10, 183 | "customField1": "自定义字段1", 184 | "customField2": [ 185 | "自定义字段2_1", 186 | "自定义字段2_2" 187 | ], 188 | "customField3": { 189 | "field3_1": "自定义字段3_1", 190 | "field3_2": "自定义字段3_2" 191 | } 192 | }, 193 | { 194 | "id": "-2051156883", 195 | "x": 0, 196 | "y": 0, 197 | "label": "192.168.12.32", 198 | "color": "#00adee", 199 | "size": 20, 200 | "textColor": "#878787", 201 | "textSize": 10, 202 | "customField1": "自定义字段1", 203 | "customField2": [ 204 | "自定义字段2_1", 205 | "自定义字段2_2" 206 | ], 207 | "customField3": { 208 | "field3_1": "自定义字段3_1", 209 | "field3_2": "自定义字段3_2" 210 | } 211 | }, 212 | { 213 | "id": "838645129", 214 | "x": 0, 215 | "y": 0, 216 | "label": "192.168.12.216", 217 | "color": "#00adee", 218 | "size": 20, 219 | "textColor": "#878787", 220 | "textSize": 10, 221 | "customField1": "自定义字段1", 222 | "customField2": [ 223 | "自定义字段2_1", 224 | "自定义字段2_2" 225 | ], 226 | "customField3": { 227 | "field3_1": "自定义字段3_1", 228 | "field3_2": "自定义字段3_2" 229 | } 230 | }, 231 | { 232 | "id": "838644165", 233 | "x": 0, 234 | "y": 0, 235 | "label": "192.168.12.113", 236 | "color": "#00adee", 237 | "size": 20, 238 | "textColor": "#878787", 239 | "textSize": 10, 240 | "customField1": "自定义字段1", 241 | "customField2": [ 242 | "自定义字段2_1", 243 | "自定义字段2_2" 244 | ], 245 | "customField3": { 246 | "field3_1": "自定义字段3_1", 247 | "field3_2": "自定义字段3_2" 248 | } 249 | }, 250 | { 251 | "id": "-2051156884", 252 | "x": 0, 253 | "y": 0, 254 | "label": "192.168.12.31", 255 | "color": "#00adee", 256 | "size": 20, 257 | "textColor": "#878787", 258 | "textSize": 10, 259 | "customField1": "自定义字段1", 260 | "customField2": [ 261 | "自定义字段2_1", 262 | "自定义字段2_2" 263 | ], 264 | "customField3": { 265 | "field3_1": "自定义字段3_1", 266 | "field3_2": "自定义字段3_2" 267 | } 268 | }, 269 | { 270 | "id": "838644164", 271 | "x": 0, 272 | "y": 0, 273 | "label": "192.168.12.112", 274 | "color": "#00adee", 275 | "size": 20, 276 | "textColor": "#878787", 277 | "textSize": 10, 278 | "customField1": "自定义字段1", 279 | "customField2": [ 280 | "自定义字段2_1", 281 | "自定义字段2_2" 282 | ], 283 | "customField3": { 284 | "field3_1": "自定义字段3_1", 285 | "field3_2": "自定义字段3_2" 286 | } 287 | }, 288 | { 289 | "id": "838645128", 290 | "x": 0, 291 | "y": 0, 292 | "label": "192.168.12.215", 293 | "color": "#00adee", 294 | "size": 20, 295 | "textColor": "#878787", 296 | "textSize": 10, 297 | "customField1": "自定义字段1", 298 | "customField2": [ 299 | "自定义字段2_1", 300 | "自定义字段2_2" 301 | ], 302 | "customField3": { 303 | "field3_1": "自定义字段3_1", 304 | "field3_2": "自定义字段3_2" 305 | } 306 | }, 307 | { 308 | "id": "838644163", 309 | "x": 0, 310 | "y": 0, 311 | "label": "192.168.12.111", 312 | "color": "#00adee", 313 | "size": 20, 314 | "textColor": "#878787", 315 | "textSize": 10, 316 | "customField1": "自定义字段1", 317 | "customField2": [ 318 | "自定义字段2_1", 319 | "自定义字段2_2" 320 | ], 321 | "customField3": { 322 | "field3_1": "自定义字段3_1", 323 | "field3_2": "自定义字段3_2" 324 | } 325 | }, 326 | { 327 | "id": "838644350", 328 | "x": 0, 329 | "y": 0, 330 | "label": "192.168.12.172", 331 | "color": "#00adee", 332 | "size": 20, 333 | "textColor": "#878787", 334 | "textSize": 10, 335 | "customField1": "自定义字段1", 336 | "customField2": [ 337 | "自定义字段2_1", 338 | "自定义字段2_2" 339 | ], 340 | "customField3": { 341 | "field3_1": "自定义字段3_1", 342 | "field3_2": "自定义字段3_2" 343 | } 344 | }, 345 | { 346 | "id": "-2007034805", 347 | "x": 0, 348 | "y": 0, 349 | "label": "10.54.14.6", 350 | "color": "#00adee", 351 | "size": 20, 352 | "textColor": "#878787", 353 | "textSize": 10, 354 | "customField1": "自定义字段1", 355 | "customField2": [ 356 | "自定义字段2_1", 357 | "自定义字段2_2" 358 | ], 359 | "customField3": { 360 | "field3_1": "自定义字段3_1", 361 | "field3_2": "自定义字段3_2" 362 | } 363 | }, 364 | { 365 | "id": "-809256359", 366 | "x": 0, 367 | "y": 0, 368 | "label": "224.0.0.252", 369 | "color": "#00adee", 370 | "size": 20, 371 | "textColor": "#878787", 372 | "textSize": 10, 373 | "customField1": "自定义字段1", 374 | "customField2": [ 375 | "自定义字段2_1", 376 | "自定义字段2_2" 377 | ], 378 | "customField3": { 379 | "field3_1": "自定义字段3_1", 380 | "field3_2": "自定义字段3_2" 381 | } 382 | }, 383 | { 384 | "id": "-809256360", 385 | "x": 0, 386 | "y": 0, 387 | "label": "224.0.0.251", 388 | "color": "#00adee", 389 | "size": 30, 390 | "textColor": "#878787", 391 | "textSize": 10, 392 | "customField1": "自定义字段1", 393 | "customField2": [ 394 | "自定义字段2_1", 395 | "自定义字段2_2" 396 | ], 397 | "customField3": { 398 | "field3_1": "自定义字段3_1", 399 | "field3_2": "自定义字段3_2" 400 | } 401 | }, 402 | { 403 | "id": "-2051156912", 404 | "x": 0, 405 | "y": 0, 406 | "label": "192.168.12.24", 407 | "color": "#00adee", 408 | "size": 20, 409 | "textColor": "#878787", 410 | "textSize": 10, 411 | "customField1": "自定义字段1", 412 | "customField2": [ 413 | "自定义字段2_1", 414 | "自定义字段2_2" 415 | ], 416 | "customField3": { 417 | "field3_1": "自定义字段3_1", 418 | "field3_2": "自定义字段3_2" 419 | } 420 | }, 421 | { 422 | "id": "-2051156911", 423 | "x": 0, 424 | "y": 0, 425 | "label": "192.168.12.25", 426 | "color": "#00adee", 427 | "size": 20, 428 | "textColor": "#878787", 429 | "textSize": 10, 430 | "customField1": "自定义字段1", 431 | "customField2": [ 432 | "自定义字段2_1", 433 | "自定义字段2_2" 434 | ], 435 | "customField3": { 436 | "field3_1": "自定义字段3_1", 437 | "field3_2": "自定义字段3_2" 438 | } 439 | }, 440 | { 441 | "id": "838645252", 442 | "x": 0, 443 | "y": 0, 444 | "label": "192.168.12.255", 445 | "color": "#00adee", 446 | "size": 20, 447 | "textColor": "#878787", 448 | "textSize": 10, 449 | "customField1": "自定义字段1", 450 | "customField2": [ 451 | "自定义字段2_1", 452 | "自定义字段2_2" 453 | ], 454 | "customField3": { 455 | "field3_1": "自定义字段3_1", 456 | "field3_2": "自定义字段3_2" 457 | } 458 | }, 459 | { 460 | "id": "838645248", 461 | "x": 0, 462 | "y": 0, 463 | "label": "192.168.12.251", 464 | "color": "#00adee", 465 | "size": 20, 466 | "textColor": "#878787", 467 | "textSize": 10, 468 | "customField1": "自定义字段1", 469 | "customField2": [ 470 | "自定义字段2_1", 471 | "自定义字段2_2" 472 | ], 473 | "customField3": { 474 | "field3_1": "自定义字段3_1", 475 | "field3_2": "自定义字段3_2" 476 | } 477 | }, 478 | { 479 | "id": "-1072993729", 480 | "x": 0, 481 | "y": 0, 482 | "label": "239.255.255.250", 483 | "color": "#00adee", 484 | "size": 20, 485 | "textColor": "#878787", 486 | "textSize": 10, 487 | "customField1": "自定义字段1", 488 | "customField2": [ 489 | "自定义字段2_1", 490 | "自定义字段2_2" 491 | ], 492 | "customField3": { 493 | "field3_1": "自定义字段3_1", 494 | "field3_2": "自定义字段3_2" 495 | } 496 | }, 497 | { 498 | "id": "838645159", 499 | "x": 0, 500 | "y": 0, 501 | "label": "192.168.12.225", 502 | "color": "#00adee", 503 | "size": 20, 504 | "textColor": "#878787", 505 | "textSize": 10, 506 | "customField1": "自定义字段1", 507 | "customField2": [ 508 | "自定义字段2_1", 509 | "自定义字段2_2" 510 | ], 511 | "customField3": { 512 | "field3_1": "自定义字段3_1", 513 | "field3_2": "自定义字段3_2" 514 | } 515 | }, 516 | { 517 | "id": "-2051156789", 518 | "x": 0, 519 | "y": 0, 520 | "label": "192.168.12.63", 521 | "color": "#00adee", 522 | "size": 20, 523 | "textColor": "#878787", 524 | "textSize": 10, 525 | "customField1": "自定义字段1", 526 | "customField2": [ 527 | "自定义字段2_1", 528 | "自定义字段2_2" 529 | ], 530 | "customField3": { 531 | "field3_1": "自定义字段3_1", 532 | "field3_2": "自定义字段3_2" 533 | } 534 | }, 535 | { 536 | "id": "838645160", 537 | "x": 0, 538 | "y": 0, 539 | "label": "192.168.12.226", 540 | "color": "#00adee", 541 | "size": 20, 542 | "textColor": "#878787", 543 | "textSize": 10, 544 | "customField1": "自定义字段1", 545 | "customField2": [ 546 | "自定义字段2_1", 547 | "自定义字段2_2" 548 | ], 549 | "customField3": { 550 | "field3_1": "自定义字段3_1", 551 | "field3_2": "自定义字段3_2" 552 | } 553 | }, 554 | { 555 | "id": "1013191670", 556 | "x": 0, 557 | "y": 0, 558 | "label": "0.0.0.0", 559 | "color": "#00adee", 560 | "size": 40, 561 | "textColor": "#878787", 562 | "textSize": 10, 563 | "customField1": "自定义字段1", 564 | "customField2": [ 565 | "自定义字段2_1", 566 | "自定义字段2_2" 567 | ], 568 | "customField3": { 569 | "field3_1": "自定义字段3_1", 570 | "field3_2": "自定义字段3_2" 571 | } 572 | }, 573 | { 574 | "id": "838644198", 575 | "x": 0, 576 | "y": 0, 577 | "label": "192.168.12.125", 578 | "color": "#00adee", 579 | "size": 20, 580 | "textColor": "#878787", 581 | "textSize": 10, 582 | "customField1": "自定义字段1", 583 | "customField2": [ 584 | "自定义字段2_1", 585 | "自定义字段2_2" 586 | ], 587 | "customField3": { 588 | "field3_1": "自定义字段3_1", 589 | "field3_2": "自定义字段3_2" 590 | } 591 | }, 592 | { 593 | "id": "838644195", 594 | "x": 0, 595 | "y": 0, 596 | "label": "192.168.12.122", 597 | "color": "#00adee", 598 | "size": 20, 599 | "textColor": "#878787", 600 | "textSize": 10, 601 | "customField1": "自定义字段1", 602 | "customField2": [ 603 | "自定义字段2_1", 604 | "自定义字段2_2" 605 | ], 606 | "customField3": { 607 | "field3_1": "自定义字段3_1", 608 | "field3_2": "自定义字段3_2" 609 | } 610 | }, 611 | { 612 | "id": "838644318", 613 | "x": 0, 614 | "y": 0, 615 | "label": "192.168.12.161", 616 | "color": "#00adee", 617 | "size": 20, 618 | "textColor": "#878787", 619 | "textSize": 10, 620 | "customField1": "自定义字段1", 621 | "customField2": [ 622 | "自定义字段2_1", 623 | "自定义字段2_2" 624 | ], 625 | "customField3": { 626 | "field3_1": "自定义字段3_1", 627 | "field3_2": "自定义字段3_2" 628 | } 629 | }, 630 | { 631 | "id": "-2051156699", 632 | "x": 0, 633 | "y": 0, 634 | "label": "192.168.12.90", 635 | "color": "#00adee", 636 | "size": 20, 637 | "textColor": "#878787", 638 | "textSize": 10, 639 | "customField1": "自定义字段1", 640 | "customField2": [ 641 | "自定义字段2_1", 642 | "自定义字段2_2" 643 | ], 644 | "customField3": { 645 | "field3_1": "自定义字段3_1", 646 | "field3_2": "自定义字段3_2" 647 | } 648 | }, 649 | { 650 | "id": "838644258", 651 | "x": 0, 652 | "y": 0, 653 | "label": "192.168.12.143", 654 | "color": "#00adee", 655 | "size": 20, 656 | "textColor": "#878787", 657 | "textSize": 10, 658 | "customField1": "自定义字段1", 659 | "customField2": [ 660 | "自定义字段2_1", 661 | "自定义字段2_2" 662 | ], 663 | "customField3": { 664 | "field3_1": "自定义字段3_1", 665 | "field3_2": "自定义字段3_2" 666 | } 667 | }, 668 | { 669 | "id": "1807683160", 670 | "x": 0, 671 | "y": 0, 672 | "label": "111.206.79.144", 673 | "color": "#00adee", 674 | "size": 20, 675 | "textColor": "#878787", 676 | "textSize": 10, 677 | "customField1": "自定义字段1", 678 | "customField2": [ 679 | "自定义字段2_1", 680 | "自定义字段2_2" 681 | ], 682 | "customField3": { 683 | "field3_1": "自定义字段3_1", 684 | "field3_2": "自定义字段3_2" 685 | } 686 | }, 687 | { 688 | "id": "-2051156939", 689 | "x": 0, 690 | "y": 0, 691 | "label": "192.168.12.18", 692 | "color": "#00adee", 693 | "size": 20, 694 | "textColor": "#878787", 695 | "textSize": 10, 696 | "customField1": "自定义字段1", 697 | "customField2": [ 698 | "自定义字段2_1", 699 | "自定义字段2_2" 700 | ], 701 | "customField3": { 702 | "field3_1": "自定义字段3_1", 703 | "field3_2": "自定义字段3_2" 704 | } 705 | }, 706 | { 707 | "id": "-2051156696", 708 | "x": 0, 709 | "y": 0, 710 | "label": "192.168.12.93", 711 | "color": "#00adee", 712 | "size": 20, 713 | "textColor": "#878787", 714 | "textSize": 10, 715 | "customField1": "自定义字段1", 716 | "customField2": [ 717 | "自定义字段2_1", 718 | "自定义字段2_2" 719 | ], 720 | "customField3": { 721 | "field3_1": "自定义字段3_1", 722 | "field3_2": "自定义字段3_2" 723 | } 724 | }, 725 | { 726 | "id": "-2051156693", 727 | "x": 0, 728 | "y": 0, 729 | "label": "192.168.12.96", 730 | "color": "#00adee", 731 | "size": 20, 732 | "textColor": "#878787", 733 | "textSize": 10, 734 | "customField1": "自定义字段1", 735 | "customField2": [ 736 | "自定义字段2_1", 737 | "自定义字段2_2" 738 | ], 739 | "customField3": { 740 | "field3_1": "自定义字段3_1", 741 | "field3_2": "自定义字段3_2" 742 | } 743 | }, 744 | { 745 | "id": "838644385", 746 | "x": 0, 747 | "y": 0, 748 | "label": "192.168.12.186", 749 | "color": "#00adee", 750 | "size": 20, 751 | "textColor": "#878787", 752 | "textSize": 10, 753 | "customField1": "自定义字段1", 754 | "customField2": [ 755 | "自定义字段2_1", 756 | "自定义字段2_2" 757 | ], 758 | "customField3": { 759 | "field3_1": "自定义字段3_1", 760 | "field3_2": "自定义字段3_2" 761 | } 762 | }, 763 | { 764 | "id": "-2051156822", 765 | "x": 0, 766 | "y": 0, 767 | "label": "192.168.12.51", 768 | "color": "#00adee", 769 | "size": 20, 770 | "textColor": "#878787", 771 | "textSize": 10, 772 | "customField1": "自定义字段1", 773 | "customField2": [ 774 | "自定义字段2_1", 775 | "自定义字段2_2" 776 | ], 777 | "customField3": { 778 | "field3_1": "自定义字段3_1", 779 | "field3_2": "自定义字段3_2" 780 | } 781 | }, 782 | { 783 | "id": "201294094", 784 | "x": 0, 785 | "y": 0, 786 | "label": "192.168.110.193", 787 | "color": "#00adee", 788 | "size": 20, 789 | "textColor": "#878787", 790 | "textSize": 10, 791 | "customField1": "自定义字段1", 792 | "customField2": [ 793 | "自定义字段2_1", 794 | "自定义字段2_2" 795 | ], 796 | "customField3": { 797 | "field3_1": "自定义字段3_1", 798 | "field3_2": "自定义字段3_2" 799 | } 800 | }, 801 | { 802 | "id": "838644412", 803 | "x": 0, 804 | "y": 0, 805 | "label": "192.168.12.192", 806 | "color": "#00adee", 807 | "size": 20, 808 | "textColor": "#878787", 809 | "textSize": 10, 810 | "customField1": "自定义字段1", 811 | "customField2": [ 812 | "自定义字段2_1", 813 | "自定义字段2_2" 814 | ], 815 | "customField3": { 816 | "field3_1": "自定义字段3_1", 817 | "field3_2": "自定义字段3_2" 818 | } 819 | }, 820 | { 821 | "id": "838644410", 822 | "x": 0, 823 | "y": 0, 824 | "label": "192.168.12.190", 825 | "color": "#00adee", 826 | "size": 20, 827 | "textColor": "#878787", 828 | "textSize": 10, 829 | "customField1": "自定义字段1", 830 | "customField2": [ 831 | "自定义字段2_1", 832 | "自定义字段2_2" 833 | ], 834 | "customField3": { 835 | "field3_1": "自定义字段3_1", 836 | "field3_2": "自定义字段3_2" 837 | } 838 | }, 839 | { 840 | "id": "201294933", 841 | "x": 0, 842 | "y": 0, 843 | "label": "192.168.110.255", 844 | "color": "#00adee", 845 | "size": 20, 846 | "textColor": "#878787", 847 | "textSize": 10, 848 | "customField1": "自定义字段1", 849 | "customField2": [ 850 | "自定义字段2_1", 851 | "自定义字段2_2" 852 | ], 853 | "customField3": { 854 | "field3_1": "自定义字段3_1", 855 | "field3_2": "自定义字段3_2" 856 | } 857 | }, 858 | { 859 | "id": "-2050948375", 860 | "x": 0, 861 | "y": 0, 862 | "label": "192.168.19.24", 863 | "color": "#00adee", 864 | "size": 20, 865 | "textColor": "#878787", 866 | "textSize": 10, 867 | "customField1": "自定义字段1", 868 | "customField2": [ 869 | "自定义字段2_1", 870 | "自定义字段2_2" 871 | ], 872 | "customField3": { 873 | "field3_1": "自定义字段3_1", 874 | "field3_2": "自定义字段3_2" 875 | } 876 | }, 877 | { 878 | "id": "591595283", 879 | "x": 0, 880 | "y": 0, 881 | "label": "228.6.7.8", 882 | "color": "#00adee", 883 | "size": 20, 884 | "textColor": "#878787", 885 | "textSize": 10, 886 | "customField1": "自定义字段1", 887 | "customField2": [ 888 | "自定义字段2_1", 889 | "自定义字段2_2" 890 | ], 891 | "customField3": { 892 | "field3_1": "自定义字段3_1", 893 | "field3_2": "自定义字段3_2" 894 | } 895 | }, 896 | { 897 | "id": "-910498946", 898 | "x": 0, 899 | "y": 0, 900 | "label": "255.255.255.255", 901 | "color": "#00adee", 902 | "size": 40, 903 | "textColor": "#878787", 904 | "textSize": 10, 905 | "customField1": "自定义字段1", 906 | "customField2": [ 907 | "自定义字段2_1", 908 | "自定义字段2_2" 909 | ], 910 | "customField3": { 911 | "field3_1": "自定义字段3_1", 912 | "field3_2": "自定义字段3_2" 913 | } 914 | }, 915 | { 916 | "id": "-2051156846", 917 | "x": 0, 918 | "y": 0, 919 | "label": "192.168.12.48", 920 | "color": "#00adee", 921 | "size": 20, 922 | "textColor": "#878787", 923 | "textSize": 10, 924 | "customField1": "自定义字段1", 925 | "customField2": [ 926 | "自定义字段2_1", 927 | "自定义字段2_2" 928 | ], 929 | "customField3": { 930 | "field3_1": "自定义字段3_1", 931 | "field3_2": "自定义字段3_2" 932 | } 933 | }, 934 | { 935 | "id": "-2051156728", 936 | "x": 0, 937 | "y": 0, 938 | "label": "192.168.12.82", 939 | "color": "#00adee", 940 | "size": 20, 941 | "textColor": "#878787", 942 | "textSize": 10, 943 | "customField1": "自定义字段1", 944 | "customField2": [ 945 | "自定义字段2_1", 946 | "自定义字段2_2" 947 | ], 948 | "customField3": { 949 | "field3_1": "自定义字段3_1", 950 | "field3_2": "自定义字段3_2" 951 | } 952 | }, 953 | { 954 | "id": "838644232", 955 | "x": 0, 956 | "y": 0, 957 | "label": "192.168.12.138", 958 | "color": "#00adee", 959 | "size": 20, 960 | "textColor": "#878787", 961 | "textSize": 10, 962 | "customField1": "自定义字段1", 963 | "customField2": [ 964 | "自定义字段2_1", 965 | "自定义字段2_2" 966 | ], 967 | "customField3": { 968 | "field3_1": "自定义字段3_1", 969 | "field3_2": "自定义字段3_2" 970 | } 971 | }, 972 | { 973 | "id": "838644353", 974 | "x": 0, 975 | "y": 0, 976 | "label": "192.168.12.175", 977 | "color": "#00adee", 978 | "size": 20, 979 | "textColor": "#878787", 980 | "textSize": 10, 981 | "customField1": "自定义字段1", 982 | "customField2": [ 983 | "自定义字段2_1", 984 | "自定义字段2_2" 985 | ], 986 | "customField3": { 987 | "field3_1": "自定义字段3_1", 988 | "field3_2": "自定义字段3_2" 989 | } 990 | }, 991 | { 992 | "id": "838645100", 993 | "x": 0, 994 | "y": 0, 995 | "label": "192.168.12.208", 996 | "color": "#00adee", 997 | "size": 20, 998 | "textColor": "#878787", 999 | "textSize": 10, 1000 | "customField1": "自定义字段1", 1001 | "customField2": [ 1002 | "自定义字段2_1", 1003 | "自定义字段2_2" 1004 | ], 1005 | "customField3": { 1006 | "field3_1": "自定义字段3_1", 1007 | "field3_2": "自定义字段3_2" 1008 | } 1009 | }, 1010 | { 1011 | "id": "-2051156852", 1012 | "x": 0, 1013 | "y": 0, 1014 | "label": "192.168.12.42", 1015 | "color": "#00adee", 1016 | "size": 20, 1017 | "textColor": "#878787", 1018 | "textSize": 10, 1019 | "customField1": "自定义字段1", 1020 | "customField2": [ 1021 | "自定义字段2_1", 1022 | "自定义字段2_2" 1023 | ], 1024 | "customField3": { 1025 | "field3_1": "自定义字段3_1", 1026 | "field3_2": "自定义字段3_2" 1027 | } 1028 | }, 1029 | { 1030 | "id": "-2051156850", 1031 | "x": 0, 1032 | "y": 0, 1033 | "label": "192.168.12.44", 1034 | "color": "#00adee", 1035 | "size": 20, 1036 | "textColor": "#878787", 1037 | "textSize": 10, 1038 | "customField1": "自定义字段1", 1039 | "customField2": [ 1040 | "自定义字段2_1", 1041 | "自定义字段2_2" 1042 | ], 1043 | "customField3": { 1044 | "field3_1": "自定义字段3_1", 1045 | "field3_2": "自定义字段3_2" 1046 | } 1047 | }, 1048 | { 1049 | "id": "838645224", 1050 | "x": 0, 1051 | "y": 0, 1052 | "label": "192.168.12.248", 1053 | "color": "#00adee", 1054 | "size": 20, 1055 | "textColor": "#878787", 1056 | "textSize": 10, 1057 | "customField1": "自定义字段1", 1058 | "customField2": [ 1059 | "自定义字段2_1", 1060 | "自定义字段2_2" 1061 | ], 1062 | "customField3": { 1063 | "field3_1": "自定义字段3_1", 1064 | "field3_2": "自定义字段3_2" 1065 | } 1066 | } 1067 | ], 1068 | "edges": [ 1069 | { 1070 | "target": "-910498946", 1071 | "source": "1013191670", 1072 | "size": 1, 1073 | "color": "#c2c2c2", 1074 | "customField1": "自定义字段1", 1075 | "customField2": [ 1076 | "自定义字段2_1", 1077 | "自定义字段2_2" 1078 | ], 1079 | "customField3": { 1080 | "field3_1": "自定义字段3_1", 1081 | "field3_2": "自定义字段3_2" 1082 | } 1083 | }, 1084 | { 1085 | "target": "591595283", 1086 | "source": "838645129", 1087 | "size": 1, 1088 | "color": "#c2c2c2", 1089 | "customField1": "自定义字段1", 1090 | "customField2": [ 1091 | "自定义字段2_1", 1092 | "自定义字段2_2" 1093 | ], 1094 | "customField3": { 1095 | "field3_1": "自定义字段3_1", 1096 | "field3_2": "自定义字段3_2" 1097 | } 1098 | }, 1099 | { 1100 | "target": "-2051156877", 1101 | "source": "-2050948375", 1102 | "size": 1, 1103 | "color": "#c2c2c2", 1104 | "customField1": "自定义字段1", 1105 | "customField2": [ 1106 | "自定义字段2_1", 1107 | "自定义字段2_2" 1108 | ], 1109 | "customField3": { 1110 | "field3_1": "自定义字段3_1", 1111 | "field3_2": "自定义字段3_2" 1112 | } 1113 | }, 1114 | { 1115 | "target": "-809256360", 1116 | "source": "-2051156693", 1117 | "size": 1, 1118 | "color": "#c2c2c2", 1119 | "customField1": "自定义字段1", 1120 | "customField2": [ 1121 | "自定义字段2_1", 1122 | "自定义字段2_2" 1123 | ], 1124 | "customField3": { 1125 | "field3_1": "自定义字段3_1", 1126 | "field3_2": "自定义字段3_2" 1127 | } 1128 | }, 1129 | { 1130 | "target": "-809256360", 1131 | "source": "838644165", 1132 | "size": 1, 1133 | "color": "#c2c2c2", 1134 | "customField1": "自定义字段1", 1135 | "customField2": [ 1136 | "自定义字段2_1", 1137 | "自定义字段2_2" 1138 | ], 1139 | "customField3": { 1140 | "field3_1": "自定义字段3_1", 1141 | "field3_2": "自定义字段3_2" 1142 | } 1143 | }, 1144 | { 1145 | "target": "-809256360", 1146 | "source": "838644258", 1147 | "size": 1, 1148 | "color": "#c2c2c2", 1149 | "customField1": "自定义字段1", 1150 | "customField2": [ 1151 | "自定义字段2_1", 1152 | "自定义字段2_2" 1153 | ], 1154 | "customField3": { 1155 | "field3_1": "自定义字段3_1", 1156 | "field3_2": "自定义字段3_2" 1157 | } 1158 | }, 1159 | { 1160 | "target": "-809256360", 1161 | "source": "838644163", 1162 | "size": 1, 1163 | "color": "#c2c2c2", 1164 | "customField1": "自定义字段1", 1165 | "customField2": [ 1166 | "自定义字段2_1", 1167 | "自定义字段2_2" 1168 | ], 1169 | "customField3": { 1170 | "field3_1": "自定义字段3_1", 1171 | "field3_2": "自定义字段3_2" 1172 | } 1173 | }, 1174 | { 1175 | "target": "-809256360", 1176 | "source": "-2051156728", 1177 | "size": 1, 1178 | "color": "#c2c2c2", 1179 | "customField1": "自定义字段1", 1180 | "customField2": [ 1181 | "自定义字段2_1", 1182 | "自定义字段2_2" 1183 | ], 1184 | "customField3": { 1185 | "field3_1": "自定义字段3_1", 1186 | "field3_2": "自定义字段3_2" 1187 | } 1188 | }, 1189 | { 1190 | "target": "-809256360", 1191 | "source": "838644195", 1192 | "size": 1, 1193 | "color": "#c2c2c2", 1194 | "customField1": "自定义字段1", 1195 | "customField2": [ 1196 | "自定义字段2_1", 1197 | "自定义字段2_2" 1198 | ], 1199 | "customField3": { 1200 | "field3_1": "自定义字段3_1", 1201 | "field3_2": "自定义字段3_2" 1202 | } 1203 | }, 1204 | { 1205 | "target": "-809256360", 1206 | "source": "838644232", 1207 | "size": 1, 1208 | "color": "#c2c2c2", 1209 | "customField1": "自定义字段1", 1210 | "customField2": [ 1211 | "自定义字段2_1", 1212 | "自定义字段2_2" 1213 | ], 1214 | "customField3": { 1215 | "field3_1": "自定义字段3_1", 1216 | "field3_2": "自定义字段3_2" 1217 | } 1218 | }, 1219 | { 1220 | "target": "-809256360", 1221 | "source": "838644321", 1222 | "size": 1, 1223 | "color": "#c2c2c2", 1224 | "customField1": "自定义字段1", 1225 | "customField2": [ 1226 | "自定义字段2_1", 1227 | "自定义字段2_2" 1228 | ], 1229 | "customField3": { 1230 | "field3_1": "自定义字段3_1", 1231 | "field3_2": "自定义字段3_2" 1232 | } 1233 | }, 1234 | { 1235 | "target": "-809256360", 1236 | "source": "-2051156696", 1237 | "size": 1, 1238 | "color": "#c2c2c2", 1239 | "customField1": "自定义字段1", 1240 | "customField2": [ 1241 | "自定义字段2_1", 1242 | "自定义字段2_2" 1243 | ], 1244 | "customField3": { 1245 | "field3_1": "自定义字段3_1", 1246 | "field3_2": "自定义字段3_2" 1247 | } 1248 | }, 1249 | { 1250 | "target": "-809256360", 1251 | "source": "-2051156846", 1252 | "size": 1, 1253 | "color": "#c2c2c2", 1254 | "customField1": "自定义字段1", 1255 | "customField2": [ 1256 | "自定义字段2_1", 1257 | "自定义字段2_2" 1258 | ], 1259 | "customField3": { 1260 | "field3_1": "自定义字段3_1", 1261 | "field3_2": "自定义字段3_2" 1262 | } 1263 | }, 1264 | { 1265 | "target": "-809256360", 1266 | "source": "-2051156852", 1267 | "size": 1, 1268 | "color": "#c2c2c2", 1269 | "customField1": "自定义字段1", 1270 | "customField2": [ 1271 | "自定义字段2_1", 1272 | "自定义字段2_2" 1273 | ], 1274 | "customField3": { 1275 | "field3_1": "自定义字段3_1", 1276 | "field3_2": "自定义字段3_2" 1277 | } 1278 | }, 1279 | { 1280 | "target": "-809256360", 1281 | "source": "-2051156884", 1282 | "size": 1, 1283 | "color": "#c2c2c2", 1284 | "customField1": "自定义字段1", 1285 | "customField2": [ 1286 | "自定义字段2_1", 1287 | "自定义字段2_2" 1288 | ], 1289 | "customField3": { 1290 | "field3_1": "自定义字段3_1", 1291 | "field3_2": "自定义字段3_2" 1292 | } 1293 | }, 1294 | { 1295 | "target": "-809256360", 1296 | "source": "838645159", 1297 | "size": 1, 1298 | "color": "#c2c2c2", 1299 | "customField1": "自定义字段1", 1300 | "customField2": [ 1301 | "自定义字段2_1", 1302 | "自定义字段2_2" 1303 | ], 1304 | "customField3": { 1305 | "field3_1": "自定义字段3_1", 1306 | "field3_2": "自定义字段3_2" 1307 | } 1308 | }, 1309 | { 1310 | "target": "-809256360", 1311 | "source": "838644385", 1312 | "size": 1, 1313 | "color": "#c2c2c2", 1314 | "customField1": "自定义字段1", 1315 | "customField2": [ 1316 | "自定义字段2_1", 1317 | "自定义字段2_2" 1318 | ], 1319 | "customField3": { 1320 | "field3_1": "自定义字段3_1", 1321 | "field3_2": "自定义字段3_2" 1322 | } 1323 | }, 1324 | { 1325 | "target": "-809256360", 1326 | "source": "-2051156877", 1327 | "size": 1, 1328 | "color": "#c2c2c2", 1329 | "customField1": "自定义字段1", 1330 | "customField2": [ 1331 | "自定义字段2_1", 1332 | "自定义字段2_2" 1333 | ], 1334 | "customField3": { 1335 | "field3_1": "自定义字段3_1", 1336 | "field3_2": "自定义字段3_2" 1337 | } 1338 | }, 1339 | { 1340 | "target": "-809256360", 1341 | "source": "838645129", 1342 | "size": 1, 1343 | "color": "#c2c2c2", 1344 | "customField1": "自定义字段1", 1345 | "customField2": [ 1346 | "自定义字段2_1", 1347 | "自定义字段2_2" 1348 | ], 1349 | "customField3": { 1350 | "field3_1": "自定义字段3_1", 1351 | "field3_2": "自定义字段3_2" 1352 | } 1353 | }, 1354 | { 1355 | "target": "-809256360", 1356 | "source": "-2051156850", 1357 | "size": 1, 1358 | "color": "#c2c2c2", 1359 | "customField1": "自定义字段1", 1360 | "customField2": [ 1361 | "自定义字段2_1", 1362 | "自定义字段2_2" 1363 | ], 1364 | "customField3": { 1365 | "field3_1": "自定义字段3_1", 1366 | "field3_2": "自定义字段3_2" 1367 | } 1368 | }, 1369 | { 1370 | "target": "-809256360", 1371 | "source": "838645100", 1372 | "size": 1, 1373 | "color": "#c2c2c2", 1374 | "customField1": "自定义字段1", 1375 | "customField2": [ 1376 | "自定义字段2_1", 1377 | "自定义字段2_2" 1378 | ], 1379 | "customField3": { 1380 | "field3_1": "自定义字段3_1", 1381 | "field3_2": "自定义字段3_2" 1382 | } 1383 | }, 1384 | { 1385 | "target": "-809256360", 1386 | "source": "838644410", 1387 | "size": 1, 1388 | "color": "#c2c2c2", 1389 | "customField1": "自定义字段1", 1390 | "customField2": [ 1391 | "自定义字段2_1", 1392 | "自定义字段2_2" 1393 | ], 1394 | "customField3": { 1395 | "field3_1": "自定义字段3_1", 1396 | "field3_2": "自定义字段3_2" 1397 | } 1398 | }, 1399 | { 1400 | "target": "-809256360", 1401 | "source": "838644198", 1402 | "size": 1, 1403 | "color": "#c2c2c2", 1404 | "customField1": "自定义字段1", 1405 | "customField2": [ 1406 | "自定义字段2_1", 1407 | "自定义字段2_2" 1408 | ], 1409 | "customField3": { 1410 | "field3_1": "自定义字段3_1", 1411 | "field3_2": "自定义字段3_2" 1412 | } 1413 | }, 1414 | { 1415 | "target": "-809256360", 1416 | "source": "838644166", 1417 | "size": 1, 1418 | "color": "#c2c2c2", 1419 | "customField1": "自定义字段1", 1420 | "customField2": [ 1421 | "自定义字段2_1", 1422 | "自定义字段2_2" 1423 | ], 1424 | "customField3": { 1425 | "field3_1": "自定义字段3_1", 1426 | "field3_2": "自定义字段3_2" 1427 | } 1428 | }, 1429 | { 1430 | "target": "-809256360", 1431 | "source": "201294094", 1432 | "size": 1, 1433 | "color": "#c2c2c2", 1434 | "customField1": "自定义字段1", 1435 | "customField2": [ 1436 | "自定义字段2_1", 1437 | "自定义字段2_2" 1438 | ], 1439 | "customField3": { 1440 | "field3_1": "自定义字段3_1", 1441 | "field3_2": "自定义字段3_2" 1442 | } 1443 | }, 1444 | { 1445 | "target": "-809256360", 1446 | "source": "838645160", 1447 | "size": 1, 1448 | "color": "#c2c2c2", 1449 | "customField1": "自定义字段1", 1450 | "customField2": [ 1451 | "自定义字段2_1", 1452 | "自定义字段2_2" 1453 | ], 1454 | "customField3": { 1455 | "field3_1": "自定义字段3_1", 1456 | "field3_2": "自定义字段3_2" 1457 | } 1458 | }, 1459 | { 1460 | "target": "-809256360", 1461 | "source": "838644171", 1462 | "size": 1, 1463 | "color": "#c2c2c2", 1464 | "customField1": "自定义字段1", 1465 | "customField2": [ 1466 | "自定义字段2_1", 1467 | "自定义字段2_2" 1468 | ], 1469 | "customField3": { 1470 | "field3_1": "自定义字段3_1", 1471 | "field3_2": "自定义字段3_2" 1472 | } 1473 | }, 1474 | { 1475 | "target": "-809256360", 1476 | "source": "-2051156911", 1477 | "size": 1, 1478 | "color": "#c2c2c2", 1479 | "customField1": "自定义字段1", 1480 | "customField2": [ 1481 | "自定义字段2_1", 1482 | "自定义字段2_2" 1483 | ], 1484 | "customField3": { 1485 | "field3_1": "自定义字段3_1", 1486 | "field3_2": "自定义字段3_2" 1487 | } 1488 | }, 1489 | { 1490 | "target": "-809256360", 1491 | "source": "1734948971", 1492 | "size": 1, 1493 | "color": "#c2c2c2", 1494 | "customField1": "自定义字段1", 1495 | "customField2": [ 1496 | "自定义字段2_1", 1497 | "自定义字段2_2" 1498 | ], 1499 | "customField3": { 1500 | "field3_1": "自定义字段3_1", 1501 | "field3_2": "自定义字段3_2" 1502 | } 1503 | }, 1504 | { 1505 | "target": "-809256360", 1506 | "source": "838644164", 1507 | "size": 1, 1508 | "color": "#c2c2c2", 1509 | "customField1": "自定义字段1", 1510 | "customField2": [ 1511 | "自定义字段2_1", 1512 | "自定义字段2_2" 1513 | ], 1514 | "customField3": { 1515 | "field3_1": "自定义字段3_1", 1516 | "field3_2": "自定义字段3_2" 1517 | } 1518 | }, 1519 | { 1520 | "target": "-809256360", 1521 | "source": "838645126", 1522 | "size": 1, 1523 | "color": "#c2c2c2", 1524 | "customField1": "自定义字段1", 1525 | "customField2": [ 1526 | "自定义字段2_1", 1527 | "自定义字段2_2" 1528 | ], 1529 | "customField3": { 1530 | "field3_1": "自定义字段3_1", 1531 | "field3_2": "自定义字段3_2" 1532 | } 1533 | }, 1534 | { 1535 | "target": "-809256360", 1536 | "source": "838644350", 1537 | "size": 1, 1538 | "color": "#c2c2c2", 1539 | "customField1": "自定义字段1", 1540 | "customField2": [ 1541 | "自定义字段2_1", 1542 | "自定义字段2_2" 1543 | ], 1544 | "customField3": { 1545 | "field3_1": "自定义字段3_1", 1546 | "field3_2": "自定义字段3_2" 1547 | } 1548 | }, 1549 | { 1550 | "target": "838645127", 1551 | "source": "-2051156877", 1552 | "size": 1, 1553 | "color": "#c2c2c2", 1554 | "customField1": "自定义字段1", 1555 | "customField2": [ 1556 | "自定义字段2_1", 1557 | "自定义字段2_2" 1558 | ], 1559 | "customField3": { 1560 | "field3_1": "自定义字段3_1", 1561 | "field3_2": "自定义字段3_2" 1562 | } 1563 | }, 1564 | { 1565 | "target": "838645128", 1566 | "source": "-2051156877", 1567 | "size": 1, 1568 | "color": "#c2c2c2", 1569 | "customField1": "自定义字段1", 1570 | "customField2": [ 1571 | "自定义字段2_1", 1572 | "自定义字段2_2" 1573 | ], 1574 | "customField3": { 1575 | "field3_1": "自定义字段3_1", 1576 | "field3_2": "自定义字段3_2" 1577 | } 1578 | }, 1579 | { 1580 | "target": "838644353", 1581 | "source": "-2051156884", 1582 | "size": 1, 1583 | "color": "#c2c2c2", 1584 | "customField1": "自定义字段1", 1585 | "customField2": [ 1586 | "自定义字段2_1", 1587 | "自定义字段2_2" 1588 | ], 1589 | "customField3": { 1590 | "field3_1": "自定义字段3_1", 1591 | "field3_2": "自定义字段3_2" 1592 | } 1593 | }, 1594 | { 1595 | "target": "838644353", 1596 | "source": "-2051156877", 1597 | "size": 1, 1598 | "color": "#c2c2c2", 1599 | "customField1": "自定义字段1", 1600 | "customField2": [ 1601 | "自定义字段2_1", 1602 | "自定义字段2_2" 1603 | ], 1604 | "customField3": { 1605 | "field3_1": "自定义字段3_1", 1606 | "field3_2": "自定义字段3_2" 1607 | } 1608 | }, 1609 | { 1610 | "target": "838645224", 1611 | "source": "-2051156759", 1612 | "size": 1, 1613 | "color": "#c2c2c2", 1614 | "customField1": "自定义字段1", 1615 | "customField2": [ 1616 | "自定义字段2_1", 1617 | "自定义字段2_2" 1618 | ], 1619 | "customField3": { 1620 | "field3_1": "自定义字段3_1", 1621 | "field3_2": "自定义字段3_2" 1622 | } 1623 | }, 1624 | { 1625 | "target": "838645252", 1626 | "source": "-2051156877", 1627 | "size": 1, 1628 | "color": "#c2c2c2", 1629 | "customField1": "自定义字段1", 1630 | "customField2": [ 1631 | "自定义字段2_1", 1632 | "自定义字段2_2" 1633 | ], 1634 | "customField3": { 1635 | "field3_1": "自定义字段3_1", 1636 | "field3_2": "自定义字段3_2" 1637 | } 1638 | }, 1639 | { 1640 | "target": "838644165", 1641 | "source": "-2051156877", 1642 | "size": 1, 1643 | "color": "#c2c2c2", 1644 | "customField1": "自定义字段1", 1645 | "customField2": [ 1646 | "自定义字段2_1", 1647 | "自定义字段2_2" 1648 | ], 1649 | "customField3": { 1650 | "field3_1": "自定义字段3_1", 1651 | "field3_2": "自定义字段3_2" 1652 | } 1653 | }, 1654 | { 1655 | "target": "201294933", 1656 | "source": "201294094", 1657 | "size": 1, 1658 | "color": "#c2c2c2", 1659 | "customField1": "自定义字段1", 1660 | "customField2": [ 1661 | "自定义字段2_1", 1662 | "自定义字段2_2" 1663 | ], 1664 | "customField3": { 1665 | "field3_1": "自定义字段3_1", 1666 | "field3_2": "自定义字段3_2" 1667 | } 1668 | }, 1669 | { 1670 | "target": "-2007034805", 1671 | "source": "-2051156877", 1672 | "size": 1, 1673 | "color": "#c2c2c2", 1674 | "customField1": "自定义字段1", 1675 | "customField2": [ 1676 | "自定义字段2_1", 1677 | "自定义字段2_2" 1678 | ], 1679 | "customField3": { 1680 | "field3_1": "自定义字段3_1", 1681 | "field3_2": "自定义字段3_2" 1682 | } 1683 | }, 1684 | { 1685 | "target": "-1072993729", 1686 | "source": "-2051156912", 1687 | "size": 1, 1688 | "color": "#c2c2c2", 1689 | "customField1": "自定义字段1", 1690 | "customField2": [ 1691 | "自定义字段2_1", 1692 | "自定义字段2_2" 1693 | ], 1694 | "customField3": { 1695 | "field3_1": "自定义字段3_1", 1696 | "field3_2": "自定义字段3_2" 1697 | } 1698 | }, 1699 | { 1700 | "target": "-1072993729", 1701 | "source": "838644324", 1702 | "size": 1, 1703 | "color": "#c2c2c2", 1704 | "customField1": "自定义字段1", 1705 | "customField2": [ 1706 | "自定义字段2_1", 1707 | "自定义字段2_2" 1708 | ], 1709 | "customField3": { 1710 | "field3_1": "自定义字段3_1", 1711 | "field3_2": "自定义字段3_2" 1712 | } 1713 | }, 1714 | { 1715 | "target": "-910498946", 1716 | "source": "838644353", 1717 | "size": 1, 1718 | "color": "#c2c2c2", 1719 | "customField1": "自定义字段1", 1720 | "customField2": [ 1721 | "自定义字段2_1", 1722 | "自定义字段2_2" 1723 | ], 1724 | "customField3": { 1725 | "field3_1": "自定义字段3_1", 1726 | "field3_2": "自定义字段3_2" 1727 | } 1728 | }, 1729 | { 1730 | "target": "1807683160", 1731 | "source": "-2051156759", 1732 | "size": 1, 1733 | "color": "#c2c2c2", 1734 | "customField1": "自定义字段1", 1735 | "customField2": [ 1736 | "自定义字段2_1", 1737 | "自定义字段2_2" 1738 | ], 1739 | "customField3": { 1740 | "field3_1": "自定义字段3_1", 1741 | "field3_2": "自定义字段3_2" 1742 | } 1743 | }, 1744 | { 1745 | "target": "-809256359", 1746 | "source": "838644318", 1747 | "size": 1, 1748 | "color": "#c2c2c2", 1749 | "customField1": "自定义字段1", 1750 | "customField2": [ 1751 | "自定义字段2_1", 1752 | "自定义字段2_2" 1753 | ], 1754 | "customField3": { 1755 | "field3_1": "自定义字段3_1", 1756 | "field3_2": "自定义字段3_2" 1757 | } 1758 | }, 1759 | { 1760 | "target": "-2051156789", 1761 | "source": "838644353", 1762 | "size": 1, 1763 | "color": "#c2c2c2", 1764 | "customField1": "自定义字段1", 1765 | "customField2": [ 1766 | "自定义字段2_1", 1767 | "自定义字段2_2" 1768 | ], 1769 | "customField3": { 1770 | "field3_1": "自定义字段3_1", 1771 | "field3_2": "自定义字段3_2" 1772 | } 1773 | }, 1774 | { 1775 | "target": "838645252", 1776 | "source": "838644353", 1777 | "size": 1, 1778 | "color": "#c2c2c2", 1779 | "customField1": "自定义字段1", 1780 | "customField2": [ 1781 | "自定义字段2_1", 1782 | "自定义字段2_2" 1783 | ], 1784 | "customField3": { 1785 | "field3_1": "自定义字段3_1", 1786 | "field3_2": "自定义字段3_2" 1787 | } 1788 | }, 1789 | { 1790 | "target": "838645252", 1791 | "source": "838645248", 1792 | "size": 1, 1793 | "color": "#c2c2c2", 1794 | "customField1": "自定义字段1", 1795 | "customField2": [ 1796 | "自定义字段2_1", 1797 | "自定义字段2_2" 1798 | ], 1799 | "customField3": { 1800 | "field3_1": "自定义字段3_1", 1801 | "field3_2": "自定义字段3_2" 1802 | } 1803 | }, 1804 | { 1805 | "target": "838645252", 1806 | "source": "-2051156755", 1807 | "size": 1, 1808 | "color": "#c2c2c2", 1809 | "customField1": "自定义字段1", 1810 | "customField2": [ 1811 | "自定义字段2_1", 1812 | "自定义字段2_2" 1813 | ], 1814 | "customField3": { 1815 | "field3_1": "自定义字段3_1", 1816 | "field3_2": "自定义字段3_2" 1817 | } 1818 | }, 1819 | { 1820 | "target": "838645252", 1821 | "source": "-2051156822", 1822 | "size": 1, 1823 | "color": "#c2c2c2", 1824 | "customField1": "自定义字段1", 1825 | "customField2": [ 1826 | "自定义字段2_1", 1827 | "自定义字段2_2" 1828 | ], 1829 | "customField3": { 1830 | "field3_1": "自定义字段3_1", 1831 | "field3_2": "自定义字段3_2" 1832 | } 1833 | }, 1834 | { 1835 | "target": "838645252", 1836 | "source": "-2051156939", 1837 | "size": 1, 1838 | "color": "#c2c2c2", 1839 | "customField1": "自定义字段1", 1840 | "customField2": [ 1841 | "自定义字段2_1", 1842 | "自定义字段2_2" 1843 | ], 1844 | "customField3": { 1845 | "field3_1": "自定义字段3_1", 1846 | "field3_2": "自定义字段3_2" 1847 | } 1848 | }, 1849 | { 1850 | "target": "838645252", 1851 | "source": "-2051156883", 1852 | "size": 1, 1853 | "color": "#c2c2c2", 1854 | "customField1": "自定义字段1", 1855 | "customField2": [ 1856 | "自定义字段2_1", 1857 | "自定义字段2_2" 1858 | ], 1859 | "customField3": { 1860 | "field3_1": "自定义字段3_1", 1861 | "field3_2": "自定义字段3_2" 1862 | } 1863 | }, 1864 | { 1865 | "target": "838645252", 1866 | "source": "-2051156699", 1867 | "size": 1, 1868 | "color": "#c2c2c2", 1869 | "customField1": "自定义字段1", 1870 | "customField2": [ 1871 | "自定义字段2_1", 1872 | "自定义字段2_2" 1873 | ], 1874 | "customField3": { 1875 | "field3_1": "自定义字段3_1", 1876 | "field3_2": "自定义字段3_2" 1877 | } 1878 | }, 1879 | { 1880 | "target": "838645252", 1881 | "source": "838644412", 1882 | "size": 1, 1883 | "color": "#c2c2c2", 1884 | "customField1": "自定义字段1", 1885 | "customField2": [ 1886 | "自定义字段2_1", 1887 | "自定义字段2_2" 1888 | ], 1889 | "customField3": { 1890 | "field3_1": "自定义字段3_1", 1891 | "field3_2": "自定义字段3_2" 1892 | } 1893 | } 1894 | ] 1895 | } -------------------------------------------------------------------------------- /demo/data_small.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "838644321", 5 | "label": "192.168.12.164" 6 | }, 7 | { 8 | "id": "-2051156877", 9 | "label": "192.168.12.38" 10 | }, 11 | { 12 | "id": "838644324", 13 | "label": "192.168.12.167" 14 | }, 15 | { 16 | "id": "-2051156755", 17 | "label": "192.168.12.76" 18 | }, 19 | { 20 | "id": "838644171", 21 | "label": "192.168.12.119" 22 | }, 23 | { 24 | "id": "838645127", 25 | "label": "192.168.12.214" 26 | }, 27 | { 28 | "id": "838645126", 29 | "label": "192.168.12.213" 30 | }, 31 | { 32 | "id": "1734948971", 33 | "label": "192.168.12.9" 34 | }, 35 | { 36 | "id": "-2051156759", 37 | "label": "192.168.12.72" 38 | }, 39 | { 40 | "id": "838644166", 41 | "label": "192.168.12.114" 42 | }, 43 | { 44 | "id": "-2051156883", 45 | "label": "192.168.12.32" 46 | }, 47 | { 48 | "id": "838645129", 49 | "label": "192.168.12.216" 50 | }, 51 | { 52 | "id": "838644165", 53 | "label": "192.168.12.113" 54 | }, 55 | { 56 | "id": "-2051156884", 57 | "label": "192.168.12.31" 58 | }, 59 | { 60 | "id": "838644164", 61 | "label": "192.168.12.112" 62 | }, 63 | { 64 | "id": "838645128", 65 | "label": "192.168.12.215" 66 | }, 67 | { 68 | "id": "838644163", 69 | "label": "192.168.12.111" 70 | }, 71 | { 72 | "id": "838644350", 73 | "label": "192.168.12.172" 74 | }, 75 | { 76 | "id": "-2007034805", 77 | "label": "10.54.14.6" 78 | }, 79 | { 80 | "id": "-809256359", 81 | "label": "224.0.0.252" 82 | }, 83 | { 84 | "id": "-809256360", 85 | "label": "224.0.0.251" 86 | }, 87 | { 88 | "id": "-2051156912", 89 | "label": "192.168.12.24" 90 | }, 91 | { 92 | "id": "-2051156911", 93 | "label": "192.168.12.25" 94 | }, 95 | { 96 | "id": "838645252", 97 | "label": "192.168.12.255" 98 | }, 99 | { 100 | "id": "838645248", 101 | "label": "192.168.12.251" 102 | }, 103 | { 104 | "id": "-1072993729", 105 | "label": "239.255.255.250" 106 | }, 107 | { 108 | "id": "838645159", 109 | "label": "192.168.12.225" 110 | }, 111 | { 112 | "id": "-2051156789", 113 | "label": "192.168.12.63" 114 | }, 115 | { 116 | "id": "838645160", 117 | "label": "192.168.12.226" 118 | }, 119 | { 120 | "id": "1013191670", 121 | "label": "0.0.0.0" 122 | }, 123 | { 124 | "id": "838644198", 125 | "label": "192.168.12.125" 126 | }, 127 | { 128 | "id": "838644195", 129 | "label": "192.168.12.122" 130 | }, 131 | { 132 | "id": "838644318", 133 | "label": "192.168.12.161" 134 | }, 135 | { 136 | "id": "-2051156699", 137 | "label": "192.168.12.90" 138 | }, 139 | { 140 | "id": "838644258", 141 | "label": "192.168.12.143" 142 | }, 143 | { 144 | "id": "1807683160", 145 | "label": "111.206.79.144" 146 | }, 147 | { 148 | "id": "-2051156939", 149 | "label": "192.168.12.18" 150 | }, 151 | { 152 | "id": "-2051156696", 153 | "label": "192.168.12.93" 154 | }, 155 | { 156 | "id": "-2051156693", 157 | "label": "192.168.12.96" 158 | }, 159 | { 160 | "id": "838644385", 161 | "label": "192.168.12.186" 162 | }, 163 | { 164 | "id": "-2051156822", 165 | "label": "192.168.12.51" 166 | }, 167 | { 168 | "id": "201294094", 169 | "label": "192.168.110.193" 170 | }, 171 | { 172 | "id": "838644412", 173 | "label": "192.168.12.192" 174 | }, 175 | { 176 | "id": "838644410", 177 | "label": "192.168.12.190" 178 | }, 179 | { 180 | "id": "201294933", 181 | "label": "192.168.110.255" 182 | }, 183 | { 184 | "id": "-2050948375", 185 | "label": "192.168.19.24" 186 | }, 187 | { 188 | "id": "591595283", 189 | "label": "228.6.7.8" 190 | }, 191 | { 192 | "id": "-910498946", 193 | "label": "255.255.255.255" 194 | }, 195 | { 196 | "id": "-2051156846", 197 | "label": "192.168.12.48" 198 | }, 199 | { 200 | "id": "-2051156728", 201 | "label": "192.168.12.82" 202 | }, 203 | { 204 | "id": "838644232", 205 | "label": "192.168.12.138" 206 | }, 207 | { 208 | "id": "838644353", 209 | "label": "192.168.12.175" 210 | }, 211 | { 212 | "id": "838645100", 213 | "label": "192.168.12.208" 214 | }, 215 | { 216 | "id": "-2051156852", 217 | "label": "192.168.12.42" 218 | }, 219 | { 220 | "id": "-2051156850", 221 | "label": "192.168.12.44" 222 | }, 223 | { 224 | "id": "838645224", 225 | "label": "192.168.12.248" 226 | } 227 | ], 228 | "edges": [ 229 | { 230 | "target": "-910498946", 231 | "source": "1013191670" 232 | }, 233 | { 234 | "target": "591595283", 235 | "source": "838645129" 236 | }, 237 | { 238 | "target": "-2051156877", 239 | "source": "-2050948375" 240 | }, 241 | { 242 | "target": "-809256360", 243 | "source": "-2051156693" 244 | }, 245 | { 246 | "target": "-809256360", 247 | "source": "838644165" 248 | }, 249 | { 250 | "target": "-809256360", 251 | "source": "838644258" 252 | }, 253 | { 254 | "target": "-809256360", 255 | "source": "838644163" 256 | }, 257 | { 258 | "target": "-809256360", 259 | "source": "-2051156728" 260 | }, 261 | { 262 | "target": "-809256360", 263 | "source": "838644195" 264 | }, 265 | { 266 | "target": "-809256360", 267 | "source": "838644232" 268 | }, 269 | { 270 | "target": "-809256360", 271 | "source": "838644321" 272 | }, 273 | { 274 | "target": "-809256360", 275 | "source": "-2051156696" 276 | }, 277 | { 278 | "target": "-809256360", 279 | "source": "-2051156846" 280 | }, 281 | { 282 | "target": "-809256360", 283 | "source": "-2051156852" 284 | }, 285 | { 286 | "target": "-809256360", 287 | "source": "-2051156884" 288 | }, 289 | { 290 | "target": "-809256360", 291 | "source": "838645159" 292 | }, 293 | { 294 | "target": "-809256360", 295 | "source": "838644385" 296 | }, 297 | { 298 | "target": "-809256360", 299 | "source": "-2051156877" 300 | }, 301 | { 302 | "target": "-809256360", 303 | "source": "838645129" 304 | }, 305 | { 306 | "target": "-809256360", 307 | "source": "-2051156850" 308 | }, 309 | { 310 | "target": "-809256360", 311 | "source": "838645100" 312 | }, 313 | { 314 | "target": "-809256360", 315 | "source": "838644410" 316 | }, 317 | { 318 | "target": "-809256360", 319 | "source": "838644198" 320 | }, 321 | { 322 | "target": "-809256360", 323 | "source": "838644166" 324 | }, 325 | { 326 | "target": "-809256360", 327 | "source": "201294094" 328 | }, 329 | { 330 | "target": "-809256360", 331 | "source": "838645160" 332 | }, 333 | { 334 | "target": "-809256360", 335 | "source": "838644171" 336 | }, 337 | { 338 | "target": "-809256360", 339 | "source": "-2051156911" 340 | }, 341 | { 342 | "target": "-809256360", 343 | "source": "1734948971" 344 | }, 345 | { 346 | "target": "-809256360", 347 | "source": "838644164" 348 | }, 349 | { 350 | "target": "-809256360", 351 | "source": "838645126" 352 | }, 353 | { 354 | "target": "-809256360", 355 | "source": "838644350" 356 | }, 357 | { 358 | "target": "838645127", 359 | "source": "-2051156877" 360 | }, 361 | { 362 | "target": "838645128", 363 | "source": "-2051156877" 364 | }, 365 | { 366 | "target": "838644353", 367 | "source": "-2051156884" 368 | }, 369 | { 370 | "target": "838644353", 371 | "source": "-2051156877" 372 | }, 373 | { 374 | "target": "838645224", 375 | "source": "-2051156759" 376 | }, 377 | { 378 | "target": "838645252", 379 | "source": "-2051156877" 380 | }, 381 | { 382 | "target": "838644165", 383 | "source": "-2051156877" 384 | }, 385 | { 386 | "target": "201294933", 387 | "source": "201294094" 388 | }, 389 | { 390 | "target": "-2007034805", 391 | "source": "-2051156877" 392 | }, 393 | { 394 | "target": "-1072993729", 395 | "source": "-2051156912" 396 | }, 397 | { 398 | "target": "-1072993729", 399 | "source": "838644324" 400 | }, 401 | { 402 | "target": "-910498946", 403 | "source": "838644353" 404 | }, 405 | { 406 | "target": "1807683160", 407 | "source": "-2051156759" 408 | }, 409 | { 410 | "target": "-809256359", 411 | "source": "838644318" 412 | }, 413 | { 414 | "target": "-2051156789", 415 | "source": "838644353" 416 | }, 417 | { 418 | "target": "838645252", 419 | "source": "838644353" 420 | }, 421 | { 422 | "target": "838645252", 423 | "source": "838645248" 424 | }, 425 | { 426 | "target": "838645252", 427 | "source": "-2051156755" 428 | }, 429 | { 430 | "target": "838645252", 431 | "source": "-2051156822" 432 | }, 433 | { 434 | "target": "838645252", 435 | "source": "-2051156939" 436 | }, 437 | { 438 | "target": "838645252", 439 | "source": "-2051156883" 440 | }, 441 | { 442 | "target": "838645252", 443 | "source": "-2051156699" 444 | }, 445 | { 446 | "target": "838645252", 447 | "source": "838644412" 448 | } 449 | ] 450 | } -------------------------------------------------------------------------------- /demo/data_small_api.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "1", 5 | "label": "1", 6 | "tooltip": "1", 7 | "x": 300, 8 | "y": 100 9 | }, 10 | { 11 | "id": "2", 12 | "label": "2", 13 | "tooltip": "2", 14 | "x": 400, 15 | "y": 200 16 | }, 17 | { 18 | "id": "3", 19 | "label": "3", 20 | "tooltip": "3", 21 | "x": 100, 22 | "y": 100 23 | }, 24 | { 25 | "id": "4", 26 | "label": "4", 27 | "tooltip": "4", 28 | "x": 200, 29 | "y": 101 30 | } 31 | ], 32 | "edges": [ 33 | 34 | { 35 | "source": "3", 36 | "target": "4", 37 | "label": "3-4", 38 | "tooltip": "3-4" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /demo/控制台示例.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | canvas demo 6 | 7 | 14 | 15 | 16 |
17 | 18 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /image/ctopobg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tm-roamer/ctopo/5fe44fee1b23e12813227f5e21b86ba277cf33b5/image/ctopobg.png -------------------------------------------------------------------------------- /image/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tm-roamer/ctopo/5fe44fee1b23e12813227f5e21b86ba277cf33b5/image/demo.png -------------------------------------------------------------------------------- /image/skin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tm-roamer/ctopo/5fe44fee1b23e12813227f5e21b86ba277cf33b5/image/skin.jpg -------------------------------------------------------------------------------- /src/consolepanel.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 控制台小工具 3 | * 作者:田明 4 | * 使用方式: 5 | * var consolePanel = new ConsolePanel({ 6 | * //上下左右回调 7 | * steerwheel:function(direct){ 8 | * //direct==event.keyCode 9 | * }, 10 | * //放大,缩小回调 11 | * scale:function(scale){ 12 | * //scale=比例 13 | * } 14 | * }); 15 | */ 16 | function ConsolePanel(){ 17 | var self = this; 18 | this.console_panel="console_panel"; //div的名称 19 | this.zoom="zoom"; 20 | this.steerwheel_panel="steerwheel_panel"; 21 | this.steer_btn="steer_btn"; 22 | this.scale_bar="scale_bar"; 23 | this.scale_slider="scale_slider"; 24 | this.scale_ruler_current="scale_ruler_current"; 25 | //当前缩放比例和上一次的缩放比例,用于监听change 26 | this.scale=.5; 27 | this.prevScale=.5; 28 | 29 | //预置的高度 30 | var steerwheelHeight = 86, //方向盘的高度 31 | zoomBtnHeight=26, //放大,缩小按钮的高度 32 | scaleBarHeight = 140, //比例尺总高度 33 | scaleSliderHeight = 20, //滑块高度 34 | scaleBarBackgroundPositionX = -44, //比例尺图片精灵定位的起点x 35 | scaleBarBackgroundPositionY = -430; //比例尺图片精灵定位的起点y 36 | 37 | //切换上下左右的图片 38 | this.setSteerWheelClass = function(className){ 39 | var steerwheel_panel = document.querySelector("."+this.steerwheel_panel); 40 | steerwheel_panel.setAttribute("class",this.steerwheel_panel+" "+className); 41 | }; 42 | //设置初始化参数 43 | this.setOption = function(opt){ 44 | self.opt=opt||{}; 45 | }; 46 | //调整滑块和当前比例的位置 47 | this.setScale = function(num){ 48 | var ratioHeight, 49 | ratioTop, 50 | sliderTop, 51 | slider = self.scale_slider, //滑块 52 | ruler_current = self.scale_ruler_current; //当前比例 53 | //设置滑块和当前比例 54 | self.scale = num>1?1:(num<0.1?0:num); 55 | ratioHeight = parseInt(scaleBarHeight*self.scale); //取得当前比例高度 56 | ratioTop = parseInt(scaleBarHeight-ratioHeight); //取得当前比例top位置 57 | sliderTop = (ratioTop-scaleSliderHeight/2); //滑块的top位置 58 | sliderTop = sliderTop<0?0:(sliderTop>=130?120:sliderTop); //ps: 比例尺图片有阴影,所以补充运算 59 | var position = scaleBarBackgroundPositionX+"px "+(scaleBarBackgroundPositionY-ratioTop)+"px"; 60 | var slider = document.querySelector("."+slider); 61 | slider.style.top=sliderTop+"px"; 62 | var ruler_current = document.querySelector("."+ruler_current); 63 | ruler_current.style.height=ratioHeight+"px"; 64 | ruler_current.style.top=ratioTop+"px"; 65 | ruler_current.style.backgroundPosition=position; 66 | //配置的回调 67 | if( self.opt.scale ){ 68 | var n = new Number(self.scale).toFixed(1)*1; 69 | //只有值发生改变才会触发回调 70 | if( n != self.prevScale ){ 71 | //这里设定放大,缩小的值域 72 | self.opt.scale(self.prevScale,n); 73 | } 74 | self.prevScale = n; 75 | } 76 | }; 77 | //上下左右的hover监听(兼职监听keydown) 78 | function selectedBtn(e){ 79 | if( e.keyCode ){ //为键盘 80 | var direct = e.keyCode; 81 | if( direct == 37 || direct == 38 || direct==39 || direct == 40){ 82 | //配置的回调 83 | if( self.opt.steerwheel ){ 84 | self.opt.steerwheel(direct); 85 | } 86 | } 87 | }else{ //为mouseenter 88 | var direct = parseInt(e.target.getAttribute("data-direct")); 89 | } 90 | self.setSteerWheelClass("steer_"+direct); 91 | } 92 | function selectedClickBtn(e){ 93 | //配置的回调 94 | var direct = parseInt(e.target.getAttribute("data-direct")); 95 | if( self.opt.steerwheel ){ 96 | self.opt.steerwheel(direct); 97 | } 98 | } 99 | function cancelSelectedBtn(e){ 100 | self.setSteerWheelClass("steer_default"); 101 | } 102 | //滑块的滑轮监听(向上是放大,向下是缩小) 103 | function scrollSlider(e){ 104 | var num = self.scale; 105 | if(e.wheelDelta){ 106 | num = e.wheelDelta>0?num+0.1:num-0.1; //ie,chrome向上滚 > 0 107 | }else if(e.detail){ 108 | num = e.detail>0?num-0.1:num+0.1; //firefox向下滚 > 0 109 | } 110 | self.setScale(num); 111 | } 112 | //放大缩小的点击事件 113 | function zoomBtn(e){ 114 | var type = e.target.getAttribute("data-type"); 115 | if( type=="out" ){ 116 | self.scale=self.scale+0.1; 117 | }else if( type=="in" ){ 118 | self.scale=self.scale-0.1; 119 | } 120 | self.setScale(self.scale); 121 | } 122 | //比例尺滑块的拖拽监听 123 | function enableDragDrapSlider(e){ 124 | var slider = e.target.getAttribute("class"); 125 | if( slider == self.scale_slider ){ 126 | e.target.setAttribute("data-drag","true"); 127 | } 128 | } 129 | function runDragDrapSlider(e){ 130 | var console_panel = document.querySelector("."+self.console_panel), 131 | slider = document.querySelector("."+self.scale_slider); 132 | if( eval( slider.getAttribute("data-drag") ) ){ 133 | var offsetTop = console_panel.offsetTop+steerwheelHeight+zoomBtnHeight; //预设变量 134 | if( offsetTop<=e.pageY && e.pageY <=offsetTop+scaleBarHeight ){ 135 | var num = ( scaleBarHeight-(e.pageY-offsetTop) )/scaleBarHeight; 136 | //console.log(b); 137 | self.setScale(num); 138 | } 139 | } 140 | } 141 | function disableDragDrapSlider(e){ 142 | var slider = document.querySelector("."+self.scale_slider); 143 | slider.setAttribute("data-drag","false"); 144 | } 145 | 146 | //初始化监听 147 | this.initEvent = function(){ 148 | //上下左右的hover监听(click) 149 | var steerBtnArray = document.querySelectorAll("."+self.steer_btn); 150 | if( steerBtnArray ){ 151 | for(var i=0; i'+ 233 | '
'+ 234 | '
'+ 235 | '
'+ 236 | '
'+ 237 | '
'+ 238 | '
'+ 239 | ''+ 240 | '
'+ 241 | '
'+ 242 | '
'+ 243 | '
'+ 244 | '
'+ 245 | '
'+ 246 | '
'+ 247 | '
'+ 248 | '
'; 249 | return console_panel; 250 | }; 251 | } -------------------------------------------------------------------------------- /src/ctopo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * canvas版topo图 3 | * 作者:田明 4 | * github: https://github.com/tm-roamer/ctopo 5 | */ 6 | function ctopo(opt){ 7 | //状态机常量 8 | const STATE_IMAGE_LOAD=10, //加载图片 9 | STATE_INIT_LOAD=20, //正在初始化 10 | STATE_INIT_OVER=30; //初始化完成 11 | //默认配置对象 12 | var defaultOpt = { 13 | id:"", //说明: canvas标签的id, 写法: canvas , #canvas 14 | width:"auto", //说明: canvas的宽度, 写法: 500,500px,50%,auto,默认auto 15 | height:"auto", //说明: canvas的高度, 写法: 500,500px,50%,auto,默认auto 16 | isOnAnimateBall:false, //说明: 是否启动连线的动画球 写法: true,false, 默认:false 17 | isShowConsolePanel:true, //说明: 是否显示控制台, 写法: true,false, 默认true 18 | isHoverNodeLight:true, //说明: 是否悬停节点高亮, 写法: true,false, 默认true 19 | isShowNodeLabel:true, //说明: 是否显示节点文字, 写法: true,false, 默认true 20 | isShowNodeTooltip:false, //说明: 是否显示节点提示框, 写法: true,false, 默认false 21 | isShowEdgeLabel:false, //说明: 是否显示连线文字, 写法: true,false, 默认false 22 | isShowEdgeTooltip:false, //说明: 是否显示连线提示框, 写法: true,false, 默认false 23 | isShowEdgeArrow:false, //说明: 是否显示连线箭头, 写法: true,false, 默认false 24 | style:{ //说明: 全局样式 25 | global:{ 26 | backgroundColor:"#ffffff", //说明: 支持fillstyle所有原生写法, 例: rgba(255,255,255,1),默认#ffffff 27 | backgroundImage:null, //说明: 背景网格线, 默认为null 28 | backgourndImageOpacity:0.3, //说明: 背景网格线透明度, 配置了backgroundImage此字段才有效, 默认0.3 29 | //备注: backgroundColor灰,白,0.5美观;backgroundColor黑色,蓝色,0.2美观 30 | tooltipBackgroundColor:"rgba(0, 0, 0, 0.7)", //说明: 悬停提示的背景色样式,默认rgba(0, 0, 0, 0.7) 31 | tooltipColor:"rgb(255, 255, 255)" //说明: 悬停提示的文字样式,默认rgb(255, 255, 255) 32 | }, 33 | node:{ 34 | color:"#00adee", //说明: 节点颜色, 支持fillstyle所有原生写法, 优先级低于节点自带属性, 默认#00adee 35 | size:20, //说明: 节点直径, 优先级低于节点自带属性, 默认20px, 36 | textColor:"#878787", //说明: 节点Label颜色, 优先级低于节点自带属性, 默认#878787 37 | textSize:10 //说明: 节点Label字体大小, 优先级低于节点自带属性, 默认10px 38 | }, 39 | edge:{ 40 | color:"#c2c2c2", //说明: 连线颜色, 支持fillstyle所有原生写法, 优先级低于节点自带属性, 默认#c2c2c2 41 | size:1, //说明: 连线宽度, 优先级低于节点自带属性, 默认1px 42 | textColor:"#878787", //说明: 节点Label颜色, 优先级低于节点自带属性, 默认#878787 43 | textSize:10 //说明: 节点Label字体大小, 优先级低于节点自带属性, 默认10px 44 | } 45 | }, 46 | layout:{ 47 | name:"force", //说明: 布局方式,支持force力导向和preset预设, 默认force 48 | param:{ 49 | isScale : false, //说明: 默认第一次应用布局,是否自适应屏幕宽高,等比例缩放,默认false 50 | isRandom : false, //说明: 默认初始位置是随机Random还是定位location,默认false 51 | initAreaW : 100, //说明: 初始分布是的初始宽,默认100px 52 | initAreaH : 56, //说明: 初始分布是的初始高,默认56px 53 | energy:0.5, //说明: 能量值范围0.3-1, 默认0.5 54 | iterations :150, //说明: 力导向的迭代次数,默认150 55 | ejectFactor : 2, //说明: 默认斥力常量,默认2 56 | ejectRange : 250, //说明: 最大斥力范围,超过的不计算节点间斥力,默认2 57 | ejectFadeRange : 30, //说明: 节点簇的减弱范围,此范围内ejectFactor-1,默认30 58 | condenseFactor : 1, //说明: 默认引力常量,默认1 59 | maxtx : 3, //说明: 每次迭代的x方向最大移动距离,默认3 60 | maxty : 1.68 //说明: 每次迭代的y方向最大移动距离,默认1.68 61 | } 62 | }, 63 | data:{ //说明: 数据格式 64 | /* 65 | nodes:[ 66 | { 67 | id:"节点id", //说明: 必填项, 节点id, 必须唯一 68 | x:0, //说明: 节点x坐标, 69 | y:0, //说明: 节点y坐标, 70 | label:"显示标签", //说明: 显示标签, 默认null 71 | tooltip:"悬停文字", //说明: 悬停文字, 默认null 72 | color:"#00adee", //说明: 节点颜色, 支持fillstyle所有原生写法, 优先级高于全局样式, 不配置默认等于全局样式 73 | size:20, //说明: 节点直径, 优先级高于全局样式, 不配置默认等于全局样式 74 | textColor:"#878787", //说明: 节点Label颜色, 优先级高于全局样式, 不配置默认等于全局样式 75 | textSize:10 //说明: 节点Label字体大小, 优先级高于全局样式, 不配置默认等于全局样式 76 | //保留字段 //说明: 保留字段不可使用 77 | // originalColor=color,保存初始颜色,方便颜色变换 78 | // dispx,dispy,布局运算时的偏移量 79 | //支持自定义字段 //说明: 80 | // (1)不支持函数形式的自定义字段,基本类型,对象,数组都行 81 | // (2)不可以和保留字段重名 82 | customField1:"fieldl", 83 | customField2:["field2_1","field2_2"], 84 | customField3:{field3_1:"field3_1",field3_2:"field3_2"} 85 | } 86 | ], 87 | edges:[ 88 | { 89 | source:"开始节点id", //说明: 必填项, 开始节点id 90 | target:"结束节点id" //说明: 必填项, 结束节点id 91 | label:"显示标签", //说明: 显示标签, 默认null 92 | tooltip:"悬停文字", //说明: 悬停文字, 默认null 93 | color:"#c2c2c2", //说明: 连线颜色, 支持fillstyle所有原生写法, 优先级高于全局样式, 不配置默认等于全局样式 94 | size:1 //说明: 连线宽度, 优先级高于全局样式, 不配置默认等于全局样式 95 | textColor:"#878787", //说明: 节点Label颜色, 优先级高于全局样式, 不配置默认等于全局样式 96 | textSize:10 //说明: 节点Label字体大小, 优先级高于全局样式, 不配置默认等于全局样式 97 | //保留字段 //说明: 保留字段不可使用 98 | // originalColor=color,保存初始颜色,方便颜色变换 99 | // sourceIndex,targetIndex=开始和结束节点在nodes数组的索引值 100 | //支持自定义字段 //说明: 101 | // (1)不支持函数形式的自定义字段,,基本类型,对象,数组都行 102 | // (2)不可以和保留字段重名 103 | customField1:"fieldl", 104 | customField2:["field2_1","field2_2"], 105 | customField3:{field3_1:"field3_1",field3_2:"field3_2"} 106 | } 107 | ] 108 | */ 109 | }, 110 | event:{ //说明: 监听回调 111 | steerwheel:null, //说明: 上下左右的平移回调 112 | scale:null, //说明: 放大缩小的回调 113 | clickNode:null, //说明: 点击节点的回调 114 | hoverNode:null, //说明: 悬停节点的回调 115 | leaveNode:null, //说明: 离开节点的回调 116 | clickEdge:null, //说明: 点击连线的回调 117 | hoverEdge:null, //说明: 悬停连线的回调 118 | leaveEdge:null //说明: 离开连线的回调 119 | } 120 | }, 121 | //topo对象 122 | tp = { 123 | version:"v1.0.0", 124 | /** 125 | * 属性合并 126 | */ 127 | extendMerge:function(){ 128 | var res={}; 129 | for(var i=0; i 全局样式 314 | node.originalColor = node.color; 315 | node.x=node.x ? node.x : 0; 316 | node.y=node.y ? node.y : 0; 317 | node.label = node.label ? node.label : null; 318 | node.tooltip=node.tooltip ? node.tooltip : null; 319 | return node; 320 | } 321 | 322 | /** 323 | * 设置单个连线的字段的初始工作(私有方法) 324 | */ 325 | function setEdge(edge,edgeStyle){ 326 | edge.size = edge.size ? edge.size : edgeStyle.size; 327 | edge.color = edge.color? edge.color: edgeStyle.color; //edge对象样式 > 全局样式 328 | edge.textSize = edge.textSize ? edge.textSize : edgeStyle.textSize; 329 | edge.textColor = edge.textColor? edge.textColor: edgeStyle.textColor; 330 | edge.originalColor = edge.color; 331 | edge.sourceIndex = 0; 332 | edge.targetIndex = 0; 333 | edge.label = edge.label ? edge.label : null; 334 | edge.tooltip = edge.tooltip ? edge.tooltip : null; 335 | return edge; 336 | } 337 | 338 | /** 339 | * 初始化对象(私有方法) 340 | */ 341 | function initObject(){ 342 | ConPanel.prototype= new ConsolePanel();//初始化控制台对象 343 | conPanel = new ConPanel(); 344 | tooltip = new Tooltip(); //悬停提示框对象 345 | utils = new Utils(); //初始化工具对象 346 | layout = new Layout(); //初始化布局对象 347 | event = new Event(); //初始化监听对象 348 | render = new Render(); //初始化绘制对象 349 | animate = new Animate(); //初始化动画对象 350 | api = new API(); //初始化API接口 351 | tp.extendCopy(tp,api); //属性copy 352 | } 353 | 354 | //控制台对象(私有对象)------------------------------------------------ 355 | function ConPanel(){ 356 | //不存在的时候才添加 357 | var console_panel = document.querySelector("."+this.console_panel); 358 | if( !console_panel ){ 359 | document.body.insertBefore(this.getDom(),document.body.firstChild); //插入html 360 | } 361 | this.setOption({steerwheel:steerwheelCallBack,scale:scaleCallBack}); 362 | this.initEvent(); //加入监听 363 | if( tp.option.isShowConsolePanel ){ 364 | this.show(); //显示 365 | }else{ 366 | this.hide(); //隐藏 367 | //this.removeEvent(); //移除监听 368 | } 369 | //上下左右平移的回调 370 | function steerwheelCallBack(keyCode){ 371 | animate.destory(); 372 | //逻辑处理 373 | utils.moveSteerWheel(tp.nodes,keyCode); 374 | //初始完成后才进行绘制 375 | if( appState == STATE_INIT_OVER ){ 376 | render.draw(); 377 | animate.init(tp.nodes,tp.edges); 378 | } 379 | //设置回调 380 | if( tp.option.event.steerwheel ){ 381 | tp.option.event.steerwheel(keyCode); 382 | } 383 | } 384 | //放大缩小的回调 385 | function scaleCallBack(prevScale,scale){ 386 | animate.destory(); 387 | //逻辑处理 388 | utils.inOutScale(tp.nodes,tp.canvas.width,tp.canvas.height,prevScale,scale); 389 | //初始完成后才进行绘制 390 | if( appState == STATE_INIT_OVER ){ 391 | render.draw(); 392 | animate.init(tp.nodes,tp.edges); 393 | } 394 | //设置回调 395 | if( tp.option.event.scale ){ 396 | tp.option.event.scale(prevScale,scale); 397 | } 398 | } 399 | } 400 | //悬停提示框对象(私有对象)------------------------------------------------ 401 | function Tooltip(){ 402 | var name="ctopo_tooltip"; 403 | //不存在的时候才添加 404 | var tip = document.querySelector("."+name); 405 | if( !tip ){ 406 | document.body.insertBefore(getDom(),document.body.firstChild); //插入html 407 | } 408 | this.chooseDisplay = function(node,edge,ex,ey){ 409 | if( tp.option.isShowNodeTooltip ){ 410 | if( node ){ 411 | if( node.tooltip ){ 412 | show(node,ex,ey); 413 | return; //因为node悬停优先级高于edge 414 | } 415 | }else{ 416 | hide(); 417 | } 418 | } 419 | if( tp.option.isShowEdgeTooltip ){ 420 | if( edge ){ 421 | if( edge.tooltip ){ 422 | show(edge,ex,ey); 423 | } 424 | }else{ 425 | hide(); 426 | } 427 | } 428 | } 429 | this.remove=function(){ 430 | var tip = document.querySelector("."+name); 431 | document.body.removeChild(tip); 432 | }; 433 | function getDom(){ 434 | var tip = document.createElement("div"); 435 | tip.setAttribute("class",name); 436 | tip.style.cssText='position: absolute;'+ 437 | 'left: 0px;'+ 438 | 'top: 0px;'+ 439 | 'background-color: '+tp.option.style.global.tooltipBackgroundColor+'; '+ 440 | 'color: '+tp.option.style.global.tooltipColor+'; '+ 441 | 'visibility: hidden; '+ 442 | 'border-radius: 4px; '+ 443 | 'white-space: nowrap; transition: left 0.4s ease 0s, top 0.4s ease 0s; '+ 444 | 'text-decoration: none; '+ 445 | 'font-family: Arial,Verdana,sans-serif; '+ 446 | 'font-size: 12px; '+ 447 | 'line-height: 18px; '+ 448 | 'font-style: normal; '+ 449 | 'font-weight: normal;'+ 450 | 'padding: 5px;'; 451 | return tip; 452 | } 453 | function show(element,ex,ey){ 454 | var tip = document.querySelector("."+name); 455 | var coord = computePosition(element,ex,ey); 456 | tip.style.top=coord.top+"px"; 457 | tip.style.left=coord.left+"px"; 458 | tip.innerHTML=element.tooltip; 459 | tip.style.visibility="visible"; 460 | } 461 | function hide(){ 462 | var tip = document.querySelector("."+name); 463 | tip.style.visibility="hidden"; 464 | } 465 | function computePosition(element,ex,ey){ 466 | var coord={}, 467 | textH=28, 468 | textW=computeTextWidth(element.tooltip)+10, //+pading 469 | canvasW=tp.canvas.width, 470 | canvasH=tp.canvas.height; 471 | //边界判断 472 | coord.top = ey <= textH/2 ? 0 : ( ey>=canvasH-textH/2 ? canvasH-textH/2 : ey-textH/2); 473 | coord.left = ex >= canvasW-element.size-textW ? (ex-element.size/2-textW) : ex+element.size/2; 474 | return coord; 475 | } 476 | function computeTextWidth(text){ 477 | return tp.context.measureText(text).width; //文字宽 478 | } 479 | } 480 | //工具对象(私有对象)----------------------------------------------- 481 | function Utils(){ 482 | this.relationEdges = []; 483 | this.relationNodes = []; 484 | this.notRelationNodes = []; 485 | 486 | //函数节流 487 | this.throttle = function(method,context,time){ 488 | var arg = arguments; 489 | clearTimeout(method.tId); 490 | method.tId=setTimeout(function(){ 491 | method.call(context,arg[3],arg[4]); 492 | },time); 493 | } 494 | 495 | //节点的碰撞检测 ff,chrome:5000节点1ms 496 | this.collideNode=function(nodes,ex,ey){ 497 | var obj = null; 498 | for(var i=0; i= 1 ){ 696 | return bool; 697 | } 698 | for (var i = 0; i < nodes.length; i++) { 699 | var node = nodes[i]; 700 | if( node.x <=0 || node.x >= canvasW || node.y <=0 || node.y >= canvasH ){ 701 | bool = true; 702 | break; 703 | } 704 | } 705 | return bool; 706 | } 707 | /** 708 | * 计算箭头平移位置 709 | */ 710 | this.computeArrowTranslate = function (dx,dy,radian,nodeE){ 711 | //计算偏移 712 | var ox = 0, 713 | oy = 0, 714 | arrawW=6, 715 | arrawHalfW=arrawW/2, 716 | x = nodeE.x, 717 | y = nodeE.y, 718 | radius = nodeE.size/2; 719 | if( dx == 0 ){ 720 | y = dy > 0 ? y-radius-arrawHalfW : y+radius+arrawHalfW ; 721 | }else if( dy == 0 ){ 722 | x = dx > 0 ? x-radius-arrawHalfW : x+radius+arrawHalfW ; 723 | }else{ 724 | ox = Math.ceil( (radius+arrawHalfW)*Math.cos( Math.abs(radian) ) ); 725 | oy = Math.ceil( (radius+arrawHalfW)*Math.sin( Math.abs(radian) ) ); 726 | x = dx > 0 ? x-ox : x+ox ; 727 | y = dy > 0 ? y-oy : y+oy ; 728 | } 729 | return {x:x,y:y}; 730 | } 731 | /** 732 | * 计算箭头旋转角度 733 | */ 734 | this.computeArrowRotate = function (dx,dy,angle){ 735 | //第一步,取得夹角,x轴正方向为0度的顺时针0-360范围 736 | if( dx==0 || dy==0 ){ 737 | if( dx < 0 ){ 738 | angle = 180; 739 | } 740 | if( dy < 0 ){ 741 | angle = 270; 742 | } 743 | }else{ 744 | if( dx > 0 && dy > 0){ //4 745 | //angle = angle; 746 | }else if( dx > 0 && dy < 0 ){ //1 747 | angle = 360 - Math.abs(angle); 748 | }else if( dx < 0 && dy > 0 ){ //3 749 | angle = 180 - Math.abs(angle); 750 | }else if( dx < 0 && dy < 0 ){ //2 751 | angle = 180 + Math.abs(angle); 752 | } 753 | } 754 | //第二步,转换成context.rotate适用的的y轴正方向为0度的0-360范围 755 | angle = angle+90 >= 360 ? (angle+90)%360 : angle+90; 756 | //第三步,角度变弧度 757 | return angle*Math.PI/180; 758 | } 759 | } 760 | //布局对象(私有对象)------------------------------------------------ 761 | function Layout(){ 762 | this.run=function(layout){ 763 | try{ 764 | utils.createNodeIndex(tp.nodes,tp.edges); //(优化)建立索引机制,方便用线查点 765 | if( layout.name === "force" ){ 766 | this.force(layout.param); 767 | } 768 | }catch(e){ 769 | throw new Error("ctopo layout error"); 770 | } 771 | } 772 | this.force=function(param){ 773 | var nodes = tp.nodes, 774 | edges = tp.edges, 775 | canvasW = tp.canvas.width, 776 | canvasH = tp.canvas.height, 777 | canvasArea = canvasW*canvasH, //画布的面积 778 | k = Math.sqrt( canvasArea / nodes.length )*param.energy, //求出每个节点的能量 779 | isScale = param.isScale, //默认第一次应用布局,是否自适应屏幕宽高,等比例缩放 780 | isRandom = param.isRandom, //默认初始位置是随机Random还是定位location 781 | initAreaW = param.initAreaW, //随机分布是的初始宽 782 | initAreaH = param.initAreaH, //随机分布是的初始高 783 | iterations = param.iterations, //力导向的迭代次数 784 | ejectFactor = param.ejectFactor, //默认斥力常量 785 | ejectRange = param.ejectRange, //最大斥力范围,超过的不计算节点间斥力 786 | ejectFadeRange = param.ejectFadeRange, //节点簇的减弱范围,此范围内斥力-1 787 | condenseFactor = param.condenseFactor, //默认引力常量 788 | maxtx = param.maxtx, //每次迭代的x方向最大移动距离 789 | maxty = param.maxty; //每次迭代的y方向最大移动距离 790 | 791 | //随机初始位置 or 定位摆放 792 | isRandom ? randomCoord(nodes) : locationCoord(nodes); 793 | //反复迭代 794 | repeatLayout(nodes,edges); 795 | 796 | //检测屏幕是否需要缩放 797 | if( isScale ){ 798 | while( utils.testIsScale(nodes,canvasW,canvasH,conPanel.scale) ){ 799 | //(优化)自动缩放比例适应屏幕 800 | utils.setZoom(conPanel.scale-0.1); 801 | } 802 | } 803 | //1. 随机分布初始节点位置 804 | function randomCoord(nodes){ 805 | var startX, startY; 806 | for (var i=0;i b ? 1 : ( a < b ? -1 : 0 ) }); 820 | for (var i=0;i 0 && diff < ejectRange ) { 848 | //离得近的节点,斥力减弱,形成簇 849 | eject =(diff < ejectFadeRange )?ejectFactor-1:ejectFactor; 850 | //f=g*m1*m2/r*r 库仑定律 851 | node.dispx = node.dispx + diffx / diff * k * k / diff * eject; 852 | node.dispy = node.dispy + diffy / diff * k * k / diff * eject; 853 | } 854 | } 855 | } 856 | //4. 计算每次迭代每条边的引力对两端节点所产生的单位位移(一般为负值) 857 | for (var a = 0; a < edges.length; a++) { 858 | var nodeS = nodes[ edges[a].sourceIndex ], 859 | nodeE = nodes[ edges[a].targetIndex ], 860 | diffx = nodeS.x - nodeE.x, 861 | diffy = nodeS.y - nodeE.y; 862 | diff = Math.sqrt(diffx * diffx + diffy * diffy); //勾股定理斜线距离 863 | //f=-g*d 胡克定律 864 | nodeS.dispx = nodeS.dispx - diffx * diff / k * condenseFactor; 865 | nodeS.dispy = nodeS.dispy - diffy * diff / k * condenseFactor; 866 | nodeE.dispx = nodeE.dispx + diffx * diff / k * condenseFactor; 867 | nodeE.dispy = nodeE.dispy + diffy * diff / k * condenseFactor; 868 | } 869 | //5. 重置每个节点的坐标set x,y 870 | for (var v = 0; v < nodes.length; v++) { 871 | var node = nodes[v], 872 | disppx = parseInt( Math.floor( node.dispx ) ), 873 | disppy = parseInt( Math.floor( node.dispy ) ); 874 | disppx = (disppx < -maxtx ? -maxtx : ( disppx > maxtx ? maxtx : disppx ) ); 875 | disppy = (disppy < -maxty ? -maxty : ( disppy > maxty ? maxty : disppy ) ); 876 | node.x = node.x + disppx; 877 | node.y = node.y + disppy; 878 | } 879 | return nodes; 880 | } 881 | } 882 | } 883 | //监听对象(私有对象)------------------------------------------------ 884 | function Event(){ 885 | var self = this; 886 | self.fps = Math.floor(1000/200), //约等于5毫秒 887 | self.fpsCount = 0; //计算触发帧率 888 | self.dragPrevX = 0; 889 | self.dragPrevY = 0; 890 | self.dragCurrentX = 0; 891 | self.dragCurrentY = 0; 892 | this.init=function(){ 893 | var canvas = tp.canvas; 894 | //监听拖拽 895 | canvas.addEventListener("mousedown",this.canvasMouseDown,false); //摁下 896 | canvas.addEventListener("mousemove",this.canvasMouseMove,false); //移动 897 | canvas.addEventListener("mouseup",this.canvasMouseUp,false); //抬起 898 | canvas.addEventListener("click",this.canvasClick,false); //点击 mouseup之后触发 899 | } 900 | this.canvasMouseDown = function (e){ 901 | //切换手型 902 | tp.canvas.style.cursor="pointer"; 903 | //启动拖拽 904 | self.isDragDrap = true; 905 | //判断是node还是canvas 906 | utils.collideNode(tp.nodes,e.pageX,e.pageY); 907 | //保存坐标 908 | self.dragPrevX = e.pageX; 909 | self.dragPrevY = e.pageY; 910 | self.dragCurrentX = e.pageX; 911 | self.dragCurrentY = e.pageY; 912 | } 913 | this.canvasMouseMove = function (e){ 914 | //ff:200节点 50ms, chrome:200节点 25ms 915 | if( self.fpsCount++ >= self.fps ){ 916 | //判断是否拖拽 917 | if( self.isDragDrap ){ 918 | animate.destory(); 919 | //保存坐标 920 | self.dragCurrentX = e.pageX; 921 | self.dragCurrentY = e.pageY; 922 | //计算位移 923 | var dx = self.dragCurrentX - self.dragPrevX; 924 | var dy = self.dragCurrentY - self.dragPrevY; 925 | //当前坐标变成上一次的坐标 926 | self.dragPrevX = self.dragCurrentX; 927 | self.dragPrevY = self.dragCurrentY; 928 | 929 | //判断mouseDown是节点还是屏幕 930 | if( self.collideNode ){ 931 | //修改节点坐标 932 | self.collideNode.x = self.collideNode.x + dx; 933 | self.collideNode.y = self.collideNode.y + dy; 934 | }else{ 935 | //nodes整体平移 936 | var nodes = tp.nodes; 937 | for(var i=0; i 全局样式 1104 | context.arc(node.x,node.y,parseInt(node.size/2),0,(Math.PI/180)*360,false); 1105 | context.fill(); 1106 | context.closePath(); 1107 | //绘制节点label 1108 | if( node.label && tp.option.isShowNodeLabel ){ 1109 | drawNodeLabel(node); 1110 | } 1111 | } 1112 | 1113 | function drawNodeLabel(node){ 1114 | var textWidth = context.measureText(node.label).width; //文字宽 1115 | context.fillStyle=node.textColor; 1116 | context.font=node.textSize+"px serif"; 1117 | context.fillText(node.label,node.x-(textWidth/2),node.y+node.size/2+node.textSize); 1118 | } 1119 | 1120 | function drawEdge(edge){ 1121 | var nodeS = tp.nodes[edge.sourceIndex]; 1122 | var nodeE = tp.nodes[edge.targetIndex]; 1123 | context.beginPath(); 1124 | context.strokeStyle=edge.color; 1125 | context.lineWidth=edge.size; 1126 | context.moveTo(nodeS.x,nodeS.y); 1127 | context.lineTo(nodeE.x,nodeE.y); 1128 | context.stroke(); 1129 | context.closePath(); 1130 | //绘制连线label 1131 | if( edge.label && tp.option.isShowEdgeLabel ){ 1132 | drawEdgeLabel(nodeS,nodeE,edge); 1133 | } 1134 | //绘制箭头 1135 | if( tp.option.isShowEdgeArrow ){ 1136 | drawArrow(nodeS,nodeE); 1137 | } 1138 | } 1139 | 1140 | function drawEdgeLabel(nodeS,nodeE,edge){ 1141 | var textWidth = context.measureText(edge.label).width, //文字宽 1142 | textX = nodeS.x + (nodeE.x-nodeS.x)/2 - textWidth/2 , 1143 | textY = nodeS.y + (nodeE.y-nodeS.y)/2 - textWidth/2 ; 1144 | context.fillStyle=edge.textColor; 1145 | context.font=edge.textSize+"px serif"; 1146 | context.fillText(edge.label,Math.abs(textX),Math.abs(textY)+edge.textSize ); 1147 | } 1148 | 1149 | /** 1150 | * 绘制箭头(6px*6px) 1151 | */ 1152 | function drawArrow(nodeS,nodeE){ 1153 | //计算箭头位置 1154 | var dx = nodeE.x - nodeS.x, 1155 | dy = nodeE.y - nodeS.y, 1156 | radian = Math.atan(dy/dx), 1157 | angle = radian *180 / Math.PI, 1158 | coord = utils.computeArrowTranslate(dx,dy,radian,nodeE), 1159 | angleRadian = utils.computeArrowRotate(dx,dy,angle); 1160 | 1161 | //将画布保存到栈中 1162 | context.save(); 1163 | context.setTransform(1,0,0,1,0,0); //恢复初始值 1164 | context.translate(coord.x,coord.y); //平移 1165 | context.rotate( angleRadian ); //旋转 1166 | context.beginPath(); 1167 | context.fillStyle=nodeE.color; 1168 | //定位到箭头中心点 1169 | context.moveTo(0,-3); 1170 | context.lineTo(3,3); 1171 | context.lineTo(-3,3); 1172 | context.lineTo(0,-3); 1173 | context.fill(); 1174 | context.closePath(); 1175 | context.restore(); 1176 | } 1177 | } 1178 | //动画对象(私有对象)------------------------------------------------ 1179 | function Animate(){ 1180 | var context = tp.context,//画布的上下文对象 1181 | speed = 1; //小球的速度 1182 | this.animateBalls =[]; //连线动画小球数组 1183 | this.init = function(nodes,edges){ 1184 | if( tp.option.isOnAnimateBall ){ 1185 | //初始化动画小球的各项参数 1186 | var nodeS,nodeE,edge,dx,dy,diff,moves,xuint,yuint; 1187 | this.animateBalls.splice(0,this.animateBalls.length); //干掉所有计算数据 1188 | for(var i=0; i 1 ? 1 : ( scale < 0 ? 0 : scale ); 1493 | scale = new Number(scale).toFixed(1)*1; 1494 | utils.setZoom(scale); 1495 | render.draw(); //绘制 1496 | } 1497 | return bool; 1498 | }else{ 1499 | return conPanel.scale; 1500 | } 1501 | } 1502 | } 1503 | //构建初始配置 1504 | tp.option = tp.extendMerge(defaultOpt,opt?opt:{}); 1505 | //初始化函数 1506 | init(); 1507 | return tp; 1508 | } --------------------------------------------------------------------------------