This commit is contained in:
jusax23 2023-06-22 12:41:11 +02:00
commit 806baf0043
Signed by: jusax23
GPG key ID: 499E2AA870C1CD41
3 changed files with 417 additions and 0 deletions

166
graphics.js Normal file
View file

@ -0,0 +1,166 @@
class Tragable {
initTrag(element, cb) {
let selected = false;
element.addEventListener('mousedown', () => {
selected = true;
});
svg.addEventListener('mousemove', event => {
if (selected) cb(event.x, event.y);
});
svg.addEventListener('mouseup', () => {
selected = false;
});
svg.addEventListener('mouseleave', event => {
selected = false;
});
}
}
class SVGNode extends Tragable {
group;
circle;
circleText;
aboveText;
constructor(node) {
super();
// Create the group element
this.group = document.createElementNS(svgNamespace, 'g');
this.group.classList.add("PNode");
this.group.setAttribute('transform', `translate(${node.x}, ${node.y})`);
// Create the circle
this.circle = document.createElementNS(svgNamespace, 'circle');
this.circle.setAttribute('cx', '0');
this.circle.setAttribute('cy', '0');
this.circle.setAttribute('r', '25');
// Create the text inside the circle
this.circleText = document.createElementNS(svgNamespace, 'text');
this.circleText.classList.add("circleText");
this.circleText.setAttribute('x', '0');
this.circleText.setAttribute('y', '5');
this.circleText.textContent = '0/1';
// Create the text above the circle
this.aboveText = document.createElementNS(svgNamespace, 'text');
this.aboveText.classList.add("aboveText");
this.aboveText.setAttribute('x', '0');
this.aboveText.setAttribute('y', '-35');
this.aboveText.textContent = node.name;
// Append the circle and texts to the group
this.group.appendChild(this.circle);
this.group.appendChild(this.circleText);
this.group.appendChild(this.aboveText);
this.initTrag(this.group, (x, y) => node.updatePosition(x, y));
}
appendIt(svg) {
svg.appendChild(this.group);
}
translate(x, y) {
this.group.setAttribute('transform', `translate(${x}, ${y})`);
}
setName(name) {
this.aboveText.textContent = name;
}
setMarks(amount, max) {
this.circleText.textContent = `${amount}/${max}`;
}
}
class SVGTRansition extends Tragable {
group;
rect;
rectText;
constructor(trans) {
super();
// Create the group element
this.group = document.createElementNS(svgNamespace, 'g');
this.group.classList.add("PTransition");
this.group.setAttribute('transform', `translate(${trans.x}, ${trans.y})`);
// Create the circle
this.rect = document.createElementNS(svgNamespace, 'rect');
this.rect.setAttribute('x', '-12.5');
this.rect.setAttribute('y', '-25');
this.rect.setAttribute('height', '50');
this.rect.setAttribute('width', '25');
// Create the text inside the circle
this.rectText = document.createElementNS(svgNamespace, 'text');
this.rectText.classList.add("rectText");
this.rectText.setAttribute('x', '-5');
this.rectText.setAttribute('y', '-35');
this.rectText.textContent = trans.name;
// Append the circle and texts to the group
this.group.appendChild(this.rect);
this.group.appendChild(this.rectText);
this.initTrag(this.group, (x, y) => trans.updatePosition(x, y));
}
appendIt(svg) {
svg.appendChild(this.group);
}
translate(x, y) {
this.group.setAttribute('transform', `translate(${x}, ${y})`);
}
setName(name) {
this.aboveText.textContent = name;
}
setCanFire(can){
if (can)this.group.classList.add("canFire");
else this.group.classList.remove("canFire");
}
}
class SVGArrow {
group;
lineText;
line;
from;
to;
constructor(from, to) {
this.from = from;
this.to = to;
this.group = document.createElementNS(svgNamespace, 'g');
this.group.classList.add("PEdge");
this.line = document.createElementNS(svgNamespace, 'line');
this.line.setAttribute('marker-end', "url(#arrowhead)");
this.group.setAttribute('transform', `translate(0, 0)`);
// Create the text inside the circle
this.lineText = document.createElementNS(svgNamespace, 'text');
this.lineText.classList.add("lineText");
this.lineText.setAttribute('x', '0');
this.lineText.setAttribute('y', '0');
this.lineText.textContent = "";
this.group.appendChild(this.line);
this.group.appendChild(this.lineText);
this.updatePosition();
}
updatePosition() {
let dx = this.to.x - this.from.x;
let dy = this.to.y - this.from.y;
let l = Math.sqrt(dx * dx + dy * dy);
dx /= l;
dy /= l;
this.line.setAttribute('x1', this.from.x + dx * 30);
this.line.setAttribute('y1', this.from.y + dy * 30);
this.line.setAttribute('x2', this.to.x - dx * 40);
this.line.setAttribute('y2', this.to.y - dy * 40);
}
appendIt(svg) {
svg.appendChild(this.group);
}
}

91
index.html Normal file
View file

