Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/joint-core/src/dia/Graph.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,24 @@ export const Graph = Model.extend({
}, this);
}

// Restrict to links attached to `model` at a specific port and/or magnet. Matched on
// the direction-appropriate end (source for outbound, target for inbound), so a
// self-loop is not matched via its other end when only one direction is requested.
if (opt.port !== undefined || opt.magnet !== undefined) {
const { port, magnet } = opt;
const modelId = model.id;
const endMatches = (end) => {
if (end.id !== modelId) return false;
if (port !== undefined && end.port !== port) return false;
if (magnet !== undefined && end.magnet !== magnet) return false;
return true;
};
links = links.filter((link) =>
(outbound && endMatches(link.source())) ||
(inbound && endMatches(link.target()))
);
}

return links;
},

Expand Down
109 changes: 109 additions & 0 deletions packages/joint-core/test/jointjs/graph.js
Original file line number Diff line number Diff line change
Expand Up @@ -1018,6 +1018,115 @@ QUnit.module('graph', function(hooks) {
);
});

QUnit.test('graph.getConnectedLinks() with port/magnet options', function(assert) {
var graph = this.graph;

new joint.shapes.standard.Rectangle({
id: 'a',
ports: { items: [{ id: 'in' }, { id: 'out' }] },
}).addTo(graph);
new joint.shapes.standard.Rectangle({ id: 'b' }).addTo(graph);

// a.out -> b
new joint.shapes.standard.Link({
id: 'l1',
source: { id: 'a', port: 'out' },
target: { id: 'b' },
}).addTo(graph);
// a.out -> b (second link on the same port)
new joint.shapes.standard.Link({
id: 'l2',
source: { id: 'a', port: 'out' },
target: { id: 'b' },
}).addTo(graph);
// b -> a.in
new joint.shapes.standard.Link({
id: 'l3',
source: { id: 'b' },
target: { id: 'a', port: 'in' },
}).addTo(graph);
// b -> a (no port)
new joint.shapes.standard.Link({
id: 'l4',
source: { id: 'b' },
target: { id: 'a' },
}).addTo(graph);
// a.out -> a.in (self-loop across two ports)
new joint.shapes.standard.Link({
id: 'l5',
source: { id: 'a', port: 'out' },
target: { id: 'a', port: 'in' },
}).addTo(graph);
// a(.body magnet) -> b
new joint.shapes.standard.Link({
id: 'l6',
source: { id: 'a', magnet: '.body' },
target: { id: 'b' },
}).addTo(graph);
// a(out port + .body magnet) -> b
new joint.shapes.standard.Link({
id: 'l7',
source: { id: 'a', port: 'out', magnet: '.body' },
target: { id: 'b' },
}).addTo(graph);

var a = graph.getCell('a');
var ids = function(links) { return _.sortBy(_.map(links, 'id')); };

// Port.
assert.deepEqual(
ids(graph.getConnectedLinks(a, { port: 'out' })),
['l1', 'l2', 'l5', 'l7'],
'port matches links attached to the element at that port, either end.',
);
assert.deepEqual(
ids(graph.getConnectedLinks(a, { outbound: true, port: 'out' })),
['l1', 'l2', 'l5', 'l7'],
'outbound + port narrows to links leaving the given port.',
);
assert.deepEqual(
ids(graph.getConnectedLinks(a, { inbound: true, port: 'in' })),
['l3', 'l5'],
'inbound + port narrows to links arriving at the given port.',
);
assert.deepEqual(
ids(graph.getConnectedLinks(a, { outbound: true, port: 'in' })),
[],
'outbound + input port yields no links (outbound attaches at the source end).',
);
assert.deepEqual(
ids(graph.getConnectedLinks(a, { port: 'missing' })),
[],
'unknown port yields no links.',
);

// Magnet.
assert.deepEqual(
ids(graph.getConnectedLinks(a, { magnet: '.body' })),
['l6', 'l7'],
'magnet matches links attached to the element at that magnet.',
);

// Port + magnet (AND).
assert.deepEqual(
ids(graph.getConnectedLinks(a, { port: 'out', magnet: '.body' })),
['l7'],
'port + magnet requires the end to match both.',
);
assert.deepEqual(
ids(graph.getConnectedLinks(a, { port: 'in', magnet: '.body' })),
[],
'port + magnet with no end matching both yields no links.',
);

// Unchanged when neither option is given.
assert.deepEqual(
ids(graph.getConnectedLinks(a)),
['l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7'],
'no port/magnet option leaves behavior unchanged.',
);
});

QUnit.test('graph.getConnectedLinks()', function(assert) {
var graph = this.graph;
this.setupTestMixtureGraph(graph);
Expand Down
4 changes: 4 additions & 0 deletions packages/joint-core/types/dia.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,10 @@ export namespace Graph {
interface ConnectionOptions extends Cell.EmbeddableOptions {
inbound?: boolean;
outbound?: boolean;
/** Restrict to links attached to the element at this port. */
port?: string;
/** Restrict to links attached to the element at this magnet (selector). */
magnet?: string;
}

interface ExploreOptions extends ConnectionOptions {
Expand Down
Loading