-
Notifications
You must be signed in to change notification settings - Fork 0
/
demo1.html
226 lines (180 loc) · 7.76 KB
/
demo1.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.css" />
</head>
<body>
<!-- content -->
<div id="myholder"></div>
<div id="paper"></div>
<!-- dependencies -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.3.3/backbone.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jointjs/2.1.0/joint.js"></script>
<!-- code -->
<script type="text/javascript">
var graph = new joint.dia.Graph;
var paper = new joint.dia.Paper({
el: document.getElementById('myholder'),
model: graph,
width: 600,
height: 100,
gridSize: 1
});
var rect = new joint.shapes.standard.Rectangle();
rect.position(100, 30);
rect.resize(100, 40);
rect.attr({
body: {
fill: 'blue'
},
label: {
text: 'Hello',
fill: 'white'
}
});
rect.addTo(graph);
var rect2 = rect.clone();
rect2.translate(300, 0);
rect2.attr('label/text', 'World!');
rect2.addTo(graph);
var link = new joint.shapes.standard.Link();
link.source(rect);
link.target(rect2);
link.addTo(graph);
</script>
<script>
var graph = new joint.dia.Graph();
var paper = new joint.dia.Paper({
el: document.getElementById('paper'),
model: graph,
width: '100%',
height: 600,
gridSize: 5,
snapLinks: true,
linkPinning: false,
defaultLink: new joint.shapes.logic.Wire,
validateConnection: function(vs, ms, vt, mt, e, vl) {
if (e === 'target') {
// target requires an input port to connect
if (!mt || !mt.getAttribute('class') || mt.getAttribute('class').indexOf('input') < 0) return false;
// check whether the port is being already used
var portUsed = this.model.getLinks().some(function(link) {
return (link.id !== vl.model.id &&
link.get('target').id === vt.model.id &&
link.get('target').port === mt.getAttribute('port'));
});
return !portUsed;
} else { // e === 'source'
// source requires an output port to connect
return ms && ms.getAttribute('class') && ms.getAttribute('class').indexOf('output') >= 0;
}
}
});
// zoom the viewport by 50%
paper.scale(1.5,1.5);
function toggleLive(model, signal) {
// add 'live' class to the element if there is a positive signal
model.findView(paper).vel.toggleClass('live', signal > 0);
}
function broadcastSignal(gate, signal) {
// broadcast signal to all output ports
setTimeout(function() {
joint.util.invoke(graph.getConnectedLinks(gate, { outbound: true }), 'set', 'signal', signal);
}, 0);
}
function initializeSignal() {
var signal = Math.random();
// > 0 wire with a positive signal is alive
// < 0 wire with a negative signal means, there is no signal
// 0 none of the above - reset value
// cancel all signals stores in wires
joint.util.invoke(graph.getLinks(), 'set', 'signal', 0);
// remove all 'live' classes
V(paper.viewport).find('.live').forEach(function(vel) {
vel.removeClass('live');
});
graph.getElements().forEach(function(element) {
// broadcast a new signal from every input in the graph
if (element instanceof joint.shapes.logic.Input) {
broadcastSignal(element, signal);
}
});
return signal;
}
// Every logic gate needs to know how to handle a situation, when a signal comes to their ports.
joint.shapes.logic.Gate.prototype.onSignal = function(signal, handler) {
handler(signal);
};
// The repeater delays a signal handling by 400ms
joint.shapes.logic.Repeater.prototype.onSignal = function(signal, handler) {
setTimeout(function() {
handler(signal);
}, 400);
};
// Output element just marks itself as alive.
joint.shapes.logic.Output.prototype.onSignal = function(signal) {
toggleLive(this, signal);
};
// diagramm setup
var gates = {
repeater: new joint.shapes.logic.Repeater({ position: { x: 410, y: 25 }}),
or: new joint.shapes.logic.Or({ position: { x: 550, y: 50 }}),
and: new joint.shapes.logic.And({ position: { x: 550, y: 150 }}),
not: new joint.shapes.logic.Not({ position: { x: 90, y: 140 }}),
nand: new joint.shapes.logic.Nand({ position: { x: 550, y: 250 }}),
nor: new joint.shapes.logic.Nor({ position: { x: 270, y: 190 }}),
xor: new joint.shapes.logic.Xor({ position: { x: 550, y: 200 }}),
xnor: new joint.shapes.logic.Xnor({ position: { x: 550, y: 100 }}),
input: new joint.shapes.logic.Input({ position: { x: 5, y: 45 }}),
output: new joint.shapes.logic.Output({ position: { x: 440, y: 290 }})
};
var wires = [
{ source: { id: gates.input.id, port: 'out' }, target: { id: gates.not.id, port: 'in' }},
{ source: { id: gates.not.id, port: 'out' }, target: { id: gates.nor.id, port: 'in1' }},
{ source: { id: gates.nor.id, port: 'out' }, target: { id: gates.repeater.id, port: 'in' }},
{ source: { id: gates.nor.id, port: 'out' }, target: { id: gates.output.id, port: 'in' }},
{ source: { id: gates.repeater.id, port: 'out' }, target: { id: gates.nor.id, port: 'in2' },
vertices: [{ x: 215, y: 100 }]
}
];
// add gates and wires to the graph
graph.addCells(joint.util.toArray(gates));
joint.util.forIn(wires, function(attributes) {
graph.addCell(paper.getDefaultLink().set(attributes));
});
graph.on('change:source change:target', function(model, end) {
var e = 'target' in model.changed ? 'target' : 'source';
if ((model.previous(e).id && !model.get(e).id) || (!model.previous(e).id && model.get(e).id)) {
// if source/target has been connected to a port or disconnected from a port reinitialize signals
current = initializeSignal();
}
});
graph.on('change:signal', function(wire, signal) {
toggleLive(wire, signal);
var magnitude = Math.abs(signal);
// if a new signal has been generated stop transmitting the old one
if (magnitude !== current) return;
var gate = wire.getTargetElement();
if (gate) {
gate.onSignal(signal, function() {
// get an array of signals on all input ports
var inboundLinks = graph.getConnectedLinks(gate, { inbound: true });
var linksByPorts = joint.util.groupBy(inboundLinks, function(wire) {
return wire.get('target').port;
});
var inputs = joint.util.toArray(linksByPorts).map(function(wires) {
return Math.max.apply(this, joint.util.invoke(wires, 'get', 'signal')) > 0;
});
// calculate the output signal
var output = magnitude * (gate.operation.apply(gate, inputs) ? 1 : -1);
broadcastSignal(gate, output);
});
}
});
// initialize signal and keep its value
var current = initializeSignal();
</script>
</body>
</html>