Custom SVG Connection Ports & Multi-Layer Cross-Layer Positioning in JointJS #3362
-
IntroductionWe are building a Plant Automation HMI application using JointJS that includes a pipeline designer with a large library of custom SVG-based industrial elements (pumps, tanks, motors, valves, etc.). We have two architectural questions regarding JointJS capabilities that are central to our implementation. Steps to reproduceI have a couple of technical questions regarding JointJS implementation for a Plant Automation HMI project we are currently developing.
Any guidance, examples, or best practices on either of these points would be greatly appreciated. Restrictions & ConstraintsNo response Does your question relate to JointJS or JointJS+. Select both if applicable.JointJS+ |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
|
Great questions, Nitin-Shandilya! 🙏 1. Connection points on custom SVG equipmentUse the Ports API rather than raw magnets. You get named, addressable points, and links snap to them automatically. For precise inlet/outlet positions on irregular SVG shapes, define a port group with the const Pump = dia.Element.define('hmi.Pump', {
size: { width: 80, height: 60 },
ports: {
groups: {
pipe: {
position: { name: 'absolute' },
attrs: { portBody: { r: 5, magnet: 'active' } },
markup: util.svg`<circle @selector="portBody"/>`
}
},
items: [
{ id: 'inlet', group: 'pipe', args: { x: 0, y: '50%' } },
{ id: 'outlet', group: 'pipe', args: { x: 'calc(w)', y: '50%' } }
]
}
}, {
markup: util.svg`<path @selector="body"/>` // your custom SVG here
});Connect a pipe to a specific port by id: link.source({ id: pump.id, port: 'outlet' });
link.target({ id: tank.id, port: 'inlet' });Because ports are positioned relative to the element bbox, they stay attached when the element is moved or resized. You can also have multiple groups on one element (e.g. a To read a port's resolved coordinates at any time — useful for the alignment in (2) — use const positions = pump.getPortsPositions('pipe'); // { inlet: {x, y, angle}, outlet: {...} }
const origin = pump.position();
const inletAbs = { x: origin.x + positions.inlet.x, y: origin.y + positions.inlet.y };Reference: Port layouts. 2. Multi-layer with cross-layer positional awarenessJointJS 4.2 introduced a first-class Layers API, and the positional awareness you're after is essentially free: all layers share the same Paper coordinate system. A wire on the Electronics layer at graph.addLayer({ id: 'map' }); // rendered back -> front in this order
graph.addLayer({ id: 'physical' });
graph.addLayer({ id: 'electronics' });
graph.setDefaultLayer('physical');
graph.addCells([pump, tank]); // -> physical layer
graph.setDefaultLayer('electronics');
graph.addCells([wire1, wire2]); // -> electronics layerEach layer is its own model with its own cell collection and z-index stacking context, and the whole thing serializes through Because the coordinate space is shared, a link on the Electronics layer can target a port on a Physical-layer element directly by id, and it will render and re-route correctly, even when you drag the physical equipment: wire.source({ id: plc.id, port: 'o1' }); // element on 'electronics'
wire.target({ id: pump.id, port: 'signal' }); // element on 'physical'To keep physical equipment visible as a reference while editing the Electronics layer, don't hide the Physical layer. Keep it rendered but non-interactive and dimmed, so it acts as a "ghost underlay." One straightforward way is to set opacity / pointer-events on the layer's view node: const layerView = paper.getLayerView('physical');
layerView.el.style.opacity = 0.2;
layerView.el.style.pointerEvents = 'none';If you need "what physical asset is under this wiring point, and which layer is it on," References: Graph API (layer methods) · GraphLayer · 4.2 release overview.
Let me know if this helps. 🙂 |
Beta Was this translation helpful? Give feedback.
Great questions, Nitin-Shandilya! 🙏
1. Connection points on custom SVG equipment
Use the Ports API rather than raw magnets. You get named, addressable points, and links snap to them automatically. For precise inlet/outlet positions on irregular SVG shapes, define a port group with the
absolutelayout and give each port explicit coordinates (px,%of the element bbox, orcalc()expressions):