簡體   English   中英

JointJS 在元素之間創建多個鏈接

[英]JointJS create multiple links between elements

我想制作一個圖表,這樣使用JointJS。

但是,當我在元素之間添加多個鏈接時,我只看到 1 個鏈接出現。 如何添加多個鏈接,並在它們之間自動調整間距?

這是添加框和鏈接的代碼。 請注意,現在我只是想在所有塊之間添加 3 個鏈接,但我只看到每個塊之間出現 1 個鏈接。

var steps = [{title: "Step 1"}, {title: "Step 2"}, {title: "Step 3"}];

steps.forEach(function(step, i){
    var title = step.title;
    var yOffset = i*150 + 50; //offsets first block by 50 in y and all others 150
    var xOffset = 60; //offsets all blocks by 60
    createBlock(title, xOffset, yOffset, i);
});

var blocks = [];

function createBlock(title, x, y, loc) {
    var x = (typeof x !== 'undefined') ?  x : 0;
    var y = (typeof y !== 'undefined') ?  y : 0;

    var newBlock = new joint.shapes.html.Element({
        position: { x: x, y: y },
        size: { width: 170, height: 100 },
        label: title,
        attrs: {
            '.label': {
                text: title,
                'ref-x': .5, 
                'ref-y': .4,
                fill: '#FFFFFF'
            },
        }
    });

    blocks.push(newBlock.id);

    graph.addCell(newBlock);

    if(blocks.length > 1) {
        var link = new joint.shapes.devs.Link({
            source: {
                id: blocks[loc-1],
            },
            target: {
                id: blocks[loc],
            },
        });
        graph.addCell(link);

        var link2 = new joint.shapes.devs.Link({
            source: {
                id: blocks[loc-1],
            },
            target: {
                id: blocks[loc],
            },
        });
        graph.addCell(link2);

        var link3 = new joint.shapes.devs.Link({
            source: {
                id: blocks[loc-1],
            },
            target: {
                id: blocks[loc],
            },
        });
        graph.addCell(link3);
    }
}

所有鏈接都位於彼此之上,因此您可以將其視為一個鏈接。 在jointjs的demo里有代碼可以查看不同路徑下的各個鏈接。 您可以添加以下代碼並查看鏈接顯示在不同的路徑中。 您需要在以下三行中將圖形更改為您的圖形名稱

// displaying multiple links between two elements in different paths
      function adjustVertices(graph, cell) {
          // If the cell is a view, find its model.
          cell = cell.model || cell;
          if (cell instanceof joint.dia.Element) {
              _.chain(graph.getConnectedLinks(cell)).groupBy(function(link) {
                  // the key of the group is the model id of the link's source or target, but not our cell id.
                  return _.omit([link.get('source').id, link.get('target').id], cell.id)[0];
              }).each(function(group, key) {
                  // If the member of the group has both source and target model adjust vertices.
                  if (key !== 'undefined') adjustVertices(graph, _.first(group));
              });
              return;
          }

          // The cell is a link. Let's find its source and target models.
          var srcId = cell.get('source').id || cell.previous('source').id;
          var trgId = cell.get('target').id || cell.previous('target').id;

          // If one of the ends is not a model, the link has no siblings.
          if (!srcId || !trgId) return;

          var siblings = _.filter(graph.getLinks(), function(sibling) {

              var _srcId = sibling.get('source').id;
              var _trgId = sibling.get('target').id;

              return (_srcId === srcId && _trgId === trgId) || (_srcId === trgId && _trgId === srcId);
          });

          switch (siblings.length) {

          case 0:
              // The link was removed and had no siblings.
              break;

          case 1:
              // There is only one link between the source and target. No vertices needed.
              cell.unset('vertices');
              break;

          default:

              // There is more than one siblings. We need to create vertices.
              // First of all we'll find the middle point of the link.
              var srcCenter = graph.getCell(srcId).getBBox().center();
              var trgCenter = graph.getCell(trgId).getBBox().center();
              var midPoint = joint.g.line(srcCenter, trgCenter).midpoint();

              // Then find the angle it forms.
              var theta = srcCenter.theta(trgCenter);

              // This is the maximum distance between links
              var gap = 20;

              _.each(siblings, function(sibling, index) {
                  // We want the offset values to be calculated as follows 0, 20, 20, 40, 40, 60, 60 ..
                  var offset = gap * Math.ceil(index / 2);
                  // Now we need the vertices to be placed at points which are 'offset' pixels distant
                  // from the first link and forms a perpendicular angle to it. And as index goes up
                  // alternate left and right.
                  //
                  //  ^  odd indexes
                  //  |
                  //  |---->  index 0 line (straight line between a source center and a target center.
                  //  |
                  //  v  even indexes
                  var sign = index % 2 ? 1 : -1;
                  var angle = joint.g.toRad(theta + sign * 90);
                  // We found the vertex.
                  var vertex = joint.g.point.fromPolar(offset, angle, midPoint);
                  sibling.set('vertices', [{ x: vertex.x, y: vertex.y }]);
              });
          }
      };


      var myAdjustVertices = _.partial(adjustVertices, graph);
      // adjust vertices when a cell is removed or its source/target was changed
      graph.on('add remove change:source change:target', myAdjustVertices);
      // also when an user stops interacting with an element.
      graph.on('cell:pointerup', myAdjustVertices);

