先看看发光链路的运行效果:
在这个Demo中主要包含三个技术点,一是如何在选取一条链路时,让整条回路发光;二是如何绘制带有箭头方向的曲线link;三是如何设置链路的样式,让整体可控。
1.如何获取整条回路的所有link,并使之发光
以前做客户支持,也处理过类似的问题,当时的解决方法是通过获取当前的Link,然后通过不断的遍历,不断获取link的fromNode和toNode,然后再获取Node的Link,从而获取回路中所有的Link和Node。这样实现的缺点是要通过大量的遍历,实现起来比较繁琐,本文的处理方法是,在创建link的时候,设置一个Client属性,在选择回路的时候,直接读取这个Client属性,并遍历一次即可。创建回路代码如下:
1 |
function
createCircuit(nodes, linename, flag) { |
2 |
if (flag)
{ |
3 |
var
startNode = nodes[ 0 ]; |
4 |
var
stopNode = nodes[nodes.length - 1 ]; |
5 |
var
link = new CLink(stopNode,
startNode); |
6 |
link.setStyle( ‘link.type‘ , "extend.left" ); |
7 |
//
link.setName(linename); |
8 |
link.setClient( ‘linename‘ ,
linename); |
9 |
box.add(link); |
10 |
} |
11 |
for (var
i = 0 ;
i < nodes.length - 1 ;
i++) { |
12 |
var
fromNode = nodes[i]; |
13 |
var
toNode = nodes[i + 1 ]; |
14 |
var
link = new CLink(fromNode,
toNode); |
15 |
//
link.setName(linename); |
16 |
link.setClient( ‘linename‘ ,
linename); |
17 |
if (i
== 0 )
{ |
18 |
link.setStyle( ‘link.type‘ , "orthogonal.H.V" ); //orthogonal\ |
19 |
} else if (i
== 1 )
{ |
20 |
link.setStyle( ‘link.type‘ , "orthogonal.V.H" ); //orthogonal\ |
21 |
} else if (i
== 2 )
{ |
22 |
link.setStyle( ‘link.type‘ , "orthogonal.V.H" ); //orthogonal\ |
23 |
} |
24 |
//
link.setStyle(‘link.type‘, "orthogonal");//orthogonal\ |
25 |
box.add(link); |
26 |
} |
27 |
} |
2.自定义实现带有箭头的曲线link
这个主要考察的是canvas绘制能力了,核心代码如下:
1 |
cx
= cx - Math.cos(angle) * radius; |
2 |
cy
= cy - Math.sin(angle) * radius; |
3 |
ctx.lineWidth
= 4 ; |
4 |
ctx.beginPath(); |
5 |
ctx.moveTo(p1.x,
p1.y - h1 / 2 ); |
6 |
ctx.quadraticCurveTo(cx,
cy, p2.x, p2.y - h2 / 2 ); |
7 |
ctx.stroke(); |
8 |
ctx.closePath(); |
9 |
//draw
arrow |
10 |
this .drawArrow(ctx,
p2.x, p2.y - h2 / 5 * 3 ,
cx, cy+ 20 , 1 , 2 ,
Math.PI / 8 , 10 ); |
3.设置Link的样式
TWaver的Link支持很多样式,常用的类型可参考下图,本文主要监听mousemove事件,并在拖动Node的过程中不断计算Node之间的相对位置,从而判定Link的类型,并不断刷新。
核心代码如下:
1 |
function
refreshLinkType() { |
2 |
box.forEach(function
(element) { |
3 |
if (element instanceof twaver.Link)
{ |
4 |
var
fromNode = element.getFromNode(); |
5 |
var
toNode = element.getToNode(); |
6 |
var
nextLinks = toNode.getLinks(); |
7 |
var
nextNode; |
8 |
nextLinks.forEach(function
(element) { |
9 |
if (element.getToNode()
!== toNode) { |
10 |
nextNode
= element.getToNode(); |
11 |
} |
12 |
}); |
13 |
var
fromPoint = fromNode.getCenterLocation(); |
14 |
var
toPoint = toNode.getCenterLocation(); |
15 |
var
nextPoint; |
16 |
if (nextNode)
{ |
17 |
nextPoint
= nextNode.getCenterLocation(); |
18 |
} |
19 |
//compute
the relationship of location between fromNode and toNode |
20 |
if (fromPoint.x
< toPoint.x && fromPoint.y < toPoint.y) { |
21 |
element.setStyle( ‘link.type‘ , "orthogonal.V.H" ); |
22 |
} else if (fromPoint.x
< toPoint.x && fromPoint.y > toPoint.y) { |
23 |
element.setStyle( ‘link.type‘ , "orthogonal.V.H" ); |
24 |
} else if (fromPoint.x
> toPoint.x && fromPoint.y < toPoint.y) { |
25 |
element.setStyle( ‘link.type‘ , "orthogonal.V.H" ); |
26 |
} else if (fromPoint.x
> toPoint.x && fromPoint.y > toPoint.y) { |
27 |
element.setStyle( ‘link.type‘ , "orthogonal" ); |
28 |
} |
29 |
if (nextPoint)
{ |
30 |
if (toPoint.x
> fromPoint.x && toPoint.x > nextPoint.x) { |
31 |
if (toPoint.y
> fromPoint.y && toPoint.y < nextPoint.y) { |
32 |
element.setStyle( ‘link.type‘ , "orthogonal.H.V" ); |
33 |
} else { |
34 |
element.setStyle( ‘link.type‘ , "orthogonal.V.H" ); |
35 |
} |
36 |
} |
37 |
} |
38 |
39 |
} |
40 |
}); |
41 |
} |
原文地址:http://blog.csdn.net/twaver/article/details/39316099