jointjs
Version:
JavaScript diagramming library
180 lines (159 loc) • 5.1 kB
JavaScript
var Shape = joint.shapes.standard.Rectangle.define('example', {
attrs: {
root: {
magnet: false
},
body: {
fill: 'lightgray'
}
},
ports: {
items: [{ group: 'out' }],
groups: {
in: {
position: { name: 'top' },
attrs: {
portBody: {
magnet: 'passive',
r: 12,
cy: -4,
fill: 'darkblue',
stroke: 'black'
}
},
z: 0
},
out: {
position: { name: 'bottom' },
attrs: {
portBody: {
magnet: 'active',
r: 12,
cy: 4,
fill: 'lightblue',
stroke: 'black'
}
},
z: 0
}
}
}
}, {
portMarkup: [{ tagName: 'circle', selector: 'portBody' }],
MINIMUM_NUMBER_OF_PORTS: 2,
getGroupPorts: function(group) {
return this.getPorts().filter(function(port) {
return port.group === group;
});
},
getInPorts: function() {
return this.getGroupPorts('in');
},
getOutPorts: function() {
return this.getGroupPorts('out');
},
getUsedInPorts: function() {
var graph = this.graph;
if (!graph) return [];
var connectedLinks = graph.getConnectedLinks(this, { inbound: true });
return connectedLinks.map(function(link) {
return this.getPort(link.target().port);
}, this);
},
getNewInPorts: function(number) {
return Array.from({ length: number }, function() {
return { group: 'in' };
});
},
updateInPorts: function() {
var minNumberOfPorts = this.MINIMUM_NUMBER_OF_PORTS;
var ports = this.getInPorts();
var usedPorts = this.getUsedInPorts();
var newPorts = this.getNewInPorts(Math.max(minNumberOfPorts - usedPorts.length, 1));
if (ports.length === minNumberOfPorts && ports.length - usedPorts.length > 0) {
// noop
} else if (ports.length === usedPorts.length) {
this.addPorts(newPorts);
} else if (ports.length + 1 > usedPorts.length) {
this.prop(['ports', 'items'], this.getOutPorts().concat(usedPorts).concat(newPorts), { rewrite: true });
}
}
});
var magnetAvailabilityHighlighter = {
name: 'stroke',
options: {
padding: 6,
attrs: {
'stroke-width': 3,
'stroke': 'red'
}
}
};
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: document.getElementById('paper'),
model: graph,
width: 800,
height: 800,
gridSize: 1,
linkPinning: false,
snapLinks: true,
defaultLink: new joint.shapes.standard.Link({ z: - 1 }),
defaultConnector: { name: 'smooth' },
defaultConnectionPoint: { name: 'boundary' },
markAvailable: true,
validateConnection: function(vS, mS, vT, mT, end, lV) {
if (!mT) return false;
if (vS === vT) return false;
if (mT.getAttribute('port-group') !== 'in') return false;
if (vT.model instanceof Shape) {
var portId = mT.getAttribute('port');
var usedInPorts = vT.model.getUsedInPorts();
if (usedInPorts.find(function(port) { return port.id === portId; })) return false;
}
return true;
}
});
paper.options.highlighting.magnetAvailability = magnetAvailabilityHighlighter;
paper.on('link:mouseenter', function(linkView) {
var tools = new joint.dia.ToolsView({
tools: [
new joint.linkTools.TargetArrowhead(),
new joint.linkTools.Remove({ distance: -30 })
]
});
linkView.addTools(tools);
});
paper.on('link:mouseleave', function(linkView) {
linkView.removeTools();
});
paper.on('link:connect link:disconnect', function(linkView, evt, elementView) {
var element = elementView.model;
if (element instanceof Shape) {
element.getInPorts().forEach(function(port) {
var portNode = elementView.findPortNode(port.id, 'portBody');
elementView.unhighlight(portNode, { highlighter: magnetAvailabilityHighlighter });
});
element.updateInPorts();
}
});
graph.on('remove', function(cell, collection, opt) {
if (!cell.isLink() || !opt.ui) return;
var target = this.getCell(cell.target().id);
if (target instanceof Shape) target.updateInPorts();
});
var shape1 = new Shape();
shape1.resize(120, 100);
shape1.position(200, 100);
shape1.updateInPorts();
shape1.addTo(graph);
var shape2 = new Shape();
shape2.resize(120, 100);
shape2.position(400, 100);
shape2.updateInPorts();
shape2.addTo(graph);
var shape3 = new Shape();
shape3.resize(120, 100);
shape3.position(300, 400);
shape3.updateInPorts();
shape3.addTo(graph);