KineticJS - 带有连接的可拖动形状

Posted

技术标签:

【中文标题】KineticJS - 带有连接的可拖动形状【英文标题】:KineticJS - draggable shape with connections 【发布时间】:2014-07-14 00:31:33 【问题描述】:

我对 KineticJS 还很陌生,并且在可拖动形状(圆形)和一条线(将这个形状与另一个连接起来)方面遇到了问题。 移动可拖动形状后,我无法重绘线条。也许你们中的一个可以给我一个提示。

这是我的代码:

<!DOCTYPE html>
<html>
<head>
<title></title>
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script type="text/javascript" src="kinetic.js"></script>
<link href='http://fonts.googleapis.com/css?family=Open+Sans+Condensed:300' rel='stylesheet' type='text/css'>
<style type="text/css">
    html, body 
        font-family: 'Open Sans Condensed', Arial, sans-serif;
        font-size: 14px;
        background: #EFEFEF;
        width: 100%;
        height: 100%;
    

    h1 
        text-align: center;
        font-size: 30px;
    

    #canvas 
        display: block;
        background: white;
        border: 1px solid #CCC;
        margin: 50px auto;
        width: 700px;
        height: 500px;
    
</style>
</head>
<body>


<h1>kinetic.js test</h1>

<div id="canvas"></div>

<script defer="defer">

    /**
     * get circle center coordinates
     *
     * @desc    gets coordinates of circle center
     * @param   shapeId     -   id of circle
     * @returns object    -   object with x and y coordinates
     */
    function getCircleCenterCoordinates(shapeId) 

        var shape = getShapeById(shapeId);

        if(typeof shape == 'object') 

            return x: shape.shape.attrs.x, y: shape.shape.attrs.y

        

    


    /**
     * get shape by id
     *
     * @desc    searches for given shape id and returns the matching
     * @param   shapeId     -   id of the circle
     * @returns *
     */
    function getShapeById(shapeId) 

        var result = jQuery.grep(shapes, function(e)  return e.id == shapeId; );

        if(result.length == 1) 

            return result[0];

         else 

            return null;

        

    


    /**
     * draw
     *
     * @desc    draw shapes
     * @retuns  void
     */
    function draw() 

        // add shapes to the layer and register event listeners
        for(var i = 0; i < shapes.length; i++) 

            var shapeObj = shapes[i];


            // add shape to layer
            circleLayer.add(shapeObj.shape);

            // register event listeners
            for(var n = 0; n < shapeObj.events.length; n++) 

                var eventObj = shapeObj.events[n];

                shapeObj.shape.on(eventObj.type, eventObj.callback);

            

            // draw connections
            for(var m = 0; m < shapeObj.connections.length; m++) 

                var connectionObj = shapeObj.connections[m];

                // get ids
                var fromId  = shapeObj.id;
                var toId    = connectionObj.to;

                // check if connection is already drawn
                if(fromId > toId) 

                    // do not draw it again
                    continue;

                

                // get coordinates
                var fromCoordinatesObj  = getCircleCenterCoordinates(fromId);
                var toCoordinatesObj    = getCircleCenterCoordinates(toId);

                // check coordinates
                if(typeof fromCoordinatesObj != 'object' || typeof toCoordinatesObj != 'object') 

                    // was not able to get valid coordinates
                    continue;

                

                // update / set line points for this connection
                connectionObj.line.attrs.points = [fromCoordinatesObj.x, fromCoordinatesObj.y, toCoordinatesObj.x, toCoordinatesObj.y];

                // add line to layer
                connectorLayer.add(connectionObj.line);

            

        


        // add the layers to the stage
        stage.add(connectorLayer);
        stage.add(circleLayer);

    


    /**
     * init shapes and layers
     * -------------------------------------------------------------------------------------------------------
     */

    // create stage
    var stage = new Kinetic.Stage(
        container: 'canvas',
        width: 700,
        height: 500
    );


    // create layers
    var circleLayer     = new Kinetic.Layer();
    var connectorLayer  = new Kinetic.Layer();


    // define shapes
    var shapes = [

        
            id:     1001,
            label:  'me',
            shape:  new Kinetic.Circle(
                x: stage.getWidth() / 2 - 200,
                y: stage.getHeight() / 2 + 100,
                radius: 70,
                fill: '#DDD',
                stroke: '#EFEFEF',
                strokeWidth: 10,
                draggable: true
            ),
            events: [
                type: 'mouseover', callback: function()  console.log('over 1');
            ],
            connections: [
                to: 2001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2),
                to: 3001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2),
                to: 4001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2)
            ]

        ,
        
            id:     2001,
            label:  'you',
            shape:  new Kinetic.Circle(
                x: stage.getWidth() / 2 + 200,
                y: stage.getHeight() / 2 + 100,
                radius: 70,
                fill: '#DDD',
                stroke: '#EFEFEF',
                strokeWidth: 10,
                draggable: true
            ),
            events: [
                type: 'mouseover', callback: function()  console.log('over 2');
            ],
            connections: [
                to: 1001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2),
                to: 3001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2),
                to: 4001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2)
            ]
        ,
        
            id:     3001,
            label:  'her',
            shape:  new Kinetic.Circle(
                x: stage.getWidth() / 2,
                y: stage.getHeight() / 2 - 100,
                radius: 70,
                fill: '#DDD',
                stroke: '#EFEFEF',
                strokeWidth: 10,
                draggable: true
            ),
            events: [
                type: 'mouseover', callback: function()  console.log('over 3');
            ],
            connections: [
                to: 1001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2),
                to: 2001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2)
            ]
        ,
        
            id:     4001,
            label:  'his',
            shape:  new Kinetic.Circle(
                x: 100,
                y: 150,
                radius: 70,
                fill: '#DDD',
                stroke: '#EFEFEF',
                strokeWidth: 10,
                draggable: true
            ),
            events: [
                type: 'mouseover', callback: function()  console.log('over 4');,
                type: 'dragend', callback: function()  console.log(this.getPosition()); console.log(shapes[3]);  
            ],
            connections: [
                to: 1001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2),
                to: 2001, line: new Kinetic.Line(stroke: '#333', strokeWidth: 2)
            ]
        

    ];


    // draw shapes
    draw();