@ -0,0 +1,91 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body,
html,
svg {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
font-family: 'Comic Sans MS', 'Chalkboard SE', 'Comic Neue', sans-serif;
}
svg {
user-select: none;
}
svg {
font-size: 1rem;
}
.PNode circle {
fill: #f1c40f;
stroke: #3498db;
stroke-width: 0.5rem;
}
.PNode circle {
fill: #f1c40f;
stroke: #3498db;
stroke-width: 0.5rem;
}
.PNode .circleText {
text-anchor: middle;
fill: black;
}
.PNode .aboveText {
text-anchor: middle;
fill: black;
}
.PNode .rectText {
text-anchor: middle;
fill: black;
}
.PTransition rect {
fill: #c0392b;
stroke: #34495e;
stroke-width: 0.2rem;
}
.PTransition.canFire rect{
fill: #27ae60;
}
.PEdge line {
stroke: gray;
stroke-width: 4;
}
#arrowhead {
z-index: -1;
fill: gray;
stroke-width: 2;
}
</style>
</head>
<body>
<svg viewBox="0 0 500 200" xmlns="http://www.w3.org/2000/svg">
<defs>
<marker id="arrowhead" markerWidth="5" markerHeight="3.5" refX="2.5" refY="1.75" orient="auto">
<polygon points="0 0, 5 1.75, 0 3.5" />
</marker>
</defs>
</svg>
<script>const svgNamespace = 'http://www.w3.org/2000/svg';</script>
<script src="graphics.js"></script>
<script src="main.js"></script>
</body>
</html>

160
main.js Normal file
View file

@ -0,0 +1,160 @@
let svg = document.querySelector("svg");
let nods = document.createElementNS(svgNamespace, 'g');
let arrows = document.createElementNS(svgNamespace, 'g');
svg.appendChild(arrows);
svg.appendChild(nods);
class Edge {
renderedElement;
end;
trans;
inEdge;
dimension = 1;
constructor(end, trans, inEdge = true) {
this.end = end;
this.trans = trans;
this.inEdge = inEdge;
this.renderedElement = inEdge ? new SVGArrow(end, trans) : new SVGArrow(trans, end);
this.renderedElement.appendIt(arrows);
end.updateList.push(this);
}
canSuck() {
return this.end.marks >= this.dimension;
}
suck() {
this.end.marks -= this.dimension;
this.end.updatePoints();
}
canPush() {
return this.end.capacity >= this.end.marks + this.dimension;
}
push() {
this.end.marks += this.dimension;
this.end.updatePoints();
}
updatePosition() {
this.renderedElement.updatePosition();
}
}
class Node {
renderedElement;
x = 0;
y = 0;
name;
capacity = 1;
marks = 0;
updateList = [];
constructor(name, x, y) {
this.name = name;
this.x = x;
this.y = y;
this.renderedElement = new SVGNode(this);
this.renderedElement.appendIt(nods);
}
updatePoints() {
this.renderedElement.setMarks(this.marks, this.capacity);
}
updatePosition(x, y) {
this.x = x;
this.y = y;
this.renderedElement.translate(x, y);
for (const elem of this.updateList) {
elem.updatePosition();
}
}
}
class Transition {
renderedElement;
name = "noname";
inEdges = [];
outEdges = [];
x;
y;
constructor(name, x, y) {
this.name = name;
this.x = x;
this.y = y;
this.renderedElement = new SVGTRansition(this);
this.renderedElement.appendIt(nods);
}
canFire() {
for (const inE of this.inEdges) {
if (!inE.canSuck()) {
this.renderedElement.setCanFire(false);
return false;
}
}
for (const outE of this.outEdges) {
if (!outE.canPush()) {
this.renderedElement.setCanFire(false);
return false;
}
}
this.renderedElement.setCanFire(true);
return true;
}
fire() {
if (!this.canFire()) return false;
for (const inE of this.inEdges) {
inE.suck();
}
for (const outE of this.outEdges) {
outE.push();
}
return true;
}
updatePosition(x, y) {
this.x = x;
this.y = y;
this.renderedElement.translate(x, y);
for (const inE of this.inEdges) {
inE.updatePosition();
}
for (const outE of this.outEdges) {
outE.updatePosition();
}
}
}
let transitions = [];
let nodes = [];
function loop() {
for (const trans of transitions) {
console.log(trans.name, trans.fire());
}
update();
}
function update() {
for (const nod of nodes) {
nod.updatePoints();
}
for (const trans of transitions) {
trans.canFire();
}
}
window.onresize = () => {
svg.setAttribute("viewBox", `0 0 ${window.innerWidth} ${window.innerHeight}`);
}
window.onresize();
let n1 = new Node("n1", 100, 100);
let n2 = new Node("n2", 100, 300);
let t1 = new Transition("t1", 100, 200);
t1.inEdges.push(new Edge(n1, t1, true))
t1.outEdges.push(new Edge(n2, t1, false));
nodes.push(n1, n2);
transitions.push(t1);