解決方案的核心在於下面介紹的 adjustVertices 函數。 它接受一個圖形和一個單元格(鏈接或元素)。 為了更加方便,該函數接受單元格視圖和模型。

如果 cell 是一個鏈接,它會找到所有具有相同源和目標的鏈接,然后在它們上設置頂點; 我們將稱這些相關鏈接為“兄弟姐妹”。 如果單元格是一個元素,我們會為連接到該元素的每個不同(不同的源和目標)鏈接執行我們的函數。

function adjustVertices(graph, cell) {

    // if `cell` is a view, find its model
    cell = cell.model || cell;

    if (cell instanceof joint.dia.Element) {
        // `cell` is an element

        _.chain(graph.getConnectedLinks(cell))
            .groupBy(function(link) {

                // the key of the group is the model id of the link's source or target
                // cell id is omitted
                return _.omit([link.source().id, link.target().id], cell.id)[0];
            })
            .each(function(group, key) {

                // if the member of the group has both source and target model
                // then adjust vertices
                if (key !== 'undefined') adjustVertices(graph, _.first(group));
            })
            .value();

        return;
    }

    // `cell` is a link
    // get its source and target model IDs
    var sourceId = cell.get('source').id || cell.previous('source').id;
    var targetId = cell.get('target').id || cell.previous('target').id;

    // if one of the ends is not a model
    // (if the link is pinned to paper at a point)
    // the link is interpreted as having no siblings
    if (!sourceId || !targetId) return;

    // identify link siblings
    var siblings = _.filter(graph.getLinks(), function(sibling) {

        var siblingSourceId = sibling.source().id;
        var siblingTargetId = sibling.target().id;

        // if source and target are the same
        // or if source and target are reversed
        return ((siblingSourceId === sourceId) && (siblingTargetId === targetId))
            || ((siblingSourceId === targetId) && (siblingTargetId === sourceId));
    });

    var numSiblings = siblings.length;
    switch (numSiblings) {

        case 0: {
            // the link has no siblings
            break;

        } case 1: {
            // there is only one link
            // no vertices needed
            cell.unset('vertices');
            break;

        } default: {
            // there are multiple siblings
            // we need to create vertices

            // find the middle point of the link
            var sourceCenter = graph.getCell(sourceId).getBBox().center();
            var targetCenter = graph.getCell(targetId).getBBox().center();
            var midPoint = g.Line(sourceCenter, targetCenter).midpoint();

            // find the angle of the link
            var theta = sourceCenter.theta(targetCenter);

            // constant
            // the maximum distance between two sibling links
            var GAP = 20;

            _.each(siblings, function(sibling, index) {

                // we want offset values to be calculated as 0, 20, 20, 40, 40, 60, 60 ...
                var offset = GAP * Math.ceil(index / 2);

                // place the vertices at points which are `offset` pixels perpendicularly away
                // from the first link
                //
                // as index goes up, alternate left and right
                //
                //  ^  odd indices
                //  |
                //  |---->  index 0 sibling - centerline (between source and target centers)
                //  |
                //  v  even indices
                var sign = ((index % 2) ? 1 : -1);

                // to assure symmetry, if there is an even number of siblings
                // shift all vertices leftward perpendicularly away from the centerline
                if ((numSiblings % 2) === 0) {
                    offset -= ((GAP / 2) * sign);
                }

                // make reverse links count the same as non-reverse
                var reverse = ((theta < 180) ? 1 : -1);

                // we found the vertex
                var angle = g.toRad(theta + (sign * reverse * 90));
                var vertex = g.Point.fromPolar(offset, angle, midPoint);

                // replace vertices array with `vertex`
                sibling.vertices([vertex]);
            });
        }
    }
}

然后我們附加必要的事件偵聽器(函數 bindInteractionEvents)。 每當用戶翻譯元素時都會重新計算頂點 - 以及添加/刪除鏈接或更改其源或目標時。

 function bindInteractionEvents(adjustVertices, graph, paper) {

        // bind `graph` to the `adjustVertices` function
        var adjustGraphVertices = _.partial(adjustVertices, graph);

        // adjust vertices when a cell is removed or its source/target was changed
        graph.on('add remove change:source change:target', adjustGraphVertices);

        // adjust vertices when the user stops interacting with an element
        paper.on('cell:pointerup', adjustGraphVertices);
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM