172 lines
7.0 KiB
HTML
172 lines
7.0 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>Process Flow</title>
|
|
<meta name="description" content="A simple process flow or SCADA diagram editor, simulating equipment monitoring and control." />
|
|
<!-- Copyright 1998-2017 by Northwoods Software Corporation. -->
|
|
<meta charset="UTF-8">
|
|
<script src="../release/go.js"></script>
|
|
<script src="../assets/js/goSamples.js"></script> <!-- this is only for the GoJS Samples framework -->
|
|
<script id="code">
|
|
function init() {
|
|
if (window.goSamples) goSamples(); // init for these samples -- you don't need to call this
|
|
var $ = go.GraphObject.make; // for more concise visual tree definitions
|
|
|
|
myDiagram =
|
|
$(go.Diagram, "myDiagramDiv",
|
|
{
|
|
"grid.visible": true,
|
|
"grid.gridCellSize": new go.Size(30, 20),
|
|
"draggingTool.isGridSnapEnabled": true,
|
|
"resizingTool.isGridSnapEnabled": true,
|
|
"rotatingTool.snapAngleMultiple": 90,
|
|
"rotatingTool.snapAngleEpsilon": 45,
|
|
"undoManager.isEnabled": true
|
|
});
|
|
|
|
// when the document is modified, add a "*" to the title and enable the "Save" button
|
|
myDiagram.addDiagramListener("Modified", function(e) {
|
|
var button = document.getElementById("SaveButton");
|
|
if (button) button.disabled = !myDiagram.isModified;
|
|
var idx = document.title.indexOf("*");
|
|
if (myDiagram.isModified) {
|
|
if (idx < 0) document.title += "*";
|
|
} else {
|
|
if (idx >= 0) document.title = document.title.substr(0, idx);
|
|
}
|
|
});
|
|
|
|
myDiagram.nodeTemplateMap.add("Process",
|
|
$(go.Node, "Auto",
|
|
{ locationSpot: new go.Spot(0.5, 0.5), locationObjectName: "SHAPE",
|
|
resizable: true, resizeObjectName: "SHAPE" },
|
|
new go.Binding("location", "pos", go.Point.parse).makeTwoWay(go.Point.stringify),
|
|
$(go.Shape, "Cylinder1",
|
|
{ name: "SHAPE",
|
|
strokeWidth: 2,
|
|
fill: $(go.Brush, "Linear",
|
|
{ start: go.Spot.Left, end: go.Spot.Right,
|
|
0: "gray", 0.5: "white", 1: "gray" }),
|
|
minSize: new go.Size(50, 50),
|
|
portId: "", fromSpot: go.Spot.AllSides, toSpot: go.Spot.AllSides
|
|
},
|
|
new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)),
|
|
$(go.TextBlock,
|
|
{ alignment: go.Spot.Center, textAlign: "center", margin: 5,
|
|
editable: true },
|
|
new go.Binding("text").makeTwoWay())
|
|
));
|
|
|
|
myDiagram.nodeTemplateMap.add("Valve",
|
|
$(go.Node, "Vertical",
|
|
{ locationSpot: new go.Spot(0.5, 1, 0, -21), locationObjectName: "SHAPE",
|
|
selectionObjectName: "SHAPE", rotatable: true },
|
|
new go.Binding("angle").makeTwoWay(),
|
|
new go.Binding("location", "pos", go.Point.parse).makeTwoWay(go.Point.stringify),
|
|
$(go.TextBlock,
|
|
{ alignment: go.Spot.Center, textAlign: "center", margin: 5, editable: true },
|
|
new go.Binding("text").makeTwoWay(),
|
|
// keep the text upright, even when the whole node has been rotated upside down
|
|
new go.Binding("angle", "angle", function(a) { return a === 180 ? 180 : 0; }).ofObject()),
|
|
$(go.Shape,
|
|
{ name: "SHAPE",
|
|
geometryString: "F1 M0 0 L40 20 40 0 0 20z M20 10 L20 30 M12 30 L28 30",
|
|
strokeWidth: 2,
|
|
fill: $(go.Brush, "Linear", { 0: "gray", 0.35: "white", 0.7: "gray" }),
|
|
portId: "", fromSpot: new go.Spot(1, 0.35), toSpot: new go.Spot(0, 0.35) })
|
|
));
|
|
|
|
myDiagram.linkTemplate =
|
|
$(go.Link,
|
|
{ routing: go.Link.AvoidsNodes, curve: go.Link.JumpGap, corner: 10, reshapable: true, toShortLength: 7 },
|
|
new go.Binding("points").makeTwoWay(),
|
|
// mark each Shape to get the link geometry with isPanelMain: true
|
|
$(go.Shape, { isPanelMain: true, stroke: "black", strokeWidth: 5 }),
|
|
$(go.Shape, { isPanelMain: true, stroke: "gray", strokeWidth: 3 }),
|
|
$(go.Shape, { isPanelMain: true, stroke: "white", strokeWidth: 1, name: "PIPE", strokeDashArray: [10, 10] }),
|
|
$(go.Shape, { toArrow: "Triangle", fill: "black", stroke: null })
|
|
);
|
|
|
|
load();
|
|
|
|
loop(); // animate some flow through the pipes
|
|
}
|
|
|
|
function loop() {
|
|
var diagram = myDiagram;
|
|
setTimeout(function() {
|
|
var oldskips = diagram.skipsUndoManager;
|
|
diagram.skipsUndoManager = true;
|
|
diagram.links.each(function(link) {
|
|
var shape = link.findObject("PIPE");
|
|
var off = shape.strokeDashOffset - 2;
|
|
shape.strokeDashOffset = (off <= 0) ? 20 : off;
|
|
});
|
|
diagram.skipsUndoManager = oldskips;
|
|
loop();
|
|
}, 100);
|
|
}
|
|
|
|
function save() {
|
|
document.getElementById("mySavedModel").value = myDiagram.model.toJson();
|
|
myDiagram.isModified = false;
|
|
}
|
|
function load() {
|
|
myDiagram.model = go.Model.fromJson(document.getElementById("mySavedModel").value);
|
|
}
|
|
</script>
|
|
|
|
</head>
|
|
<body onload="init()">
|
|
<div id="sample">
|
|
<div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:500px"></div>
|
|
<p>
|
|
A <em>process flow diagram</em> is commonly used in chemical and process engineering to indicate the general flow of plant processes and equipment.
|
|
A simple SCADA diagram, with animation of the flow along the pipes, is implemented here.
|
|
</p>
|
|
<p>
|
|
The diagram displays the background grid layer by setting <b>grid.visible</b> to true,
|
|
and also allows snapping to the grid using <a>DraggingTool.isGridSnapEnabled</a>,
|
|
<a>ResizingTool.isGridSnapEnabled</a>, and <a>RotatingTool.snapAngleMultiple</a> alongside <a>RotatingTool.snapAngleEpsilon</a>.
|
|
</p>
|
|
<p>
|
|
The diagram also uses the <b>loop</b> function to animate the links by adjusting the <a>Shape.strokeDashOffset</a> every 100 ms.
|
|
</p>
|
|
<div>
|
|
<div>
|
|
<button id="SaveButton" onclick="save()">Save</button>
|
|
<button onclick="load()">Load</button>
|
|
Diagram Model saved in JSON format:
|
|
</div>
|
|
<textarea id="mySavedModel" style="width:100%;height:300px">
|
|
{ "class": "go.GraphLinksModel",
|
|
"nodeDataArray": [
|
|
{"key":"P1", "category":"Process", "pos":"150 120", "text":"Process"},
|
|
{"key":"P2", "category":"Process", "pos":"330 320", "text":"Tank"},
|
|
{"key":"V1", "category":"Valve", "pos":"270 120", "text":"V1"},
|
|
{"key":"P3", "category":"Process", "pos":"150 420", "text":"Pump"},
|
|
{"key":"V2", "category":"Valve", "pos":"150 280", "text":"VM", "angle":270},
|
|
{"key":"V3", "category":"Valve", "pos":"270 420", "text":"V2", "angle":180},
|
|
{"key":"P4", "category":"Process", "pos":"450 140", "text":"Reserve Tank"},
|
|
{"key":"V4", "category":"Valve", "pos":"390 60", "text":"VA"},
|
|
{"key":"V5", "category":"Valve", "pos":"450 260", "text":"VB", "angle":90}
|
|
],
|
|
"linkDataArray": [
|
|
{"from":"P1", "to":"V1"},
|
|
{"from":"P3", "to":"V2"},
|
|
{"from":"V2", "to":"P1"},
|
|
{"from":"P2", "to":"V3"},
|
|
{"from":"V3", "to":"P3"},
|
|
{"from":"V1", "to":"V4"},
|
|
{"from":"V4", "to":"P4"},
|
|
{"from":"V1", "to":"P2"},
|
|
{"from":"P4", "to":"V5"},
|
|
{"from":"V5", "to":"P2"}
|
|
]}
|
|
</textarea>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|