gojs
Version:
Interactive diagrams, charts, and graphs, such as trees, flowcharts, orgcharts, UML, BPMN, or business diagrams
746 lines (743 loc) • 31.7 kB
HTML
<html>
<head>
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-1506307-6"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-1506307-6');
</script>
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Electric Circuit</title>
<meta name="description" content="" />
<meta charset="UTF-8">
<script src="./go.js"></script>
<script src="./goeditor-data-interaction.js"></script>
<script src="./goeditor-setup.js"></script>
<script src="./storage/gcs.js"></script>
<script src="https://apis.google.com/js/api.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/dropbox.js/2.5.7/Dropbox-sdk.min.js"></script>
<script src="https://js.live.net/v7.2/OneDrive.js"></script>
<script type="text/javascript" src="https://www.dropbox.com/static/api/2/dropins.js" id="dropboxjs" data-app-key="3sm2ko6q7u1gbix"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
<script src="./DataInspector.js"></script>
<script src="../../extensions/figures.js"></script>
<script src="./WireDragTool.js"></script>
<link rel="stylesheet" type="text/css" href="./DataInspector.css" />
<link rel="stylesheet" type="text/css" href="./storage/GoCloudStorageUI.css" />
<link rel="stylesheet" type="text/css" href="./goeditor.css" />
<script>
function init() {
setupEditorApplication();
nodeGenerationMap = new go.Map();
categories = [""];
// Circuit Figures
// Figures for different shaped lines
go.Shape.defineFigureGenerator("Off", function (shape, w, h) { // 1 Connector Switch Up, same as line2
var geo = new go.Geometry(go.Geometry.Line);
geo.startX = w;
geo.startY = 0;
geo.endX = 0;
geo.endY = h;
return geo;
});
go.Shape.defineFigureGenerator("On", function (shape, w, h) { // 1 Connector Switch Down
var geo = new go.Geometry(go.Geometry.Line);
geo.startX = w;
geo.startY = h;
geo.endX = 0;
geo.endY = h;
return geo;
});
go.Shape.defineFigureGenerator("Up", function (shape, w, h) { // 2 Connector Switch Up
var geo = new go.Geometry(go.Geometry.Line);
geo.startX = 0;
geo.startY = h / 2;
geo.endX = w;
geo.endY = 0;
return geo;
});
go.Shape.defineFigureGenerator("Down", function (shape, w, h) { // 2 Connector Switch Down
var geo = new go.Geometry(go.Geometry.Line);
geo.startX = 0;
geo.startY = h / 2;
geo.endX = w;
geo.endY = h;
return geo;
});
go.Shape.defineFigureGenerator("Ground2", function (shape, w, h) { // Different ground figure than one predefined in figures.js
var geo = new go.Geometry();
var fig = new go.PathFigure(0, 0, false);
geo.add(fig);
fig.add(new go.PathSegment(go.PathSegment.Line, w, 0));
fig.add(new go.PathSegment(go.PathSegment.Move, w / 8, h / 4));
fig.add(new go.PathSegment(go.PathSegment.Line, 7 * w / 8, h / 4));
fig.add(new go.PathSegment(go.PathSegment.Move, w / 4, h / 2));
fig.add(new go.PathSegment(go.PathSegment.Line, 3 * w / 4, h / 2));
return geo;
});
go.Shape.defineFigureGenerator("Transistor", function (shape, w, h) {
var geo = new go.Geometry();
var KAPPA = 4 * ((Math.sqrt(2) - 1) / 3);
var cpOffset = KAPPA * .5;
var radius = .5;
var centerx = .5;
var centery = .5;
var fig = new go.PathFigure((centerx - radius) * w, centery * h, false);
geo.add(fig);
// circle
fig.add(new go.PathSegment(go.PathSegment.Bezier, centerx * w,
(centery - radius) * h, (centerx - radius) * w, (centery - cpOffset) * h,
(centerx - cpOffset) * w, (centery - radius) * h));
fig.add(new go.PathSegment(go.PathSegment.Bezier, (centerx + radius) * w, centery * h,
(centerx + cpOffset) * w, (centery - radius) * h,
(centerx + radius) * w, (centery - cpOffset) * h));
fig.add(new go.PathSegment(go.PathSegment.Bezier, centerx * w, (centery + radius) * h,
(centerx + radius) * w, (centery + cpOffset) * h,
(centerx + cpOffset) * w, (centery + radius) * h));
fig.add(new go.PathSegment(go.PathSegment.Bezier, (centerx - radius) * w, centery * h,
(centerx - cpOffset) * w, (centery + radius) * h,
(centerx - radius) * w, (centery + cpOffset) * h));
// vertical middle-line
fig.add(new go.PathSegment(go.PathSegment.Move, w / 4, h / 4));
fig.add(new go.PathSegment(go.PathSegment.Line, w / 4, 3 * h / 4));
// line middle to top-right
fig.add(new go.PathSegment(go.PathSegment.Move, w / 4, 3 * h / 8));
fig.add(new go.PathSegment(go.PathSegment.Line, 7 * w / 8, h / 8));
// line middle to bottom-right
fig.add(new go.PathSegment(go.PathSegment.Move, w / 4, 5 * h / 8));
fig.add(new go.PathSegment(go.PathSegment.Line, 7 * w / 8, 7 * h / 8));
// line middle to left
fig.add(new go.PathSegment(go.PathSegment.Move, w / 4, h / 2));
fig.add(new go.PathSegment(go.PathSegment.Line, 0, h / 2));
return geo;
});
go.Shape.defineFigureGenerator("Fuse", function (shape, w, h) { // Fuse
var geo = new go.Geometry();
var fig = new go.PathFigure(0, 0, false);
geo.add(fig);
// box
fig.add(new go.PathSegment(go.PathSegment.Move, w / 8, h / 4));
fig.add(new go.PathSegment(go.PathSegment.Line, 7 * w / 8, h / 4));
fig.add(new go.PathSegment(go.PathSegment.Line, 7 * w / 8, 3 * h / 4));
fig.add(new go.PathSegment(go.PathSegment.Line, w / 8, 3 * h / 4));
fig.add(new go.PathSegment(go.PathSegment.Line, w / 8, h / 4));
// line across, may change to wave
fig.add(new go.PathSegment(go.PathSegment.Move, 0, h / 2));
fig.add(new go.PathSegment(go.PathSegment.Line, w, h / 2));
return geo;
});
// General Styling
function nodeStyle() {
return [new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
new go.Binding("isShadowed", "isSelected").ofObject(), new go.Binding("angle").makeTwoWay(),
{
selectionAdorned: false,
shadowOffset: new go.Point(0, 0),
shadowBlur: 15,
shadowColor: "red",
rotatable: true,
toolTip: sharedToolTip
}];
}
function shapeStyle() {
return {
name: "NODESHAPE",
desiredSize: new go.Size(40, 40),
strokeWidth: 2,
fill: "lightgray",
stroke: "darkslategray"
};
}
function portStyle(input) {
return {
desiredSize: new go.Size(5, 5),
fill: "black",
fromSpot: go.Spot.Right,
fromLinkable: !input,
toSpot: go.Spot.Left,
toLinkable: input,
cursor: "pointer"
};
}
myDiagram.nodeTemplate = // Generic nodeTemplate to make junctions
$(go.Node, "Auto", nodeStyle(),
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify), new go.Binding("segmentIndex").makeTwoWay(), new go.Binding("segmentFraction").makeTwoWay(),
{ name: "junction" },
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "inout", toSpot: go.Spot.AllSides, fromSpot: go.Spot.AllSides, fromLinkable: true })
);
function initialProperties(e) {
e.subject.each(function (node) {
if (node.category === "dcvoltagesource" && node.data.Voltage === undefined) node.data.Voltage = 1;
if (node.category === "resistor" && node.data.Resistance === undefined) node.data.Resistance = 1;
if (node.category === "capacitor" && node.data.Capacitance === undefined) node.data.Capacitance = 1;
if (node.category === "inductor" && node.data.Inductance === undefined) node.data.Inductance = 1;
if (node.category === "acvoltagesource" && node.data.Amplitude === undefined) node.data.Amplitude = 1; node.data.Interval = 100; node.data.Count = 0; node.data.Color = 'black';
});
}
myDiagram.addDiagramListener("ExternalObjectsDropped", function (e) { initialProperties(e); });
myDiagram.addDiagramListener("ClipboardPasted", function (e) { initialProperties(e); });
myDiagram.addDiagramListener("BackgroundDoubleClicked", function (e) {
e.diagram.startTransaction("create junction");
var model = myDiagram.model;
var pos = e.diagram.lastInput.documentPoint;
var label = { category: "junction" }; // Create empty NodeData
model.addNodeData(label);
var node = e.diagram.findNodeForData(label);
node.location = pos;
e.diagram.commitTransaction("create junction");
});
// Shows tooltip when hover over node
var sharedToolTip =
$(go.Adornment, "Auto",
$(go.Shape, "RoundedRectangle", { fill: "lightyellow" }),
$(go.TextBlock, { margin: 2 },
new go.Binding("text", "", function (d) { return d.category; })));
// Node templates
var dcVoltTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "DCvoltageSource", shapeStyle()),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent" }), // Creates invisible background box so easier to click on
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0.02, 0.5) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(0.98, 0.5) })
);
var acVoltTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "ACvoltageSource", shapeStyle()),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent" }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0.5, 0.99), toSpot: go.Spot.Bottom }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(0.5, 0.01), fromSpot: go.Spot.Top })
);
var capacitorTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Capacitor", shapeStyle()),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent" }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0.02, 0.5) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(0.98, 0.5) })
);
var resistorTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Resistor", shapeStyle(),
{ desiredSize: new go.Size(55, 35) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0, 0.5) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(.7, .5) })
);
var lightbulbTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Circle", shapeStyle()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: go.Spot.Left }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: go.Spot.Right })
);
var diodeTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Diode", shapeStyle()),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent" }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0.02, 0.5) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(0.98, 0.5) })
);
var inductorTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Inductor", shapeStyle()),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0.05, 1) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(0.95, 1) })
);
var transistorTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Transistor", shapeStyle()),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent" }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "collector", alignment: new go.Spot(0.02, 0.5), toSpot: go.Spot.Left }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "base", alignment: new go.Spot(0.86, 0.15), toSpot: go.Spot.TopRight }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "emitter", alignment: new go.Spot(0.86, 0.85), fromSpot: go.Spot.BottomRight })
);
var switchTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Off", shapeStyle(), new go.Binding("figure", "state").makeTwoWay(),
{ desiredSize: new go.Size(50, 20) }),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent", desiredSize: new go.Size(50, 20) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0, 0.95) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: new go.Spot(1, 0.95) }),
{ // If double clicked, it will swap the switch from on and off
doubleClick: function (e, obj) {
e.diagram.startTransaction("Toggle Switch");
var shp = obj.findObject("NODESHAPE");
if (shp.figure == "Off") // Off to on
shp.figure = "On";
else // On to off
shp.figure = "Off";
e.diagram.commitTransaction("Toggle Switch");
}
}
);
var switch2Temp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Up", shapeStyle(), new go.Binding("figure", "state").makeTwoWay(),
{ desiredSize: new go.Size(50, 20) }),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent", desiredSize: new go.Size(50, 20) }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: new go.Spot(0, 0.5) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out1", name: "out1", alignment: new go.Spot(1, 0.05) }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out2", name: "out2", alignment: new go.Spot(1, 0.95) }),
{ // If double clicked, it will swap the switch from top to bottom
doubleClick: function (e, obj) {
e.diagram.startTransaction("Toggle Switch");
var shp = obj.findObject("NODESHAPE");
if (shp.figure == "Up") // Up to down
shp.figure = "Down";
else // Down to up
shp.figure = "Up";
e.diagram.commitTransaction("Toggle Switch");
}
}
);
var groundTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Ground", shapeStyle()),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent" }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "", alignment: go.Spot.Top, toSpot: go.Spot.Top })
);
var fuseTemp =
$(go.Node, "Spot", nodeStyle(),
$(go.Shape, "Fuse", shapeStyle()),
$(go.Shape, "Rectangle", shapeStyle(),
{ fill: "transparent", stroke: "transparent" }),
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "in", alignment: go.Spot.Left }),
$(go.Shape, "Rectangle", portStyle(false),
{ portId: "out", alignment: go.Spot.Right })
);
var junTemp =
$(go.Node, "Spot", nodeStyle(), { rotatable: false },
$(go.Shape, "Rectangle", shapeStyle(),
{ desiredSize: new go.Size(15, 15), fill: "transparent", stroke: "transparent" }), // transparent box that makes junctions easier to click on
$(go.Shape, "Rectangle", portStyle(true),
{ portId: "inout", toSpot: go.Spot.AllSides, fromSpot: go.Spot.AllSides, fromLinkable: true }), // linkable in and out of this port
);
function createJunction(e, obj) { // Creates Junction node when user double clicks on a link
var adorn = obj.part;
e.handled = true;
e.diagram.startTransaction("Link Label");
var model = myDiagram.model;
var pos = e.documentPoint;
var posX = pos.x;
var posY = pos.y;
var label = {}; // Create empty NodeData
model.addNodeData(label);
var node = e.diagram.findNodeForData(label); // Finds the created node from the NodeData
node.labeledLink = obj; // and sets the labeledLink to the link that was clicked on
index = obj.findClosestSegment(pos); // Finds the index
node.segmentIndex = index;
var startPoint = obj.points.elt(index); // Grabs the point at the start and end of the segment
var endPoint = obj.points.elt(index + 1);
// Finds dif between pos and startPoint and divided by dif of endPoint and startPoint
if (startPoint.x - endPoint.x === 0) // Segment is horizontal
node.segmentFraction = (pos.y - startPoint.y) / (endPoint.y - startPoint.y);
else // Segment is vertical
node.segmentFraction = (pos.x - startPoint.x) / (endPoint.x - startPoint.x);
e.diagram.commitTransaction("Link Label");
}
// Link template
myDiagram.linkTemplate =
$(go.Link,
{
routing: go.Link.AvoidsNodes,
curve: go.Link.JumpOver,
corner: 3,
relinkableFrom: true, relinkableTo: true,
selectionAdorned: false, // Links are not adorned when selected so that their color remains visible.
shadowOffset: new go.Point(0, 0), shadowBlur: 5, shadowColor: "red",
resizable: true,
reshapable: true,
name: "",
},
new go.Binding("isShadowed", "isSelected").ofObject(),
$(go.Shape,
{ name: "SHAPE", strokeWidth: 2, stroke: "black" }),
{
doubleClick: function (e, obj) {
createJunction(e, obj);
}
}
);
// Adds the templates to the map
myDiagram.nodeTemplateMap.add("dcvoltagesource", dcVoltTemp);
myDiagram.nodeTemplateMap.add("acvoltagesource", acVoltTemp);
myDiagram.nodeTemplateMap.add("capacitor", capacitorTemp);
myDiagram.nodeTemplateMap.add("resistor", resistorTemp);
myDiagram.nodeTemplateMap.add("inductor", inductorTemp);
myDiagram.nodeTemplateMap.add("lightbulb", lightbulbTemp);
myDiagram.nodeTemplateMap.add("diode", diodeTemp);
myDiagram.nodeTemplateMap.add("transistor", transistorTemp);
myDiagram.nodeTemplateMap.add("switch", switchTemp);
myDiagram.nodeTemplateMap.add("switch2", switch2Temp);
myDiagram.nodeTemplateMap.add("ground", groundTemp);
myDiagram.nodeTemplateMap.add("fuse", fuseTemp);
myDiagram.nodeTemplateMap.add("junction", junTemp);
var palette = new go.Palette("palette"); // Creates a new Palette in the HTML DIV element "palette"
// Copies the template to the palette
palette.nodeTemplateMap = myDiagram.nodeTemplateMap;
// Adds the nodes to the palette
palette.model.nodeDataArray = [
{ category: "dcvoltagesource" },
{ category: "acvoltagesource" },
{ category: "capacitor" },
{ category: "resistor" },
{ category: "inductor" },
{ category: "lightbulb" },
{ category: "diode" },
{ category: "transistor" },
{ category: "switch" },
{ category: "switch2" },
{ category: "ground" },
{ category: "fuse" },
// { category: "junction" }
];
// Generates links and makes it so links connect by ports
myDiagram.model =
$(go.GraphLinksModel,
{
linkLabelKeysProperty: "junctions",
linkFromPortIdProperty: "fromPort",
linkToPortIdProperty: "toPort"
});
loop();
inspector = new Inspector('myInspectorDiv', myDiagram,
{
properties: {
'key': { show: false },
'segmentIndex': { show: false }, 'segmentFraction': { show: false },
'name': { show: Inspector.showIfNode },
'category': { show: Inspector.showIfNode, readOnly: true },
'angle': {
show: Inspector.showIfPresent,
type: 'select',
choices: function (node, propName) {
return ['0', '90', '180', '270'];
}
},
'loc': { show: Inspector.showIfNode },
'Voltage': { show: Inspector.showIfPresent },
'Resistance': { show: Inspector.showIfPresent },
'Capacitance': { show: Inspector.showIfPresent },
'Inductance': { show: Inspector.showIfPresent },
'Amplitude': { show: Inspector.showIfPresent },
'Interval': { show: Inspector.showIfPresent },
'state': {
show: Inspector.showIfPresent,
type: 'select',
choices: function (node, propName) {
if (node.category === 'switch') return ['On', 'Off'];
else if (node.category === 'switch2') return ['Up', 'Down'];
}
}
}
}
);
myDiagram.toolManager.mouseMoveTools.insertAt(2,
$(WireDragTool, {
isEnabled: false, // disabled by the checkbox
delay: 0, // always canStart(), so PanningTool never gets the chance to run
}));
/*12DY@9dkd)dk*/
} // end init
</script>
</head>
<body onload="init();">
<div>
<nav>
<span id="currentStorageSpan"></span>
<ul id="fileMenus">
<li>
<a href="#">File</a>
<ul>
<li><a href="#" onclick="handlePromise('New')">New <p class="shortcut">(Ctrl + D)</p></a></li>
<li><a href="#" onclick="handlePromise('Load')">Open... <p class="shortcut">(Ctrl + O)</p></a></li>
<li><a href="#" onclick="handlePromise('Save')">Save <p class="shortcut">(Ctrl + S)</p></a></li>
<li><a href="#" onclick="handlePromise('SaveAs')">Save As...</a></li>
<li><a href="#" onclick="handlePromise('Delete')">Remove... <p class="shortcut">(Ctrl + R)</p></a></li>
<li><a href="#">Import Data From >>></a>
<ul>
<li><a href="#" onclick="authorizeGoogleUserForDataImport()">Google Sheet</a></li>
<li><a href="#" onclick="document.getElementById('file-input').click()">Local CSV File</a>
</ul>
</li>
<li><a href="#" onclick="makeDiagramImage()">Export PNG</a></li>
<li><a href="#" onclick="updateCurrentStorageSpan()">Change Storage Service</a></li>
</ul>
</li>
</ul>
<p id="isAutoSavingP"><input type="checkbox" id="isAutoSavingCheckbox" unchecked /> <label for="isAutoSavingCheckbox">Autosave Enabled</label></p>
<p id="ge-header">Electric Circuit v1.0</p>
<div id="ge-filename">(Unsaved file)</div>
</nav>
<input type="file" id="file-input" style="display: none;" />
<div id="container" style="display: flex;">
<div id="palette" style="border: solid 1px black; width: 115px; height:798px; float: left;"></div>
<div id="myDiagramDiv" style="background: #969699; width: 100%; height:800px; float: left;"></div>
<div id="ge-inspector-div" style="background: #212121; flex-grow: 1; height: 800px; float: right;">
<div id="myInspectorDiv" class="inspector">
</div>
</div>
</div>
<div id="ge-footer">
<span>Built with the <a href="https://gojs.net">GoJS Diagramming Library</a>, by <a href="https://nwoods.com"> Northwoods Software</a>.</span>
</div>
<p>
This editor allows one to build interactive electric circuits. Drag and drop parts from the palette or double click on the background to create a junction.
</p>
<p>
Drag from the preset ports on the parts to another part's ports to draw wires. Double-click on wires to create a junction on the wire. Hit W to toggle the wire creating tool
</p>
<p>
Select an element to change its properties based on what part it is. Also the ability to double click switches to change their state, or edit them through data inspector.
</p>
<script>
function loop() {
setTimeout(function () {
updateStatus();
loop();
}, 25); // Updates every 25 milliseconds
}
function updateStatus() {
var oldskip = myDiagram.skipsUndoManager;
myDiagram.skipsUndoManager = true;
myDiagram.nodes.each(function (node) { // Does the volt sources first
if (node.category == "dcvoltagesource") {
doDCVolt(node);
}
if (node.category == "acvoltagesource") {
doACVolt(node);
}
});
myDiagram.nodes.each(function (node) {
if (node.name === "junction") doJunction(node); // special case for labellink junctions
switch (node.category) {
case "capacitor": doAll(node); break;
case "resistor": doAll(node); break;
case "inductor": doAll(node); break;
case "switch": doSwitch(node); break;
case "switch2": doSwitch2(node); break;
case "diode": doAll(node); break;
case "lightbulb": doLightBulb(node); break;
case "transistor": doAll(node); break;
case "ground": doGround(node); break;
case "fuse": doAll(node); break;
case "junction": doJunction2(node); break;
case "dcvoltsource": break;
case "acvoltsource": break;
}
})
myDiagram.skipsUndoManager = oldskip;
}
function uniqueChildren(link, children) { // fills up a set with all the unique children of the given link, used for determining if it loops back to itself
link.labelNodes.each(function (nodes) { // checks all the labelnodes for a child branch back to the volt source
if (!children.has(nodes.data.key)) {
children.add(nodes.data.key);
nodes.findLinksOutOf().each(function (links) {
uniqueChildren(links, children);
});
}
});
var node = link.toNode;
if (!children.has(node.data.key)) {
children.add(node.data.key);
if (node.category != "junction" && node.findObject("NODESHAPE") != null) {
if (node.findObject("NODESHAPE").figure == "Up") { // only checks out1 when switch is up
node.findLinksOutOf("out1").each(function (links) {
uniqueChildren(links, children);
});
} else if (node.findObject("NODESHAPE").figure == "Down") { // only checks out2 when switch is down
node.findLinksOutOf("out2").each(function (links) {
uniqueChildren(links, children);
});
} else if (node.findObject("NODESHAPE").figure != "Off") { // only checks when switch is down
node.findLinksOutOf().each(function (links) {
uniqueChildren(links, children);
});
}
} else { // all other cases
node.findLinksOutOf().each(function (links) {
uniqueChildren(links, children);
});
}
}
}
function setOutputLinks(node, color) { // Changes the output links that is connected to a node
var key = node.data.key;
node.findLinksOutOf().each(function (link) {
var children = new Set([]);
uniqueChildren(link, children);
if (children.has(key))
link.findObject("SHAPE").stroke = color;
else
link.findObject("SHAPE").stroke = "black";
});
}
function linkIsOn(link) { // Determines if previous wire is on or off
return link.findObject("SHAPE").stroke === "blue";
}
function setNodeColor(node, color) {
if (node.findObject("NODESHAPE") == null) return;
if (node.findLinksInto().first() === null) { // Used when deleting the last wire into a node to avoid it continuing to appear on
node.findObject("NODESHAPE").fill = "red";
node.findObject("NODESHAPE").stroke = "red";
}
node.findLinksInto().each(function (link) {
if (link.findObject("SHAPE").stroke === color) {
node.findObject("NODESHAPE").fill = color;
node.findObject("NODESHAPE").stroke = color;
}
});
}
function doJunction(node) {
if (node.labeledLink != null) {
var color = node.labeledLink.findObject("SHAPE").stroke; // Grabs the color from the link it is on
if (color === "black") // if there is no input from the labeledlink, check for links into
var color = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
setOutputLinks(node, color);
node.labeledLink.findObject("SHAPE").stroke = color;
}
}
function doJunction2(node) { // standard draggable junction
var color = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
setOutputLinks(node, color);
}
function doDCVolt(node) {
var color = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
var children = new Set([]);
var key = node.data.key;
node.findLinksOutOf().each(function (link) {
uniqueChildren(link, children);
});
if (children.has(key)) {
setOutputLinks(node, "blue");
setNodeColor(node, "blue");
} else {
setOutputLinks(node, "black");
setNodeColor(node, "black");
}
}
function doACVolt(node) {
var color = node.data.Color;
node.data.Count += 25;
if (node.data.Count >= node.data.Interval) {
if (color === 'blue') color = 'black';
else if (color === 'black') color = 'blue';
node.data.Color = color;
node.data.Count = 0;
}
var children = new Set([]);
var key = node.data.key;
node.findLinksOutOf().each(function (link) {
uniqueChildren(link, children);
});
if (children.has(key)) {
setOutputLinks(node, color);
setNodeColor(node, color);
} else {
setOutputLinks(node, "black");
setNodeColor(node, "black");
}
}
function doSwitch(node) {
var color = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
if (node.findObject("NODESHAPE").figure == "On") { // Allows the output to go through if the switch is down
setOutputLinks(node, color);
} else {
setOutputLinks(node, "black");
}
setNodeColor(node, color);
}
function doSwitch2(node) {
var color = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
var nodeFig = node.findObject("NODESHAPE").figure;
if (nodeFig === "Up") {
node.findLinksOutOf().each(function (link) {
if (link.fromPort.name === "out1") { // Only emits to the top port
link.path.stroke = color;
}
if (link.fromPort.name === "out2") { // Force set the bottom port off
link.path.stroke = "black";
}
});
} else if (nodeFig === "Down") {
node.findLinksOutOf().each(function (link) {
if (link.fromPort.name === "out1") { // Force set the top port off
link.path.stroke = "black";
}
if (link.fromPort.name === "out2") { // Only emits to the bottom port
link.path.stroke = color;
}
});
}
setNodeColor(node, color)
}
function doLightBulb(node) {
var color = node.findLinksInto().any(linkIsOn) ? "yellow" : "lightgray"; // Sets the light bulb to either yellow or lightgray instead of blue/black
var color2 = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
if (node.findLinksInto().first() === null) {
node.findObject("NODESHAPE").fill = "lightgray";
}
node.findLinksInto().each(function (link) {
node.findObject("NODESHAPE").fill = color;
});
setOutputLinks(node, color2);
}
// Does nothing for now
function doGround(node) {
var color = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
node.findLinksInto().each(function (link) {
if (link.findObject("SHAPE").stroke === color) {
node.findObject("NODESHAPE").fill = color;
node.findObject("NODESHAPE").stroke = color;
}
});
}
// does the rest/generic actions
function doAll(node) {
var color = node.findLinksInto().any(linkIsOn) ? "blue" : "black";
setOutputLinks(node, color);
setNodeColor(node, color);
}
function toggleWire() {
var tool = myDiagram.toolManager.findTool("WireDragTool");
if (tool !== null) tool.isEnabled = !tool.isEnabled;
if (tool.isEnabled) document.getElementById('ge-footer').innerText = "Wire Dragging Tool Enabled";
else document.getElementById('ge-footer').innerHTML = "<span>Built with the <a href=\"https://gojs.net\">GoJS Diagramming Library</a>, by <a href=\"https://nwoods.com\"> Northwoods Software</a>.</span>";
}
/* Post-Init files go here ijiwd8up@90n */
</script>
</div>
</body>
</html>