先看看发光链路的运行效果:
在这个Demo中主要包含三个技术点,一是如何在选取一条链路时,让整条回路发光;二是如何绘制带有箭头方向的曲线link;三是如何设置链路的样式,让整体可控。
1.如何获取整条回路的所有link,并使之发光
以前做客户支持,也处理过类似的问题,当时的解决方法是通过获取当前的Link,然后通过不断的遍历,不断获取link的fromNode和toNode,然后再获取Node的Link,从而获取回路中所有的Link和Node。这样实现的缺点是要通过大量的遍历,实现起来比较繁琐,本文的处理方法是,在创建link的时候,设置一个Client属性,在选择回路的时候,直接读取这个Client属性,并遍历一次即可。创建回路代码如下:
1 |
function createCircuit(nodes, linename, 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" );
|
8 |
link.setClient( 'linename' , linename);
|
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);
|
16 |
link.setClient( 'linename' , linename);
|
18 |
link.setStyle( 'link.type' , "orthogonal.H.V" );
|
20 |
link.setStyle( 'link.type' , "orthogonal.V.H" );
|
22 |
link.setStyle( 'link.type' , "orthogonal.V.H" );
|
2.自定义实现带有箭头的曲线link
这个主要考察的是canvas绘制能力了,核心代码如下:
1 |
cx = cx - Math.cos(angle) * radius; |
2 |
cy = cy - Math.sin(angle) * radius;
|
5 |
ctx.moveTo(p1.x, p1.y - h1 / 2 );
|
6 |
ctx.quadraticCurveTo(cx, cy, p2.x, p2.y - h2 / 2 );
|
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();
|
8 |
nextLinks.forEach(function (element) {
|
9 |
if (element.getToNode() !== toNode) {
|
10 |
nextNode = element.getToNode();
|
13 |
var fromPoint = fromNode.getCenterLocation();
|
14 |
var toPoint = toNode.getCenterLocation();
|
17 |
nextPoint = nextNode.getCenterLocation();
|
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" );
|
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" );
|
34 |
element.setStyle( 'link.type' , "orthogonal.V.H" );
|