[英]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.