前提:
1. 节点具有方向,上/下/左/右 四个方向
2. 节点移动时,必须及时计算出新的方向,
先上效果图
package com.donkey.workflow.comp.line
{
import com.donkey.workflow.comp.Anchor;
import com.donkey.workflow.comp.OutlineForLine;
import com.donkey.workflow.event.AnchorDragEvent;
import com.donkey.workflow.event.NodeDragEvent;
import flash.display.Graphics;
import flash.geom.Point;
public class BrokenLine extends Line
{
private static const FIX_LENGTH:int = 20;
private var _sourceDirection:Number;
private var _targetDirection:Number;
private var _straight:int = 1;
public function BrokenLine()
{
}
override protected function createChildren():void
{
super.createChildren();
}
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
super.updateDisplayList(unscaledWidth, unscaledHeight);
var g:Graphics = graphics;
g.clear();
var backgroundColor:Number = selected ? getStyle("selectedColor") : getStyle("backgroundColor");
linePoints = [];
generatePoint(sourcePoint, sourceDirection, targetPoint, targetDirection);
for each (var line:LinePoints in linePoints)
{
// 画直线
g.lineStyle(2, backgroundColor);
g.moveTo(line.sourcePoint.x, line.sourcePoint.y);
g.lineTo(line.targetPoint.x, line.targetPoint.y);
}
var endLine:LinePoints = linePoints[linePoints.length - 1];
if(arrow && null != endLine)
{
// 画箭头
var radius:Number = 8.5;
var angle:int= GetAngle(endLine.sourcePoint.x, endLine.sourcePoint.y, endLine.targetPoint.x, endLine.targetPoint.y);
var centerX:int=endLine.targetPoint.x - radius * Math.cos(angle *(Math.PI/180)) ;
var centerY:int=endLine.targetPoint.y + radius * Math.sin(angle *(Math.PI/180)) ;
var topX:int=endLine.targetPoint.x;
var topY:int=endLine.targetPoint.y;
var leftX:int=centerX + radius * Math.cos((angle +120) *(Math.PI/180)) ;
var leftY:int=centerY - radius * Math.sin((angle +120) *(Math.PI/180)) ;
var rightX:int=centerX + radius * Math.cos((angle +240) *(Math.PI/180)) ;
var rightY:int=centerY - radius * Math.sin((angle +240) *(Math.PI/180)) ;
this.graphics.beginFill(backgroundColor, 1);
this.graphics.lineStyle(1,backgroundColor, 1);
this.graphics.moveTo(topX,topY);
this.graphics.lineTo(leftX,leftY);
this.graphics.lineTo(centerX,centerY);
this.graphics.lineTo(rightX,rightY);
this.graphics.lineTo(topX,topY);
this.graphics.endFill();
}
outLine.line = this;
}
private function GetAngle(startX:Number,startY:Number,endX:Number,endY:Number):int
{
var tmpx:int=endX - startX ;
var tmpy:int=startY -endY ;
var angle:int= Math.atan2(tmpy,tmpx)*(180/Math.PI);
return angle;
}
/**
* 生成节点
**/
private function generatePoint(source:Point, sourceD:int, target:Point, targetD:int):void
{
smoothPoint(source);
smoothPoint(target);
var startPoint:Point = offsetPoint(source, sourceD);
var line:LinePoints = new LinePoints();
line.sourcePoint = source;
line.targetPoint = startPoint;
linePoints.push(line);
var endPoint:Point = offsetPoint(target, targetD);
if (startPoint.y <= endPoint.y)
{
this.calculatePoint(startPoint, sourceD, endPoint, targetD);
}
else
{
this.calculatePoint(endPoint, targetD, startPoint, sourceD);
}
line = new LinePoints();
line.sourcePoint = endPoint;
line.targetPoint = target;
linePoints.push(line);
}
/**
* 去除误差
* @param source
*/
private function smoothPoint(source:Point):void
{
source.x = Math.round(source.x);
source.y = Math.round(source.y);
if(source.x % 2 == 1)
{
source.x = source.x + 1;
}
if(source.y % 2 == 1)
{
source.y = source.y + 1;
}
}
/**
* 生成开始/结束节点偏移
**/
private function offsetPoint(source:Point, sourceD:int):Point
{
var gap:Number;
var nextSourcePoint:Point = null;
if (Math.abs(sourceD) == 1)
{
gap = sourceD > 0 ? FIX_LENGTH : 0 - FIX_LENGTH;
nextSourcePoint = new Point(source.x + gap, source.y);
}
else if (Math.abs(sourceD) == 2)
{
gap = sourceD > 0 ? FIX_LENGTH : 0 - FIX_LENGTH;
nextSourcePoint = new Point(source.x , source.y + gap);
}
return nextSourcePoint;
}
/**
* 计算
**/
private function calculatePoint(source:Point, sourceD:int, target:Point, targetD:int):void
{
if (Math.abs(source.x - target.x) <= 1 && Math.abs(source.y - target.y) <= 1)
{
return;
}
var line:LinePoints = null;
var nextPoint:Point = findNextPoint(source, sourceD, target, targetD);
var nextPointDirection:int = 0;
if(nextPoint == null)
{
nextPoint = new Point(Math.round(source.x + target.x)/2, Math.round(source.y + target.y)/2 );
if(Math.abs(sourceD) == Math.abs(targetD))
{
if(Math.abs(sourceD) == 1)
{
nextPointDirection = source.y <= nextPoint.y ? 2 : -2;
}
else
{
nextPointDirection = source.x <= nextPoint.x ? 1 : -1;
}
}
else
{
if(Math.abs(sourceD) == 1)
{
nextPointDirection = source.y <= nextPoint.y ? -2 : 2;
}
else
{
nextPointDirection = source.x <= nextPoint.x ? -1 : 1;
}
}
calculatePoint(source, nextPointDirection, nextPoint, sourceD);
calculatePoint(nextPoint, 0 - sourceD, target, targetD);
}
else
{
// 加入
line = new LinePoints();
line.sourcePoint = source;
line.targetPoint = nextPoint;
linePoints.push(line);
line = new LinePoints();
line.sourcePoint = nextPoint;
line.targetPoint = target;
linePoints.push(line);
}
}
private function findNextPoint(source:Point, sourceD:int, target:Point, targetD:int):Point
{
var x:int = 0;
var y:int = 0;
if(Math.abs(sourceD) == 1)
{
if (sourceD > 0)
{
if (source.x <= target.x)
{
x = target.x;
y = source.y;
}
else if (source.x > target.x)
{
x = source.x;
y = target.y;
}
}
else
{
if (source.x <= target.x)
{
x = source.x;
y = target.y;
}
else if (source.x > target.x)
{
x = target.x;
y = source.y;
}
}
}
else
{
if (sourceD > 0)
{
if (source.y <= target.y)
{
x = source.x;
y = target.y;
}
else if (source.y > target.y)
{
x = target.x;
y = source.y;
}
}
else
{
if (source.y <= target.y)
{
x = target.x;
y = source.y;
}
else if (source.y > target.y)
{
x = source.x;
y = target.y;
}
}
}
var nextPoint:Point = new Point(x, y);
var directionS:int = calculateDirection(source, nextPoint, sourceD);
var directionT:int = calculateDirection(nextPoint, target, targetD);
var find:Boolean = false;
if ((Math.abs(directionS) != Math.abs(sourceD)) || directionS == sourceD)
{
//方向相同或者垂直
if ((Math.abs(directionT) != Math.abs(targetD)) || directionT == 0 - targetD)
{
find = true;
}
else
{
if(directionT == targetD)
{
if (Math.abs(targetD) == 1)
{
if ((nextPoint.x > target.x && targetD > 0) || (nextPoint.x < target.x && targetD < 0))
{
find = true;
}
}
}
}
}
if (find)
{
return nextPoint;
}
return null;
}
/**
* 计算两个坐标的方向
*/
private function calculateDirection(source:Point, target:Point, direction:int):int
{
if (source.y == target.y)
{
return source.x <= target.x ? 1 : -1;
}
else
{
return source.y <= target.y ? 2 : -2;
}
}
/**
* 根据两个节点之间的位置重新计算开始位置和结束位置
**/
/*override protected function changePoint():void
{
if (this.sourceDirection == 1)
{
this.sourcePoint.x = this.sourcePoint.x + sourceNode.width / 2;
}
if (this.sourceDirection == -1)
{
this.sourcePoint.x = this.sourcePoint.x - sourceNode.width / 2;
}
if (this.sourceDirection == 2)
{
this.sourcePoint.y = this.sourcePoint.y + sourceNode.height / 2;
}
if (this.sourceDirection == -2)
{
this.sourcePoint.y = this.sourcePoint.y - sourceNode.height / 2;
}
// 目标节点
if (this.targetDirection == 1)
{
this.targetPoint.x = this.targetPoint.x + targetNode.width / 2;
}
if (this.targetDirection == -1)
{
this.targetPoint.x = this.targetPoint.x - targetNode.width / 2;
}
if (this.targetDirection == 2)
{
this.targetPoint.y = this.targetPoint.y + targetNode.height / 2;
}
if (this.targetDirection == -2)
{
this.targetPoint.y = this.targetPoint.y - targetNode.height / 2;
}
}*/
override protected function changePoint(point:Point, anchor:Anchor):void
{
point.x = point.x + anchor.initPoint.x;
point.y = point.y + anchor.initPoint.y;
}
override protected function startNodeMoveHandle(event:NodeDragEvent):void{
updatePoint(sourcePoint, sourceDirection, event, sourceAnchor);
invalidateDisplayList();
}
override protected function endNodeMoveHandle(event:NodeDragEvent):void{
updatePoint(targetPoint, targetDirection, event, targetAnchor);
invalidateDisplayList();
}
/**
* 更新起始坐标
**/
/*private function updatePoint(point:Point, direction:int, event:NodeDragEvent):void
{
if (direction == 1)
{
point.x = event.node.x + event.node.width;
point.y = event.node.y + event.node.height / 2;
}
if (direction == -1)
{
point.x = event.node.x;
point.y = event.node.y + event.node.height / 2;
}
if (direction == 2)
{
point.x = event.node.x + event.node.width / 2;;
point.y = event.node.y + event.node.height;
}
if (direction == -2)
{
point.x = event.node.x + event.node.width / 2;;
point.y = event.node.y;
}
}*/
private function updatePoint(point:Point, direction:int, event:NodeDragEvent, anchor:Anchor):void
{
point.x = event.node.x + anchor.initPoint.x;
point.y = event.node.y + anchor.initPoint.y;
}
/**
* 1. 直线
* 2. 曲线
* 3. 折线
*/
public function get straight():int
{
return _straight;
}
/**
* @private
*/
public function set straight(value:int):void
{
_straight = value;
}
public function get targetDirection():Number
{
return _targetDirection;
}
public function set targetDirection(value:Number):void
{
_targetDirection = value;
}
public function get sourceDirection():Number
{
return _sourceDirection;
}
public function set sourceDirection(value:Number):void
{
_sourceDirection = value;
}
}
}
整体的流程图如下: