2013/03/28

To Customize Interactions in TWaver

Recently, there comes a fairly demanding requirement that a node dragged from the toolbar will be inserted in the link under the mouse, during which that the the section of the link to be inserted by the node will protrude over its original height.
Nodes can be inserted in to a link through the deletion of the original one and the addition of two new ones, but the protruding part is troublesome, which, however can be realized with the help of ShapeLink in TWaverFlex.
Method:
  1. Listen to the event "DragEvent.DRAG_OVER" in network and judge whether there is Link under the mouse by the method "network#getElementsByDisplayObject". If there is, set this link as transparent(link.setStyle(Styles.LINK_ALPHA, 0) and then add a ShapeLink; if there is not, set it as transparent, restore it and delete ShapeLink. Please refer to the method "updateMark" or "removeMark" for detailed codes:
    private function updateMark(link:Link, data:Object, point:Point):void {
        if(!network.elementBox.contains(markLink)){
            markLink.fromNode = link.fromNode;
            markLink.toNode = link.toNode;
            markLink.setStyle(Styles.SHAPELINK_TYPE, Consts.SHAPELINK_TYPE_QUADTO);
            markLink.setStyle(Styles.LINK_WIDTH, link.getStyle(Styles.LINK_WIDTH));
            markLink.setStyle(Styles.LINK_COLOR, link.getStyle(Styles.LINK_COLOR));
            markLink.setStyle(Styles.LINK_ALPHA, link.getStyle(Styles.LINK_ALPHA));
           
            network.elementBox.add(markLink);
            lastLink = link;
            link.setStyle(Styles.LINK_ALPHA, 0);
        }
       
        var points:Collection = new Collection();
       
        var fromCenter:Point = markLink.fromNode.centerLocation;
        var toCenter:Point = markLink.toNode.centerLocation;
        var radius:Number = Math.sqrt(data.width*data.width + data.height*data.height)/2;
        var crossPoints:Object = getCrossPoints(fromCenter, toCenter, point, radius*2);
        if (crossPoints){
            if(fromCenter.x<toCenter.x){
                points.addItem(crossPoints.p2);
                points.addItem(crossPoints.p2);
            }else{
                points.addItem(crossPoints.p1);
                points.addItem(crossPoints.p1);
            }
           
            var crossPoint:Point = new Point(crossPoints.p1.x + (crossPoints.p2.x-crossPoints.p1.x)/2,
                crossPoints.p1.y + (crossPoints.p2.y-crossPoints.p1.y)/2);
            var controlPoints:Object = getCrossPoints(crossPoint, point, point, radius*3);
            if(controlPoints){
                if(crossPoint.y >= point.y){
                    points.addItem(controlPoints.p2);
                }else{
                    points.addItem(controlPoints.p1);
                }
            }else{
                if(point.y>=fromCenter.y){
                    point.y = point.y - radius * 3;
                }else{
                    point.y = point.y + radius * 3;
                }
                points.addItem(point);
            }
            if(fromCenter.x<toCenter.x){
                points.addItem(crossPoints.p1);
                points.addItem(crossPoints.p1);
            }else{
                points.addItem(crossPoints.p2);
                points.addItem(crossPoints.p2);
            }
        }else{
            points.addItem(fromCenter);
        }
        markLink.points = points;
    }

    private function removeMark(moving:Boolean):void {
        if(network.elementBox.contains(markLink)){
            var fromNode:Node = markLink.fromNode;
            var toNode:Node = markLink.toNode;
            network.elementBox.remove(markLink);
            if(lastLink && moving){
                lastLink.setStyle(Styles.LINK_ALPHA, markLink.getStyle(Styles.LINK_ALPHA));
                lastLink = null;
            }
        }
    }

  2. The key is how to make sure which points among ShapeLink will protrude. The solution is to calculate the intersection of the semi-circle and line. Please refer to the method "getCrossPoints" for detailed codes: 
    private function getCrossPoints(p1:Point, p2:Point, circleCenter:Point, radius:Number):Object{
        var line_p1_x:Number = p1.x;
        var line_p1_y:Number = p1.y;
        var line_p2_x:Number = p2.x;
        var line_p2_y:Number = p2.y;
        var circle_center_x:Number = circleCenter.x;
        var circle_center_y:Number = circleCenter.y;
        var circle_radius:Number = radius;
        var line_k:Number =(line_p2_y-line_p1_y)/(line_p2_x-line_p1_x);
        var line_b:Number =line_p1_y-line_k*line_p1_x;
        var a:Number =1+line_k*line_k;
        var b:Number =-2*circle_center_x+2*line_k*line_b-2*line_k*circle_center_y;
        var c:Number =circle_center_x*circle_center_x+(line_b-circle_center_y)*(line_b-circle_center_y)-circle_radius*circle_radius; 
        var delta:Number =b*b-4*a*c;
        var x1:Number =(-b+Math.sqrt(delta))/(2*a);
        var x2:Number =(-b-Math.sqrt(delta))/(2*a);
        var y1:Number =line_k*x1+line_b;
        var y2:Number =line_k*x2+line_b;
       
        if(delta>=0){
            return {p1: new Point(x1, y1), p2: new Point(x2, y2)};
        }else{
            return null;
        }
    }
  3. Delete ShapeLink and establish two Links in the event "DragEvent.DRAG_DROP".

No comments:

Post a Comment