</script>

【问题讨论】:

为什么不使用 Kinetic.Group 呢? 你好,Elsa,感谢您的回复!我对 KineticJs 很陌生。检查手册后,它不像我的问题的解决方案。如果我将我的连接线从节点 A 到节点 B 放在一个组中,另一个节点不会知道它,对吗?我只想要一个“粘性”线到节点 A 和 B,当节点 A 或节点 B 移动时,它也会移动。谢谢。 好吧,如果你创建一个组,然后添加任何你想要的节点(例如线和圆圈)并将它们设置为可拖动,当你拖动一个时,整个组将一起移动物品。这就是我理解你到现在为止想要做的事情 :-) 不客气,祝你好运! 啊,现在我明白了,你误解了我的问题:) 我只想移动连接到我移动的圆圈的线。圆圈 A 移动。圆圈 B 和 C 仍处于相同位置。但是从 B 和 C 到 A 的线必须移动到 A 的新中心。再次感谢您 【参考方案1】:

以下是保持 2 个节点与 Kinetic.Line 连接的方法。

创建一个 Kinetic.Line 并设置点以连接您希望连接的 2 个节点。

在您希望连接的 2 个节点上侦听 dragmove 事件。

在拖动任一节点时,重置连接线的点以再次连接到 2 个节点。

这样的……

NodeA.on('dragmove',function()
    connectorAB.points([NodeA.x(),nodeA.y(),nodeB.x(),nodeB.y()]);
    layer.draw();
);

// same thing for NodeB

【讨论】:

谢谢markE!它几乎可以工作。当我移动我的节点时,线条将按预期绘制,但旧线条仍然出现。我必须清洁层或其他东西吗?我目前只是更新我的 KineticJs 线对象中的点,然后调用 draw() 函数。谢谢 如果圆圈和连接器位于不同的层,则必须更新两个层。无论哪种方式stage.draw() 都可以。

以上是关于KineticJS - 带有连接的可拖动形状的主要内容,如果未能解决你的问题,请参考以下文章

夹在与 KineticJS 楔子的交点上

KineticJS:禁用拖动

KineticJs - 将图像合并到另一个图像上

使用 KineticJS 在鼠标悬停时重新着色形状

拖动时的 KineticJS 图层索引

在 KineticJS 中检测舞台上的点击而不是形状上的点击