jointjs
Version:
JavaScript diagramming library
201 lines (168 loc) • 4.94 kB
JavaScript
var graph = new joint.dia.Graph();
var paper = new joint.dia.Paper({
el: document.getElementById('paper'),
width: 800,
height: 350,
gridSize: 10,
defaultAnchor: { name: 'perpendicular' },
defaultConnectionPoint: { name: 'boundary' },
model: graph
});
var pn = joint.shapes.pn;
var pReady = new pn.Place({
position: { x: 140, y: 50 },
attrs: {
'.label': {
'text': 'ready',
'fill': '#7c68fc' },
'.root': {
'stroke': '#9586fd',
'stroke-width': 3
},
'.tokens > circle': {
'fill': '#7a7e9b'
}
},
tokens: 1
});
var pIdle = pReady.clone()
.attr('.label/text', 'idle')
.position(140, 260)
.set('tokens', 2);
var buffer = pReady.clone()
.position(350, 160)
.set('tokens', 12)
.attr({
'.label': {
'text': 'buffer'
},
'.alot > text': {
'fill': '#fe854c',
'font-family': 'Courier New',
'font-size': 20,
'font-weight': 'bold',
'ref-x': 0.5,
'ref-y': 0.5,
'y-alignment': -0.5,
'transform': null
}
});
var cAccepted = pReady.clone()
.attr('.label/text', 'accepted')
.position(550, 50)
.set('tokens', 1);
var cReady = pReady.clone()
.attr('.label/text', 'accepted')
.position(560, 260)
.set('ready', 3);
var pProduce = new pn.Transition({
position: { x: 50, y: 160 },
attrs: {
'.label': {
'text': 'produce',
'fill': '#fe854f'
},
'.root': {
'fill': '#9586fd',
'stroke': '#9586fd'
}
}
});
var pSend = pProduce.clone()
.attr('.label/text', 'send')
.position(270, 160);
var cAccept = pProduce.clone()
.attr('.label/text', 'accept')
.position(470, 160);
var cConsume = pProduce.clone()
.attr('.label/text', 'consume')
.position(680, 160);
function link(a, b) {
return new pn.Link({
source: { id: a.id, selector: '.root' },
target: { id: b.id, selector: '.root' },
attrs: {
'.connection': {
'fill': 'none',
'stroke-linejoin': 'round',
'stroke-width': '2',
'stroke': '#4b4a67'
}
}
});
}
graph.addCell([pReady, pIdle, buffer, cAccepted, cReady, pProduce, pSend, cAccept, cConsume]);
graph.addCell([
link(pProduce, pReady),
link(pReady, pSend),
link(pSend, pIdle),
link(pIdle, pProduce),
link(pSend, buffer),
link(buffer, cAccept),
link(cAccept, cAccepted),
link(cAccepted, cConsume),
link(cConsume, cReady),
link(cReady, cAccept)
]);
function fireTransition(t, sec) {
var inbound = graph.getConnectedLinks(t, { inbound: true });
var outbound = graph.getConnectedLinks(t, { outbound: true });
var placesBefore = inbound.map(function(link) {
return link.getSourceElement();
});
var placesAfter = outbound.map(function(link) {
return link.getTargetElement();
});
var isFirable = true;
placesBefore.forEach(function(p) {
if (p.get('tokens') === 0) {
isFirable = false;
}
});
if (isFirable) {
placesBefore.forEach(function(p) {
// Let the execution finish before adjusting the value of tokens. So that we can loop over all transitions
// and call fireTransition() on the original number of tokens.
setTimeout(function() {
p.set('tokens', p.get('tokens') - 1);
}, 0);
var links = inbound.filter(function(l) {
return l.getSourceElement() === p;
});
links.forEach(function(l) {
var token = V('circle', { r: 5, fill: '#feb662' });
l.findView(paper).sendToken(token, sec * 1000);
});
});
placesAfter.forEach(function(p) {
var links = outbound.filter(function(l) {
return l.getTargetElement() === p;
});
links.forEach(function(l) {
var token = V('circle', { r: 5, fill: '#feb662' });
l.findView(paper).sendToken(token, sec * 1000, function() {
p.set('tokens', p.get('tokens') + 1);
});
});
});
}
}
function simulate() {
var transitions = [pProduce, pSend, cAccept, cConsume];
transitions.forEach(function(t) {
if (Math.random() < 0.7) {
fireTransition(t, 1);
}
});
return setInterval(function() {
transitions.forEach(function(t) {
if (Math.random() < 0.7) {
fireTransition(t, 1);
}
});
}, 2000);
}
var simulationId = simulate();
function stopSimulation(simulationId) {
clearInterval(simulationId);
}