javascript jsPlumb - 每侧的动态端点锚点

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15211096/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 23:52:37  来源:igfitidea点击:

jsPlumb - dynamic endpoint anchors on each side

javascriptjqueryhtmljsplumb

提问by DMINATOR

I am trying to figure out a way how to add endpoint anchors dynamically to jsPlumb container.

我试图找出一种如何将端点锚点动态添加到 jsPlumb 容器的方法。

I would like to have source endpoints on the left side and target endpoints on the right side only.

我想在左侧有源端点,在右侧有目标端点。

The problem is, that I wasn't able to find any way to do so, without resorting to some hacks, like I am doing now.

问题是,我无法找到任何方法来做到这一点,而不像我现在所做的那样求助于一些黑客。

jsPlumb supports Continuous Anchors, but position of individual anchor will be recalculated based on the orientation between connectors and number of continuous anchors. This means both source and target endpoints could be sharing the same side of the container, this is something I would like to avoid.

jsPlumb 支持连续锚点,但将根据连接器之间的方向和连续锚点的数量重新计算单个锚点的位置。这意味着源和目标端点可以共享容器的同一侧,这是我想避免的。

Here is a jsFiddler code I came up with

这是我想出jsFiddler 代码

Here is a part of the code I am using to hack and recalculate anchor positions myself (when Add button is clicked), with some buggy results :(

这是我用来自己破解和重新计算锚点位置的代码的一部分(单击“添加”按钮时),结果有一些错误:(

   function fixEndpoints(endpoints) {

            //there are 2 types - input and output

            var inputAr = $.grep(endpoints, function (elementOfArray, indexInArray) {
                return elementOfArray.isSource; //input
            });

            var outputAr = $.grep(endpoints, function (elementOfArray, indexInArray) {
                return elementOfArray.isTarget; //output
            });

            calculateEndpoint(inputAr, true);
            calculateEndpoint(outputAr, false);
        }

        function calculateEndpoint(endpointArray, isInput) {

            //multiplyer
            var mult = 1 / endpointArray.length;

            for (var i = 0; i < endpointArray.length; i++) {

                if (isInput) {
                    endpointArray[i].anchor.x = 1;
                    endpointArray[i].anchor.y = mult * i;//, 1, 0] };
                } 
                else {
                    endpointArray[i].anchor.x = 0;
                    endpointArray[i].anchor.y = mult * i;//, -1, 0] };
                }
            }
        }



        //Add additional anchor
        $(".button_add").live("click", function () {

            var parentnode = $(this)[0].parentNode.parentNode;

            jsPlumb.addEndpoint(
                parentnode,
                anEndpointSource
            );

            jsPlumb.addEndpoint(
                parentnode,
                anEndpointDestination
            );

            //get list of current endpoints
            var endpoints = jsPlumb.getEndpoints(parentnode);

            //fix endpoints
            fixEndpoints(endpoints);

            jsPlumb.recalculateOffsets();
            jsPlumb.repaint(parentnode);
        });

Expected result

预期结果

As you can see on the image above, left side has only source endpoints (Dot) and right side (Box) only target endpoints, once new endpoint is added, anchors are recalculated based on the number of anchors on one side.

如上图所示,左侧只有源端点(Dot),右侧(Box)只有目标端点,一旦添加新端点,锚点将根据一侧的锚点数量重新计算。

This works but still buggy: position is updated only once I move the container and connection between containers is not correct as well.

这有效但仍然有问题:位置仅在我移动容器并且容器之间的连接也不正确时更新。

What I would like to have, is a way for it to work and connect items correctly (preferably using correct jsPlumb code without resorting to hacks)

我想要的是一种让它正确工作和连接项目的方法(最好使用正确的 jsPlumb 代码而不诉诸黑客)

采纳答案by DMINATOR

I finally figured out how to do it. It was easier than I thought.

我终于知道怎么做了。这比我想象的要容易。

Code is basically the same with a few changes, here is updated fiddler sample

代码基本相同但有一些变化,这里是更新的提琴手示例

<!DOCTYPE html>
<html>
<head>
<title>JS plumb test</title>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.23/jquery-ui.min.js"></script>
    <script type="text/javascript" src="./include/jquery.jsPlumb-1.3.16-all-min.js"></script>

<style>
    .window { 
        background-color: #EEEEEF;
        border: 1px solid #346789;
        border-radius: 0.5em;
        box-shadow: 2px 2px 5px #AAAAAA;
        color: black;
        height: 5em;
        position: absolute;
        width: 5em;
    }

    .window:hover { 
        box-shadow: 2px 2px 19px #AAAAAA;
        cursor: pointer;
    }


    .button_add, .button_add_window, .button_remove, .button {
        background-color: deepskyblue;
        text-align: center;
        border: 1px solid;
    }

    .button_container {
        margin: 5px;
        background-color: #aaaaaa
    }
</style>

<script>

    jsPlumb.ready(function () {


        //FIX DOM:
        $(("#container1"))[0].innerHTML = $(("#container0"))[0].innerHTML;

        //all windows are draggable
        jsPlumb.draggable($(".window"));


        var anEndpointSource = {
            endpoint: "Rectangle",
            isSource: true,
            isTarget: false,
            maxConnections: 1,

            anchor: [1, 0, 1, 0]
        };

        var anEndpointDestination = {
            endpoint: "Dot",
            isSource: false,
            isTarget: true,
            maxConnections: 1,

            anchor: [0, 1, -1, 0]
        };


        //Fixes endpoints for specified target
        function fixEndpoints(parentnode) {

            //get list of current endpoints
            var endpoints = jsPlumb.getEndpoints(parentnode);

            //there are 2 types - input and output

            var inputAr = $.grep(endpoints, function (elementOfArray, indexInArray) {
                return elementOfArray.isSource; //input
            });

            var outputAr = $.grep(endpoints, function (elementOfArray, indexInArray) {
                return elementOfArray.isTarget; //output
            });

            calculateEndpoint(inputAr, true);
            calculateEndpoint(outputAr, false);

            jsPlumb.repaintEverything();
        }

        //recalculate endpoint anchor position manually
        function calculateEndpoint(endpointArray, isInput) {

            //multiplyer
            var mult = 1 / (endpointArray.length+1);

            for (var i = 0; i < endpointArray.length; i++) {

                if (isInput) {

                    //position
                    endpointArray[i].anchor.x = 1;
                    endpointArray[i].anchor.y = mult * (i + 1);
                } 
                else {

                    //position
                    endpointArray[i].anchor.x = 0;
                    endpointArray[i].anchor.y = mult * (i + 1);
                }
            }
        }



        //Add additional anchor
        $(".button_add").live("click", function () {

            var parentnode = $(this)[0].parentNode.parentNode;

            jsPlumb.addEndpoint(
                parentnode,
                anEndpointSource
            );

            jsPlumb.addEndpoint(
                parentnode,
                anEndpointDestination
            );

            fixEndpoints(parentnode);
        });

        //Remove anchor 
        $(".button_remove").live("click", function () {

            var parentnode = $(this)[0].parentNode.parentNode;

            //get list of current endpoints
            var endpoints = jsPlumb.getEndpoints(parentnode);

            //remove 2 last one

            if (endpoints.length > 1) {
                jsPlumb.deleteEndpoint(endpoints[endpoints.length - 2]);
            }

            if (endpoints.length > 0) {
                jsPlumb.deleteEndpoint(endpoints[endpoints.length - 1]);
            }

            fixEndpoints(parentnode);
        });


        //adds new window
        $(".button_add_window").click(function () {

            var id = "dynamic_" + $(".window").length;

            //create new window and add it to the body
            $('<div class="window" id="' + id + '" >').appendTo('body').html($(("#container0"))[0].innerHTML);

            //set jsplumb properties
            jsPlumb.draggable($('#' + id));
        });
    });
</script>

</head>
<body >

    <!-- Adds new windows to the page -->
    <div class="window" style="left: 600px" id="details">
        <p style="text-align: center">Window</p>
        <div class="button_container">
            <div class="button_add_window">Add</div>
        </div>
    </div>

    <!-- Primary window - used as html templated for descendants -->
    <div class="window" style="left: 20px" id="container0">
        <div class="button_container">
            <div class="button_add">Add</div>
            <div class="button_remove">Remove</div>
        </div>
    </div>

    <div class="window" style="left: 200px" id="container1">
    </div>


</body>
</html>

Changes that I made:

我所做的更改:

  1. Now I specify endpoint anchor offset when I add it, I only calculate anchor position, so offset never changes, it is always correct from the start:

    var anEndpointSource = {
        endpoint: "Rectangle",
        isSource: true,
        isTarget: false,
        maxConnections: 1,
    
        anchor: [1, 0, 1, 0]
    };
    
  2. Once endpoint is added, I re-calculate anchor positions and call (this will repaint connections):

    jsPlumb.repaintEverything();

  1. 现在我在添加时指定端点锚点偏移量,我只计算锚点位置,所以偏移量永远不会改变,从一开始它总是正确的:

    var anEndpointSource = {
        endpoint: "Rectangle",
        isSource: true,
        isTarget: false,
        maxConnections: 1,
    
        anchor: [1, 0, 1, 0]
    };
    
  2. 添加端点后,我重新计算锚点位置并调用(这将重新绘制连接):

    jsPlumb.repaintEverything();

Here is the final result:

这是最终结果:

endpoints correctly connected

endpoints correctly connected

回答by Buddhika

You can delete states by double click by adding

您可以通过添加双击删除状态

                     newState.dblclick(function(e) {
                        alert("This will delete the state and its connections");
                        instance.detachAllConnections($(this));
                      $(this).remove();
                      e.stopPropagation();
                    });

function to your jsPlumb.ready function. you can add this to your all states by adding

函数到您的 jsPlumb.ready 函数。您可以通过添加将其添加到您的所有状态

var windows = jsPlumb.getSelector(".statemachine-demo .state");
            windows.dblclick(function(e) {
            alert("This will delete the state and its connections");
            instance.detachAllConnections($(this));
          $(this).remove();
          e.stopPropagation();
        });

here statemachine-demo is id of div in your contaner and state is class of state divs.

这里 statemachine-demo 是容器中 div 的 id,而 state 是状态 div 的类。

回答by cn123h

thank you for the solution, it works fine when the anchor side is predefined, like here sources are always on the left side and targets are always on the right.

谢谢你的解决方案,当锚点被预定义时它工作正常,就像这里的源总是在左边,目标总是在右边。

But if they are dynamic we need to implement the side selection also by ourselves?

但是如果它们是动态的,我们也需要自己实现侧边选择吗?

As a workaround what I did is to set more possible anchor positions in default config. Any better idea?

作为一种解决方法,我所做的是在默认配置中设置更多可能的锚点位置。有什么更好的主意吗?

thanks

谢谢