水浒揭秘 贞芸劫:FLEX WEB流程设计器线条、箭头的绘制

来源:百度文库 编辑:偶看新闻 时间:2024/05/01 00:20:33

流程设计器里面,最复杂的其实不是拖来拖去的图片,而是线条的绘制包括锚点、箭头,如果把线条绘制好了,那设计器就没什么难度了。

绘制线条会涉及到一些数学知识,主要是三角函数、极坐标等,如果不记得了,赶紧恶补一下吧,这个是必须的。

线条绘制又分多种场景:

1 在一个节点和鼠标所在坐标之间绘制(寻找目标节点过程),这个线条要跟随鼠标的移动而不断重绘。线条的起点为节点中心点坐标与鼠标位置的连线再与节点边缘的交点(有点抽象,等会看图就明白)

可能很多人都以为是在拖动线条,其实这是一个假象,当鼠标移动时,会先擦除线条,然后重新绘制一条节点和鼠标当前位置的连线,当鼠标移动一段距离后,实际上重绘了无数次,这样线条的“拖动”就有连贯性,如果只在鼠标移动结束之后再绘制一条也可以,这样只需要重绘一次,但视觉上的效果要查很多。

2 在两个节点之间绘制,起点和终点坐标分别为两个节点中心点坐标之间的连线分别与节点边缘的交点。

3 拖动锚点(一条线条被分成几段时,子线条之间的交点)绘制,和第1点有些类似,稍微复杂点。

下面举第1种场景中节点在鼠标左上方的例子进行说明:



 上图中x的坐标即为线条的起点

X坐标的计算过程:
X横坐标X.x3=O.x+len
根据相似三角形,存在关系 (x2-x1)/(len/2)=(y2-y1)/H
H=(len/2)(y2-y1)/(x2-x1)
X点的纵坐标X.y3=O.y+len/2+H

计算X坐标的代码如下(考虑了各种场景):

 

Actionscript代码  
  1. /**   
  2.          * 获取起始点与图片边框的交点坐标   
  3.          * 需按矩形对角线划分四个区域(此处为正方形,每90度为一个边界)   
  4.          * acrossNode 参照节点对象(为上图中的节点对象)   
  5.          */   
  6.         public static function getLinkPoint(fromPoint:Point,targetPoint:Point,acrossNode:BaseNode):Point   
  7.         {   
  8.             var angle:Number=getAngel(fromPoint,targetPoint);   
  9.             /**计算交点与中心点的垂直和水平距离*/   
  10.             var distanceX:Number=Math.abs((targetPoint.x-fromPoint.x)*(acrossNode.width/2)/(targetPoint.y-fromPoint.y));   
  11.             var distanceY:Number=Math.abs((targetPoint.y-fromPoint.y)*(acrossNode.width/2)/(targetPoint.x-fromPoint.x));   
  12.                
  13.             if(targetPoint.x
  14.             {   
  15.                 distanceX=-distanceX;   
  16.             }   
  17.             if(targetPoint.y
  18.             {   
  19.                 distanceY=-distanceY;   
  20.             }   
  21.             /**最终xy坐标*/   
  22.             var x:Number=0;   
  23.             var y:Number=0;   
  24.             if(angle>=45&&angle<135)   
  25.             {   
  26.                 x=fromPoint.x+distanceX;   
  27.                 y=acrossNode.y;   
  28.             }   
  29.             else if(angle>=135&&angle<225)   
  30.             {   
  31.                 x=acrossNode.x;   
  32.                 y=fromPoint.y+distanceY;   
  33.             }   
  34.             else if(angle>=225&&angle<315)   
  35.             {   
  36.                 x=fromPoint.x+distanceX;   
  37.                 y=fromPoint.y+acrossNode.height/2;   
  38.             }   
  39.             else   
  40.             {   
  41.                 x=fromPoint.x+acrossNode.width/2;   
  42.                 y=fromPoint.y+distanceY;   
  43.             }   
  44.             return new Point(x,y);   
  45.         }   
  46.            
  47.         /**获取两点夹角的角度*/   
  48.         private static function getAngel(fromPoint:Point,targetPoint:Point):Number   
  49.         {   
  50.             /**为了与三角坐标一致,y坐标的值要反过来*/   
  51.                
  52.             /**通过反正切计算弧度*/   
  53.             var radian:Number=Math.abs(Math.atan((targetPoint.x-fromPoint.x)/(targetPoint.y-fromPoint.y)));   
  54.             /**计算角度*/   
  55.             var angle:Number=radian*180/Math.PI;   
  56.             if((targetPoint.x>=fromPoint.x)&&(targetPoint.y<=fromPoint.y))//0~90区域    
  57.             {   
  58.                 angle=90-angle;   
  59.             }   
  60.             else if((targetPoint.x<=fromPoint.x)&&(targetPoint.y<=fromPoint.y))//90~180区域   
  61.             {   
  62.                 angle=90+angle;   
  63.             }   
  64.             else if((targetPoint.x<=fromPoint.x)&&(targetPoint.y>=fromPoint.y))//180~270区域   
  65.             {   
  66.                 angle=270-angle;   
  67.             }   
  68.             else if((targetPoint.x>=fromPoint.x)&&(targetPoint.y>=fromPoint.y))//270~360区域   
  69.             {   
  70.                 angle=270+angle;   
  71.             }   
  72.             return angle;   
  73.         }  

 

 

具体绘制线条还有一个技巧,线条绘制出来不仅是摆看的,还要加事件,可以被选取,太细了选择太困难,太粗了又太难看,一个很简单的办法就是绘制两条线,一条1个像素的实线,一条比较粗的透明线,透明线实际上是为了扩大选择区域。

 

Actionscript代码  
  1. graphics.clear();   
  2. graphics.moveTo(fromPoint.x,fromPoint.y);   
  3. graphics.lineStyle(8,color,0,true,LineScaleMode.NORMAL,CapsStyle.NONE);   
  4. graphics.lineTo(targetPoint.x,targetPoint.y);   
  5.                
  6. graphics.moveTo(fromPoint.x,fromPoint.y);   
  7. graphics.lineStyle(DesignerConstances.LINE_THICKNESS,color);   
  8. graphics.lineTo(targetPoint.x,targetPoint.y);  

 

 

绘制箭头

为了简化可绘制等边三角形



 三角形被线条平分,先计算3个顶点的坐标,然后绘制3条线,最后填充三角形

平分后的弧度各为PI/6。
1)以下为A点坐标的计算过程:
正切值tan(a)=(y2-y1)/(x2-x1)
通过反正切得弧度a=atan(tan(a))
角AP2O的弧度θ为a+b=a+PI/6
H=len*Sin(θ)
W=len*Cos(θ)
A.x3=P2.x2-W,A.y3=P2.y2-H
2)同理,通过弧度c=PI/6-a可计算出B的坐标.

 

 

