前提:
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; } } }
整体的流程图如下: