Posted on 2011-02-16 17:02
TWaver 閱讀(2734)
評論(3) 編輯 收藏
最近用戶有個比較“變態”的需求:從工具欄上將節點拖入拓撲圖中時,如果鼠標下面是Link,就將節點插入這條Link之間;而且鼠標在拖拽過程中,鼠標下面的link呈現凸起效果。
在Link之間插入節點好說,可以刪除這條Link再添加兩條Link,不過凸起效果就有點費勁了。這里用TWaver Flex的ShapeLink實現比較滿意的效果:

大概思路是:
1. 監聽network的DragEvent.DRAG_OVER事件,用network#getElementsByDisplayObject方法判斷鼠標下面是否有Link。如果有就將這個Link變成透明(link.setStyle(Styles.LINK_ALPHA, 0);),然后加入一條ShapeLink;如果沒有就將之前變成透明的Link還原,并刪除ShapeLink。具體代碼見updateMark以及removeMark方法:
1 private function updateMark(link:Link, data:Object, point:Point):void {
2 if(!network.elementBox.contains(markLink)){
3 markLink.fromNode = link.fromNode;
4 markLink.toNode = link.toNode;
5 markLink.setStyle(Styles.SHAPELINK_TYPE, Consts.SHAPELINK_TYPE_QUADTO);
6 markLink.setStyle(Styles.LINK_WIDTH, link.getStyle(Styles.LINK_WIDTH));
7 markLink.setStyle(Styles.LINK_COLOR, link.getStyle(Styles.LINK_COLOR));
8 markLink.setStyle(Styles.LINK_ALPHA, link.getStyle(Styles.LINK_ALPHA));
9
10 network.elementBox.add(markLink);
11 lastLink = link;
12 link.setStyle(Styles.LINK_ALPHA, 0);
13 }
14
15 var points:Collection = new Collection();
16
17 var fromCenter:Point = markLink.fromNode.centerLocation;
18 var toCenter:Point = markLink.toNode.centerLocation;
19 var radius:Number = Math.sqrt(data.width*data.width + data.height*data.height)/2;
20 var crossPoints:Object = getCrossPoints(fromCenter, toCenter, point, radius*2);
21 if (crossPoints){
22 if(fromCenter.x<toCenter.x){
23 points.addItem(crossPoints.p2);
24 points.addItem(crossPoints.p2);
25 }else{
26 points.addItem(crossPoints.p1);
27 points.addItem(crossPoints.p1);
28 }
29
30 var crossPoint:Point = new Point(crossPoints.p1.x + (crossPoints.p2.x-crossPoints.p1.x)/2,
31 crossPoints.p1.y + (crossPoints.p2.y-crossPoints.p1.y)/2);
32 var controlPoints:Object = getCrossPoints(crossPoint, point, point, radius*3);
33 if(controlPoints){
34 if(crossPoint.y >= point.y){
35 points.addItem(controlPoints.p2);
36 }else{
37 points.addItem(controlPoints.p1);
38 }
39 }else{
40 if(point.y>=fromCenter.y){
41 point.y = point.y - radius * 3;
42 }else{
43 point.y = point.y + radius * 3;
44 }
45 points.addItem(point);
46 }
47 if(fromCenter.x<toCenter.x){
48 points.addItem(crossPoints.p1);
49 points.addItem(crossPoints.p1);
50 }else{
51 points.addItem(crossPoints.p2);
52 points.addItem(crossPoints.p2);
53 }
54 }else{
55 points.addItem(fromCenter);
56 }
57 markLink.points = points;
58 }
59
60 private function removeMark(moving:Boolean):void {
61 if(network.elementBox.contains(markLink)){
62 var fromNode:Node = markLink.fromNode;
63 var toNode:Node = markLink.toNode;
64 network.elementBox.remove(markLink);
65 if(lastLink && moving){
66 lastLink.setStyle(Styles.LINK_ALPHA, markLink.getStyle(Styles.LINK_ALPHA));
67 lastLink = null;
68 }
69 }
70 }
71
2. 最關鍵的是如何確定ShapeLink的points。這里的核心是計算圓和直線的交點。具體代碼見getCrossPoints方法:
1 private function getCrossPoints(p1:Point, p2:Point, circleCenter:Point, radius:Number):Object{
2 var line_p1_x:Number = p1.x;
3 var line_p1_y:Number = p1.y;
4 var line_p2_x:Number = p2.x;
5 var line_p2_y:Number = p2.y;
6 var circle_center_x:Number = circleCenter.x;
7 var circle_center_y:Number = circleCenter.y;
8 var circle_radius:Number = radius;
9 var line_k:Number =(line_p2_y-line_p1_y)/(line_p2_x-line_p1_x);
10 var line_b:Number =line_p1_y-line_k*line_p1_x;
11 var a:Number =1+line_k*line_k;
12 var b:Number =-2*circle_center_x+2*line_k*line_b-2*line_k*circle_center_y;
13 var c:Number =circle_center_x*circle_center_x+(line_b-circle_center_y)*(line_b-circle_center_y)-circle_radius*circle_radius;
14 var delta:Number =b*b-4*a*c;
15 var x1:Number =(-b+Math.sqrt(delta))/(2*a);
16 var x2:Number =(-b-Math.sqrt(delta))/(2*a);
17 var y1:Number =line_k*x1+line_b;
18 var y2:Number =line_k*x2+line_b;
19
20 if(delta>=0){
21 return {p1: new Point(x1, y1), p2: new Point(x2, y2)};
22 }else{
23 return null;
24 }
25 }
26
3. 在DragEvent.DRAG_DROP事件里,刪除ShapeLink并創建兩條Link。
源碼下載