Actionscript代码  
  1. /**   
  2.          * 根据线条起始点绘制三角形   
  3.          */   
  4.         public function draw(ui:UIComponent,fromPoint:Point,toPoint:Point,color:uint):void   
  5.         {   
  6.             var vDistance:Number= toPoint.y-fromPoint.y;//起始点垂直距离   
  7.             var sDistance:Number=Point.distance(fromPoint,toPoint);//起始点直线距离   
  8.                
  9.             var sinValue:Number=vDistance/sDistance;//起始点间的夹角的sin值   
  10.                
  11.             /**两点间直线与水平线的角度(弧度)*/   
  12.             var radian:Number=Math.asin(sinValue);   
  13.             /**用于计算三角形顶点与目标点水平距离的夹角(弧度)*/   
  14.             var hRadian:Number=radian-Math.PI/6;   
  15.                
  16.             /**用于计算三角形顶点与目标点垂直距离的夹角(弧度)*/   
  17.             var vRadian:Number=radian+Math.PI/6;   
  18.             /**上顶点与目标点的垂直距离*/   
  19.             var topYDis:Number=8*Math.sin(vRadian);   
  20.             /**上顶点与目标点的水平距离*/   
  21.             var topXDis:Number=8*Math.cos(vRadian);   
  22.             /**下顶点与目标点的垂直距离*/   
  23.             var botYDis:Number=8*Math.sin(hRadian);   
  24.             /**下顶点与目标点的水平距离*/   
  25.             var botXDis:Number=8*Math.cos(hRadian);   
  26.                
  27.             /**计算三角形上下顶点坐标*/   
  28.             var topPointX:Number=toPoint.x-topXDis;   
  29.             var topPointY:Number=toPoint.y-topYDis;   
  30.                
  31.             var botPointX:Number=toPoint.x-botXDis;   
  32.             var botPointY:Number=toPoint.y-botYDis;   
  33.             if(toPoint.x
  34.             {   
  35.                 topPointX=toPoint.x+topXDis;   
  36.                 botPointX=toPoint.x+botXDis;   
  37.             }   
  38.   
  39.             ui.graphics.beginFill(color);   
  40.             ui.graphics.moveTo(topPointX,topPointY);   
  41.             ui.graphics.lineTo(toPoint.x,toPoint.y);   
  42.             ui.graphics.lineTo(botPointX,botPointY);   
  43.             ui.graphics.lineTo(topPointX,topPointY);   
  44.         }