【问题标题】:KineticJS: Draw Arrow between two shapesKineticJS:在两个形状之间绘制箭头
【发布时间】:2013-06-29 21:08:54
【问题描述】:

所以,我想在 kineticjs 的帮助下创建一个有限状态机可视化器/编辑器,但我遇到了以下场景:

我有两个“节点”,比如说可以在我的舞台上拖动的圆形对象(用标签分组)。现在我不想点击一个圆圈,按住鼠标并移动它并在两个形状之间添加一个连接(为了简单起见,一个箭头)。

因此,如果我还没有找到解决方案,请提供有关如何完成此操作的任何提示。

指定它:节点本身应该保持可拖动。我的想法是:添加一个黑色圆圈和一个半径稍小的白色圆圈,将它们分组。然后在 dragstart 白色圆圈上 -> 拖动节点,在 dragstart 黑色圆圈上 -> 绘制箭头。

问题是如何从一个形状开始绘制一个箭头并跟随鼠标到达它的目标(可以是另一个节点组 => 到该组的连接或舞台的空白点 => 一个覆盖打开,让用户选择另一个节点绘制或取消绘制)。

我希望这有点清楚易懂。如需更多信息,请随时问我。

最好的问候, 多米尼克

p.s.:这种行为似乎与 lucidchart (dot com) 在创建图表时使用的行为完全一样,所以也许你了解我想要实现的目标,更好地查看这里的演示:https://www.lucidchart.com/demo

【问题讨论】:

    标签: javascript kineticjs


    【解决方案1】:

    首先,为了简单起见,这里是一个关于如何用鼠标和 KineticJS 绘制基本线条的小提琴:http://jsfiddle.net/projeqht/fF3hh/

    假设你已经在舞台上有两个圆圈,你需要画一条线来连接它们。

    我们可以使用e.targetNode来选择每个事件(mousedown、mouseup)上的节点,例如:

    layer.on("mousedown", function (e) {
      var nodeDown = e.targetNode;
    }
    
    layer.on("mouseup", function (e) {
      var nodeUp = e.targetNode;
    }
    

    我们需要检查 nodeDown 的父级是否是 Kinetic.Group 其他东西。

    1. 如果目标节点nodeDown有一个Kinetic.Group作为父节点,我们可以使用这个Group来存储新行,第二个目标节点nodeUp
    2. 如果目标节点nodeUp没有父节点的Kinetic.Group,我们需要查看nodeUp是否有父节点的组。如果nodeUp 有一个 Kinetic.Group 作为父节点,那么我们可以使用该 Group 来存储新行和第一个目标节点 nodeDown
    3. 如果nodeDownnodeUp 都没有父组,那么我们需要为它们创建一个新组,并将所有 3 个形状(2 个圆和一条线)添加到该新组。

    使用本教程了解如何将形状从一组移动到另一组:http://www.html5canvastutorials.com/kineticjs/html5-canvas-move-shape-to-another-container-with-kineticjs/

    此外,如果您将一个形状从一个组移动到另一个组,您可能需要remove()destroy() 多余的组(如果不再需要)。

    在绘制线条时,您必须禁用拖动形状,以便您可以使用鼠标拖动和绘制。您可以通过执行类似的操作来做到这一点:

    function stopDrag() {
      for (var i=0; i<layer.children.length; i++) {
        layer.children[i].setDraggable(false);
      }
    }
    
    function startDrag() {
      for (var i=0; i<layer.children.length; i++) {
          layer.children[i].setDraggable(true);
      }
    }
    

    这将使图层的所有子级都可拖动和不可拖动,但您可能希望通过比选择layer.children 更具体来限制这一点。我喜欢在这里使用的一个好技巧是将所有可拖动的组命名为“draggable_shapes”,然后使用var draggableArray = stage.get('.draggable_shapes') 选择所有允许拖动的组,然后您可以循环遍历该数组和setDraggable()

    另外一点需要注意的是,Line 的 X 和 Y 坐标计算起来会有点棘手,这取决于它是否有一个 Group 作为父级或一个 Layer。如果 Line 被分组,则 Line 的坐标将相对于 Group 位置,否则 Line 的坐标将相对于 Stage(左上角)。

    这将使您开始将一条线与两个不同的圆圈连接起来。如果您希望线条仅连接在圆圈的外缘上,则由您来执行坐标逻辑。

    也许您可能想在每个圆圈后面添加一个透明矩形(属性opacity: 0),以便在鼠标按下矩形时,您将调用drawLine() 开始绘制一条线。否则,如果用户单击圆圈,它将拖动组。至少它具有与 Lucid Chart 应用程序类似的功能。

    自定义命中函数 (http://www.html5canvastutorials.com/kineticjs/html5-canvas-kineticjs-custom-hit-function-tutorial/) 可能是一种更简洁的方法,但我并不是 100% 使用自定义命中函数,其他人可能更了解。

    如果您需要进一步的帮助,请告诉我。祝你好运!

    【讨论】:

    • 非常感谢您的回答。我明天试试,因为我现在脑子里有个大疙瘩。我已将答案标记为已接受,因为乍一看,这对我来说似乎非常详细和合乎逻辑,所以再次感谢您! :)
    • +1 用于自定义点击功能。这对他们来说是一个完美的用例
    • 所以,它可以工作:) 只是为了提供信息。唯一的问题:使用触摸界面,我只能得到 x 和 y 坐标的 NaN。关于如何更改代码以实现触摸坐标的任何想法?我尝试了 getTouchPosition() 并再次 getX 等等,但没有成功。
    • 抱歉,现在也支持触控。添加 touchPosition 等时遇到了一点代码问题(忘记了,);)
    猜你喜欢
    • 2013-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多