cirsim
Version:
Cirsim Circuit Simulator
1,746 lines (1,386 loc) • 3.37 MB
JavaScript
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./index.js":
/*!******************!*\
!*** ./index.js ***!
\******************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Cirsim": () => (/* reexport safe */ _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim),
/* harmony export */ "default": () => (/* reexport safe */ _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim)
/* harmony export */ });
/* harmony import */ var _src_public_path__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src/public-path */ "./src/public-path.js");
/* harmony import */ var _src_public_path__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_src_public_path__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _src_polyfills_all__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./src/polyfills/all */ "./src/polyfills/all.js");
/* harmony import */ var _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./src/Cirsim/Cirsim */ "./src/Cirsim/Cirsim.js");
/* harmony import */ var _src_cirsim_scss__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./src/_cirsim.scss */ "./src/_cirsim.scss");
/* harmony import */ var _src_Cirsim_Utility_Ready__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./src/Cirsim/Utility/Ready */ "./src/Cirsim/Utility/Ready.js");
// The public-path module must be imported first!
// This allows Cirsim to be used as Cirsim or Cirsim.Cirsim
// since the version in cl/cirsim is Cirsim.Cirsim.
_src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim.Cirsim = _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim; // Automatically install into div.cirsim-install, where the text
// contents of the tag are JSON to configure Cirsim
_src_Cirsim_Utility_Ready__WEBPACK_IMPORTED_MODULE_4__.Ready.go(function () {
var elements = document.querySelectorAll('div.cirsim-install');
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
element.classList.remove('cirsim-install');
var json = JSON.parse(element.textContent);
element.innerHTML = '';
var cirsim = new _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim(element, json);
cirsim.startNow();
element.style.display = 'block';
}
});
__webpack_require__.g.Cirsim = _src_Cirsim_Cirsim__WEBPACK_IMPORTED_MODULE_2__.Cirsim;
/***/ }),
/***/ "./src/Cirsim/Bend.js":
/*!****************************!*\
!*** ./src/Cirsim/Bend.js ***!
\****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Bend": () => (/* binding */ Bend)
/* harmony export */ });
/* harmony import */ var _Selectable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Selectable */ "./src/Cirsim/Selectable.js");
/**
* Object that represents a bend in a connection line.
* @constructor
*/
var Bend = function Bend(x, y) {
_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.call(this);
this.connection = null; // Connection this bend is associated with
if (x !== undefined) {
this.x = x;
this.moveX = x;
}
if (y !== undefined) {
this.y = y;
this.moveY = y;
}
};
Bend.prototype = Object.create(_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype);
Bend.prototype.constructor = Bend;
Bend.prototype.touchRange = 12;
Bend.prototype.size = 4;
Bend.prototype.clone = function () {
var copy = new Bend();
copy.copyFrom(this);
return copy;
};
Bend.prototype.draw = function (context, view) {
if (view.selection.isSelected(this)) {
this.selectStyle(context, view);
context.beginPath();
context.arc(this.x, this.y, this.size, 0, 2 * Math.PI);
context.fill();
}
};
/**
* Determine if we have touched this bend
* @param x
* @param y
* @returns {boolean}
*/
Bend.prototype.touch = function (x, y) {
return Math.abs(x - this.x) + Math.abs(y - this.y) <= this.touchRange;
};
/**
* Delete this bend, removing it from the connection.
* @param caller Calling object.
* that object.
*/
Bend.prototype["delete"] = function (caller) {
this.connection.removeBend(this);
};
/**
* Save this bend as an object suitable for conversion to JSON
* @returns {{x: *, y: *}}
*/
Bend.prototype.save = function () {
return {
"x": this.x,
"y": this.y
};
};
/***/ }),
/***/ "./src/Cirsim/Circuit.js":
/*!*******************************!*\
!*** ./src/Cirsim/Circuit.js ***!
\*******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Circuit": () => (/* binding */ Circuit)
/* harmony export */ });
/* harmony import */ var _Component_CircuitRef__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Component/CircuitRef */ "./src/Cirsim/Component/CircuitRef.js");
/* harmony import */ var _Connection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Connection */ "./src/Cirsim/Connection.js");
/* harmony import */ var _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Utility/Sanitize */ "./src/Cirsim/Utility/Sanitize.js");
/* harmony import */ var _Utility_Rect__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Utility/Rect */ "./src/Cirsim/Utility/Rect.js");
/* harmony import */ var _Circuits__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Circuits */ "./src/Cirsim/Circuits.js");
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
/**
* Construct a circuit
* @param name Name of the circuit
* @constructor
*/
var Circuit = function Circuit(name) {
this.circuits = null;
this.components = [];
this.name = name;
this.width = this.defWidth;
this.height = this.defHeight; // Previous copy in the copy stack
this.prev = null;
/**
* See if some object has been touched by the mouse.
* @param x Mouse X
* @param y Mouse Y
* @return Touched element or null if none
*/
this.touch = function (x, y) {
//
// First we try to grab a component.
// We do this in reverse order so we are selecting
// from top down.
//
for (var i = this.components.length - 1; i >= 0; i--) {
var component = this.components[i];
var grabbed = component.touch(x, y);
if (grabbed !== null) {
return grabbed;
}
}
return null;
};
/**
* Advance the animation by delta time...
* @param delta
*/
this.advance = function (delta) {
var any = false;
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
if (component.advance(delta)) {
any = true;
}
}
return any;
};
};
Circuit.prototype.defWidth = 1920; ///< Default width
Circuit.prototype.defHeight = 1080; ///< Default height
/**
* Create a backup clone of this circuit
* @returns {Circuit}
*/
Circuit.prototype.clone = function () {
var copy = new Circuit(this.name);
copy.width = this.width;
copy.height = this.height; // Add to the copy stack
copy.prev = this.prev;
this.prev = copy; // Iterate over the components, cloning each of them
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
var componentCopy = component.clone();
copy.add(componentCopy);
} // Again we iterate over the components, this time
// cloning the output connections.
for (var _i = 0; _i < this.components.length; _i++) {
var component = this.components[_i];
for (var j = 0; j < component.outs.length; j++) {
var out = component.outs[j];
for (var k = 0; k < out.to.length; k++) {
out.to[k].clone();
}
}
}
return copy;
};
/**
* Create a backup clone of this circuit
* @returns {Circuit}
*/
Circuit.prototype.copy_clone = function () {
var copy = new Circuit(this.name);
copy.width = this.width;
copy.height = this.height; // Iterate over the components, cloning each of them
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
var componentCopy = component.clone();
copy.add(componentCopy);
} // Again we iterate over the components, this time
// cloning the output connections.
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
for (var j = 0; j < component.outs.length; j++) {
var out = component.outs[j];
for (var k = 0; k < out.to.length; k++) {
out.to[k].clone();
}
}
}
return copy;
};
/**
* Update circuit after a circuit change.
* This is used by CircuitRef components to ensure
* references are always correct.
*/
Circuit.prototype.update = function () {
var _iterator = _createForOfIteratorHelper(this.components),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var component = _step.value;
component.update();
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
};
Circuit.prototype.draw = function (context, view) {
this.components.forEach(function (component, index, array) {
component.draw(context, view);
});
};
Circuit.prototype.newTab = function () {
// There was code here to iterate over the components
// in reverse order. I don't recall why that was. I think
// it may be a holdover from the circuits being in reverse
// order. I'm removed it and will see if it breaks anything.
// for(let i=this.components.length-1; i>= 0; i--) {
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i]; // Tell any components that need to know that
// we have selected a new tab. This is
// important for the reference component.
component.newTab();
}
};
Circuit.prototype.recompute = function () {
for (var i = 0; i < this.components.length; i++) {
// Ensure everything get recomputed
this.components[i].pending();
}
};
/**
* Test if components or bends are contained in a given rectangle.
* @param rect Rect object
* @returns {Array} Array of all contained components
*/
Circuit.prototype.inRect = function (rect) {
var ret = [];
for (var i = this.components.length - 1; i >= 0; i--) {
this.components[i].inRect(rect, ret);
}
return ret;
};
Circuit.prototype.snapIt = function (item) {
if (this.circuits.snap) {
item.x = this.circuits.grid * Math.round(item.x / this.circuits.grid);
item.y = this.circuits.grid * Math.round(item.y / this.circuits.grid);
}
};
Circuit.prototype.add = function (component) {
this.components.push(component);
component.added(this);
return component;
};
/**
* Delete a specific item from the list of components
* @param toDelete Item to delete
*/
Circuit.prototype["delete"] = function (toDelete) {
for (var i = 0; i < this.components.length; i++) {
if (this.components[i] === toDelete) {
this.components.splice(i, 1);
break;
}
}
};
/**
* Determine if x,y touches a component In
* @param x
* @param y
*/
Circuit.prototype.touchIn = function (x, y) {
for (var i = this.components.length - 1; i >= 0; i--) {
var component = this.components[i];
var touched = component.touchIn(x, y);
if (touched !== null) {
return touched;
}
}
return null;
};
/**
* Determine if x,y touches a component Out
* @param x
* @param y
*/
Circuit.prototype.touchOut = function (x, y) {
for (var i = this.components.length - 1; i >= 0; i--) {
var component = this.components[i];
var touched = component.touchOut(x, y);
if (touched !== null) {
return touched;
}
}
return null;
};
/**
* Save this object into an object suitable for conversion to
* a JSON object for storage.
* @returns Object
*/
Circuit.prototype.save = function () {
// Iterate over the components, saving each of them
var comps = [];
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i]; // Set an ID on each component
// component.id = "c" + (i + 1001);
comps.push(component.save());
} // Then iterate over the connections, saving each of them
var connections = [];
for (var _i2 = 0; _i2 < this.components.length; _i2++) {
var _component = this.components[_i2];
connections = connections.concat(_component.saveConnections());
}
return {
"name": this.name,
"width": this.width,
"height": this.height,
"components": comps,
"connections": connections
};
};
/**
* Load this object from an object that was converted from a
* JSON object for storage.
* @param obj
*/
Circuit.prototype.load = function (obj) {
this.name = _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__.Sanitize.sanitize(obj.name);
this.width = +obj.width;
this.height = +obj.height; // Load the components
var compsMap = {}; // Map from component ID to component object
for (var i = 0; i < obj.components.length; i++) {
var componentObj = obj.components[i];
var componentProto = void 0;
if (componentObj.type === "CircuitRef") {
componentProto = _Component_CircuitRef__WEBPACK_IMPORTED_MODULE_0__.CircuitRef;
} else {
componentProto = this.circuits.model.main.components.get(componentObj.type);
}
if (componentProto !== null) {
var component = new componentProto();
component.circuit = this;
component.load(componentObj);
compsMap[component.id] = component;
this.add(component);
} else {
console.log(componentObj);
}
} // Load the connections
for (var _i3 = 0; _i3 < obj.connections.length; _i3++) {
var connectionObj = obj.connections[_i3];
var fmComp = compsMap[connectionObj["from"]];
if (fmComp === undefined) {
console.log("From object undefined");
console.log(this);
console.log(connectionObj);
continue;
}
var toComp = compsMap[connectionObj["to"]];
if (toComp === undefined) {
console.log("To object undefined");
console.log(this);
console.log(connectionObj);
continue;
}
var outNdx = connectionObj["out"];
var inNdx = connectionObj["in"];
var connection = this.connect(fmComp, outNdx, toComp, inNdx);
if (connection !== null) {
connection.load(connectionObj);
}
}
};
/**
* Get a component by it's naming
* @param naming Naming to search for
* @returns {*}
*/
Circuit.prototype.getComponentByNaming = function (naming) {
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
if (component.naming === naming) {
return component;
}
}
return null;
};
/**
* Get all components by type
* @param type Naming to search for
* @returns Array with collection of components of that type
*/
Circuit.prototype.getComponentsByType = function (type) {
var components = [];
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
if (component.constructor.type === type) {
components.push(component);
}
}
return components;
};
Circuit.prototype.mouseUp = function () {
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
component.mouseUp();
}
};
Circuit.prototype.connect = function (outObj, outNdx, inObj, inNdx) {
if (outObj.outs.length <= outNdx || inObj.ins.length <= inNdx) {
return null;
}
return new _Connection__WEBPACK_IMPORTED_MODULE_1__.Connection(outObj.outs[outNdx], inObj.ins[inNdx]);
};
Circuit.prototype.getComponentsByType = function (type) {
var ret = [];
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
if (component.constructor.type === type) {
ret.push(component);
}
}
return ret;
};
/**
* Determine the maximum size in each dimension for this circuit.
* Does include an extra 16 pixel bias in each dimension to account for
* inputs and outputs.
* @returns {{x: number, y: number}}
*/
Circuit.prototype.maxXY = function () {
var maxX = 1;
var maxY = 1;
for (var i = 0; i < this.components.length; i++) {
var bounds = this.components[i].bounds();
if (bounds.right > maxX) {
maxX = bounds.right;
}
if (bounds.bottom > maxY) {
maxY = bounds.bottom;
}
}
return {
x: maxX + 16,
y: maxY + 16
};
};
/**
* Compute a bounding box that encloses all of this circuit.
* @returns {*}
*/
Circuit.prototype.bounds = function () {
if (this.components.length === 0) {
return new _Utility_Rect__WEBPACK_IMPORTED_MODULE_3__.Rect();
}
var bounds = this.components[0].bounds();
for (var i = 0; i < this.components.length; i++) {
var b = this.components[i].bounds();
bounds.expand(b);
}
return bounds;
};
Circuit.prototype.pending = function () {
for (var i = 0; i < this.components.length; i++) {
var component = this.components[i];
component.pending();
}
};
Circuit.prototype.getName = function () {
return this.name;
};
Circuit.prototype.setName = function (name) {
this.name = name;
};
/**
* Obtain basic statistics about this circuit
* @returns {{name: *, numComponents: Number, numConnections: number, width: *, height: *}}
*/
Circuit.prototype.stats = function () {
var numConnections = 0;
this.components.forEach(function (component) {
component.outs.forEach(function (out) {
numConnections += out.to.length;
});
});
return {
name: this.name,
numComponents: this.components.length,
numConnections: numConnections,
width: this.width,
height: this.height
};
};
Circuit.prototype.moveToFront = function (component) {
for (var i = 0; i < this.components.length; i++) {
if (this.components[i] === component) {
this.components.splice(i, 1);
this.components.push(component);
break;
}
}
};
/**
* Return all CircuitRef components that refer to a circuit
* @param circuit Circuit we are testing. If omitted, all CircuitRef components are returned.
* @return array of CircuitRef components.
*/
Circuit.prototype.references = function (circuit) {
var references = [];
var _iterator2 = _createForOfIteratorHelper(this.components),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var component = _step2.value;
if (component instanceof _Component_CircuitRef__WEBPACK_IMPORTED_MODULE_0__.CircuitRef) {
if (circuit !== undefined) {
if (component.circuitName === circuit.name) {
references.push(component);
}
} else {
references.push(component);
}
}
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return references;
};
/***/ }),
/***/ "./src/Cirsim/Circuits.js":
/*!********************************!*\
!*** ./src/Cirsim/Circuits.js ***!
\********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Circuits": () => (/* binding */ Circuits)
/* harmony export */ });
/* harmony import */ var _Simulation__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Simulation */ "./src/Cirsim/Simulation.js");
/* harmony import */ var _Circuit__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Circuit */ "./src/Cirsim/Circuit.js");
/* harmony import */ var _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Utility/Sanitize */ "./src/Cirsim/Utility/Sanitize.js");
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
/**
* A collection of circuit objects
* @param model The model we are a member of
* @param simulation The simulation object that simulates operation of the circuits
* @constructor
*/
var Circuits = function Circuits(model, simulation) {
this.model = model;
this.circuits = [];
this.grid = 8;
this.snap = true;
this.id = model !== null ? model.id : undefined; // If none is supplied, create a simulation object
this.simulation = simulation ? simulation : new _Simulation__WEBPACK_IMPORTED_MODULE_0__.Simulation(); // Previous copy in the copy stack
this.prev = null;
};
/**
* Add a circuit to this collection of circuits
* @param circuit
*/
Circuits.prototype.add = function (circuit) {
this.circuits.push(circuit);
circuit.circuits = this;
return circuit;
};
Circuits.prototype.insert = function (circuit) {
this.circuits.unshift(circuit);
circuit.circuits = this;
return circuit;
};
/**
* Get the collection of circuits.
* @returns Array of Circuit objects (copy)
*/
Circuits.prototype.getCircuits = function () {
return this.circuits.slice();
};
/**
* Get a circuit by name
* @param name Name of the circuit
* @returns Circuit object or null
*/
Circuits.prototype.getCircuit = function (name) {
for (var i = 0; i < this.circuits.length; i++) {
var circuit = this.circuits[i];
if (circuit.name === name) {
return circuit;
}
}
return null;
};
Circuits.prototype.advance = function (delta) {
var ret = false;
for (var i = 0; i < this.circuits.length; i++) {
var circuit = this.circuits[i];
if (circuit.advance(delta)) {
ret = true;
}
}
return ret;
};
/**
* Determine if a circuit can be deleted.
* @param ndx Index into the circuits.
*/
Circuits.prototype.canDelete = function (ndx) {
if (ndx === 0) {
// The main circuit (first) cannot be deleted
return false;
} // Do any circuits to the left refer to this one?
var circuit = this.circuits[ndx];
for (var i = 0; i < ndx; i++) {
var references = this.circuits[i].references(circuit);
if (references.length > 0) {
return false;
}
}
return true;
};
/**
* Determine if a circuit can be moved left as a tab.
* @param ndx Index into the circuits.
* @returns {boolean} True if can be moved left
*/
Circuits.prototype.canMoveLeft = function (ndx) {
// First two tabs cannot be moved left at all
if (ndx < 2) {
return false;
} // Does the circuit to the left refer to this one?
var circuit = this.circuits[ndx];
var references = this.circuits[ndx - 1].references(circuit);
return references.length === 0;
};
/**
* Determine if a circuit can be moved right as a tab
* @param ndx Index into the circuits.
* @returns {boolean} True if can be move right
*/
Circuits.prototype.canMoveRight = function (ndx) {
// First tab cannot be moved at all. Last tab can't
// move to the right.
if (ndx === 0 || ndx === this.circuits.length - 1) {
return false;
} // What does this circuit refer to?
var right = this.circuits[ndx + 1].name;
var references = this.circuits[ndx].references();
var _iterator = _createForOfIteratorHelper(references),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var reference = _step.value;
if (reference.circuitName === right) {
return false;
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return true;
};
Circuits.prototype.moveLeft = function (ndx) {
if (this.canMoveLeft(ndx)) {
this.model.backup();
var t = this.circuits[ndx - 1];
this.circuits[ndx - 1] = this.circuits[ndx];
this.circuits[ndx] = t;
return true;
}
return false;
};
Circuits.prototype.moveRight = function (ndx) {
if (this.canMoveRight(ndx)) {
this.model.backup();
var t = this.circuits[ndx + 1];
this.circuits[ndx + 1] = this.circuits[ndx];
this.circuits[ndx] = t;
return true;
}
return false;
};
Circuits.prototype.rename = function (ndx, name) {
this.model.backup();
var circuit = this.circuits[ndx]; // Rename any references to this circuit
for (var i = 0; i < ndx; i++) {
var references = this.circuits[i].references(circuit);
var _iterator2 = _createForOfIteratorHelper(references),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var reference = _step2.value;
reference.circuitName = name;
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
circuit.setName(name);
};
Circuits.prototype.newTab = function () {
// for(let i=0; i<this.circuits.length; i++) {
// this.circuits[i].newTab();
// }
for (var i = this.circuits.length - 1; i >= 0; i--) {
this.circuits[i].newTab();
}
};
Circuits.prototype.recompute = function () {
//for(let i=0; i<this.circuits.length; i++) {
for (var i = this.circuits.length - 1; i >= 0; i--) {
this.circuits[i].recompute();
}
};
/**
* Create a backup clone of this circuit
* @returns {Circuits}
*/
Circuits.prototype.clone = function () {
var copy = new Circuits(this.model, this.simulation);
copy.grid = this.grid;
copy.snap = this.snap; // Add to the copy stack
copy.prev = this.prev;
this.prev = copy; // Copy the circuit objects
for (var i = 0; i < this.circuits.length; i++) {
var circuit = this.circuits[i];
copy.add(circuit.clone());
}
return copy;
};
/**
* Update circuits after a circuit change.
* This is used by CircuitRef components to ensure
* references are always correct.
* @param circuit Update up until this circuit
*/
Circuits.prototype.update = function (circuit) {
var _iterator3 = _createForOfIteratorHelper(this.circuits),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var c = _step3.value;
if (c === circuit) {
break;
}
c.update();
}
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
};
Circuits.prototype.toJSON = function () {
return JSON.stringify(this.save());
};
/**
* Load the circuits from a JSON-encoded object
* @param json
*/
Circuits.prototype.fmJSON = function (json) {
var obj = JSON.parse(json);
this.load(obj);
};
/**
* Save this object into an object suitable for conversion to
* a JSON object for storage.
* @returns Object
*/
Circuits.prototype.save = function () {
var cirs = [];
for (var i = 0; i < this.circuits.length; i++) {
var circuit = this.circuits[i];
cirs.push(circuit.save());
}
var obj = {
"grid": this.grid,
"circuits": cirs,
"id": this.id
};
if (this.snap) {
obj.snap = true;
}
return obj;
};
/**
* Load this object from an object converted from a JSON
* object used for storage.
* @param obj
*/
Circuits.prototype.load = function (obj) {
this.grid = +obj["grid"];
this.snap = _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__.Sanitize.boolean(obj["snap"]);
this.prev = null;
this.circuits = [];
if (obj["id"] !== undefined) {
this.id = _Utility_Sanitize__WEBPACK_IMPORTED_MODULE_2__.Sanitize.sanitize(obj["id"]);
} //
// Load circuits in reverse order
//
for (var i = obj.circuits.length - 1; i >= 0; i--) {
var circuitObj = obj.circuits[i];
var circuit = new _Circuit__WEBPACK_IMPORTED_MODULE_1__.Circuit(circuitObj.name);
this.insert(circuit);
circuit.load(circuitObj);
} // In reverse order, ensure all circuits have
// had compute called on all components
for (var _i = this.circuits.length - 1; _i >= 0; _i--) {
this.circuits[_i].pending();
}
};
Circuits.prototype.addCircuit = function (name) {
var circuit = new _Circuit__WEBPACK_IMPORTED_MODULE_1__.Circuit(name);
this.add(circuit);
};
/**
* Delete a circuit by the index to the circuit
* @param index Index into the circuits array
*/
Circuits.prototype.deleteCircuitByIndex = function (index) {
this.circuits.splice(index, 1);
};
/**
* Get a component by it's naming
* @param naming Naming to search for
* @returns {*}
*/
Circuits.prototype.getComponentByNaming = function (naming) {
for (var i = 0; i < this.circuits.length; i++) {
var circuit = this.circuits[i];
var pin = circuit.getComponentByNaming(naming);
if (pin !== null) {
return pin;
}
}
return null;
};
/**
* Get all components by type
* @param type Naming to search for
* @returns Array with collection of components of that type
*/
Circuits.prototype.getComponentsByType = function (type) {
var components = [];
for (var i = 0; i < this.circuits.length; i++) {
var circuit = this.circuits[i];
var c = circuit.getComponentsByType(type);
components = components.concat(c);
}
return components;
};
/**
* Replace a circuit that currently exists with a new version.
*/
Circuits.prototype.replaceCircuit = function (circuit) {
circuit.circuits = this;
for (var i = 0; i < this.circuits.length; i++) {
if (this.circuits[i].name === circuit.name) {
this.circuits[i] = circuit; // Ensure all components in the new circuit are pending, so they
// all get updated.
circuit.components.forEach(function (component) {
component.pending();
}); // Force this to appear to be a new tab
this.model.newTab();
break;
}
}
};
/***/ }),
/***/ "./src/Cirsim/Cirsim.js":
/*!******************************!*\
!*** ./src/Cirsim/Cirsim.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Cirsim": () => (/* binding */ Cirsim)
/* harmony export */ });
/* harmony import */ var _Main__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Main */ "./src/Cirsim/Main.js");
/* harmony import */ var _Options__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./Options */ "./src/Cirsim/Options.js");
/* harmony import */ var _Components__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Components */ "./src/Cirsim/Components.js");
/* harmony import */ var _Component_All__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./Component/All */ "./src/Cirsim/Component/All.js");
/* harmony import */ var _Utility_Ready__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Utility/Ready */ "./src/Cirsim/Utility/Ready.js");
/**
* Create an instance of Cirsim
*
* This creates a single Instance that manages the
* components and starts actual Cirsim windows.
*
* Construct and start running like this:
*
* Given an HTML div:
* <div id="cirsim"></div>
*
* The following script starts Cirsim in that div:
*
* var cirsim = new Cirsim('#cirsim');
* cirsim.start();
*
* @param sel Selector to create Cirsim in (can be many)
* @param options An object containing Cirsim options.
* @constructor
*/
var Cirsim = function Cirsim(sel, options) {
var _this = this;
//
// Master set of the version
//
var PACKAGE = __webpack_require__(/*! ../../package.json */ "./package.json");
this.version = PACKAGE.version; //
// Determine the root directory for Cirsim
// This is the directory containing cirsim.js or
// cirsim.min.js
//
this.root = __webpack_require__.p; // Record the selector
this.sel = sel; // The Options object that manages user options
this.options = new _Options__WEBPACK_IMPORTED_MODULE_1__.Options(options); //
// Install all components and configure standard
// Cirsim palettes.
//
this.components = new _Components__WEBPACK_IMPORTED_MODULE_2__.Components();
(0,_Component_All__WEBPACK_IMPORTED_MODULE_3__.All)(this.components); // A collection of Main objects.
var mains = []; // A collection of tests.
// We collect those in Cirsim because the actual
// Main may not be created, yet.
var tests = [];
/**
* Start Cirsim running, creating the user interface.
* This does wait for document ready before calling
* this.startNow() unless we are running in no-window
* mode. In that case it returns a started instance.
*/
this.start = function () {
if (sel === null) {
return _this.startNow();
}
_Utility_Ready__WEBPACK_IMPORTED_MODULE_4__.Ready.go(function () {
_this.startNow();
});
};
/**
* Start Cirsim running now. Does not wait for document ready.
*/
this.startNow = function () {
if (sel !== null) {
if (sel instanceof Element) {
var main = new _Main__WEBPACK_IMPORTED_MODULE_0__.Main(_this, sel, tests);
mains.push(main);
} else {
var elements = document.querySelectorAll(sel);
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
var _main = new _Main__WEBPACK_IMPORTED_MODULE_0__.Main(_this, element, tests);
mains.push(_main);
}
}
if (mains.length === 1) {
if (_this.options.global !== null) {
__webpack_require__.g[_this.options.global] = mains[0];
}
return mains[0];
}
} else {
_this.options.display = 'none';
var _main2 = new _Main__WEBPACK_IMPORTED_MODULE_0__.Main(_this, null, tests);
mains.push(_main2);
return _main2;
}
return null;
};
/**
* Get all active instances of Cirsim that are running.
* @returns {Array} Array of objects of type Main.
* @deprecated This is going away
*/
this.getInstances = function () {
return mains;
};
/**
* Add a test that is available to run
*
* The underlying test is a JavaScript object with these tags:
*
* tag: A tag to identify the test
* name: Name of the test, what will appear in menus
* input: Array of input labels
* output: Array of output labels
* test: Array of tests, each an array of input/expected
* staff: true if this is staff testing (no saving)
*
* @param test Test to add. Can be Javascript object, JSON or base64
* encoded JSON.
*/
this.addTest = function (test) {
tests.push(test);
};
/**
* Run a test by name
* @param test
*/
this.runTest = function (test) {
mains.forEach(function (main) {
main.runTest(test);
});
};
};
/***/ }),
/***/ "./src/Cirsim/Component.js":
/*!*********************************!*\
!*** ./src/Cirsim/Component.js ***!
\*********************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "Component": () => (/* binding */ Component)
/* harmony export */ });
/* harmony import */ var _Selectable__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Selectable */ "./src/Cirsim/Selectable.js");
/* harmony import */ var _In__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./In */ "./src/Cirsim/In.js");
/* harmony import */ var _Out__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./Out */ "./src/Cirsim/Out.js");
/* harmony import */ var _OutInv__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./OutInv */ "./src/Cirsim/OutInv.js");
/* harmony import */ var _Connection__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./Connection */ "./src/Cirsim/Connection.js");
/* harmony import */ var _Dlg_ComponentPropertiesDlg__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./Dlg/ComponentPropertiesDlg */ "./src/Cirsim/Dlg/ComponentPropertiesDlg.js");
/* harmony import */ var dompurify__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! dompurify */ "../../.yarn/cache/dompurify-npm-2.2.9-1a93a7440c-8673be49ae.zip/node_modules/dompurify/dist/purify.js");
/* harmony import */ var dompurify__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(dompurify__WEBPACK_IMPORTED_MODULE_6__);
/* harmony import */ var _Utility_Rect__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./Utility/Rect */ "./src/Cirsim/Utility/Rect.js");
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
/**
* Base object for a component in a circuit
* @constructor
*/
var Component = function Component() {
_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.call(this);
var circuit = null;
Object.defineProperty(this, 'circuit', {
get: function get() {
return circuit;
},
set: function set(value) {
circuit = value;
}
});
this.height = 10;
this.width = 10;
this.prev = null;
this.id = ''; // Will be set to a unique id for this component
this.circuit = null;
this.naming = null; // Naming, as in U1 or I1
this.ins = [];
this.outs = [];
};
Component.prototype = Object.create(_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype);
Component.prototype.constructor = Component;
/**
* Prefix for component naming
*/
Component.prototype.prefix = "U";
Component.prototype.nameRequired = false;
Component.prototype.delay = 11; ///< Propagation delay in nanoseconds
/**
* Assign this component a unique ID. This is done when a
* component is created by the view.
*/
Component.prototype.brand = function () {
// Every component get a unique ID when it is created
this.id = 'c' + ++Component.maxId;
}; /// Maximum ID integer value for any component
Component.maxId = 1000;
Component.prototype.copyFrom = function (component) {
this.height = component.height;
this.width = component.width;
this.prev = component.prev;
this.naming = component.naming;
this.id = component.id;
component.prev = this;
_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype.copyFrom.call(this, component); //
// Copy input and output states
//
for (var i = 0; i < this.ins.length; i++) {
this.ins[i].copyFrom(component.ins[i]);
}
for (var _i = 0; _i < this.outs.length; _i++) {
this.outs[_i].copyFrom(component.outs[_i]);
}
};
Component.prototype.drop = function () {
if (this.x < this.width / 2) {
this.x = this.width / 2;
}
if (this.y < this.height / 2) {
this.y = this.height / 2;
}
};
Component.prototype.grab = function () {
_Selectable__WEBPACK_IMPORTED_MODULE_0__.Selectable.prototype.grab.call(this);
this.circuit.moveToFront(this);
};
Component.prototype.mouseUp = function () {};
/**
* Called when a component is added to a circuit
* @param circuit
*/
Component.prototype.added = function (circuit) {
this.circuit = circuit;
if (this.naming === null && this.nameRequired) {
// Create a new name
for (var i = 1;; i++) {
var naming = void 0;
if (this.prefix.charAt(0) === "*") {
if (i <= 26) {
naming = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.charAt(i - 1);
} else {
naming = this.prefix.charAt(1) + (i - 26);
}
} else {
naming = this.prefix + i;
}
var existing = this.circuit.getComponentByNaming(naming);
if (existing === null) {
this.naming = naming;
break;
}
}
}
};
/**
* Add an input to this component
* @param x Relative X location
* @param y Relative Y location
* @param len Length of the line to draw for the input
* @return {In}
*/
Component.prototype.addIn = function (x, y, len, name) {
var inObj = new _In__WEBPACK_IMPORTED_MODULE_1__.In(this, x, y, len, name);
inObj.index = this.ins.length;
this.ins.push(inObj);
return inObj;
};
/**
* Add an output to this component
* @param x Relative X location
* @param y Relative Y location
* @param len Length of the line to draw for the output
* @return Created output object
*/
Component.prototype.addOut = function (x, y, len, name, inv) {
var outObj = new _Out__WEBPACK_IMPORTED_MODULE_2__.Out(this, x, y, len, name, inv);
outObj.index = this.outs.length;
this.outs.push(outObj);
return outObj;
};
/**
* Add an inverse output to this component
* @param x Relative X location
* @param y Relative Y location
* @param len Length of the line to draw for the output
* @return Created output object
*/
Component.prototype.addOutInv = function (x, y, len, name, inv) {
var outObj = new _OutInv__WEBPACK_IMPORTED_MODULE_3__.OutInv(this, x, y, len, name, inv);
outObj.index = this.outs.length;
this.outs.push(outObj);
return outObj;
};
/**
* Try to touch this component or some part of
* the component.
* @param x Mouse X
* @param y Mouse Y
*/
Component.prototype.touch = function (x, y) {
// First, try to touch the inputs and outputs
var touched = this.touchOut(x, y);
if (touched !== null) {
// We have touched an Out connector. Add a connection
// for this output, but with no current "to"
return new _Connection__WEBPACK_IMPORTED_MODULE_4__.Connection(touched, null);
}
touched = this.touchIn(x, y);
if (touched !== null) {
// We have touched an In connector. Add a connection
// for this input, but with no current "from"
return new _Connection__WEBPACK_IMPORTED_MODULE_4__.Connection(null, touched);
} // Have we touched the component itself?
if (x >= this.x - this.width / 2 && x <= this.x + this.width / 2 && y >= this.y - this.height / 2 && y <= this.y + this.height / 2) {
return this;
} // Test if we have touched an output connection or bend
for (var i = 0; i < this.outs.length; i++) {
var conn = this.outs[i].touchConnections(x, y);
if (conn !== null) {
return conn;
}
}
return null;
};
/**
* Try to touch an Out object for this componenet
* @param x
* @param y
* @return Out object touched or null if none
*/
Component.prototype.touchOut = function (x, y) {
for (var i = 0; i < this.outs.length; i++) {
if (this.outs[i].touch(x, y)) {
return this.outs[i];
}
}
return null;
};
/**
* Try to touch an In object for this componenet
* @param x
* @param y
* @return In object touched or null if none
*/
Component.prototype.touchIn = function (x, y) {
for (var i = 0; i < this.ins.length; i++) {
if (this.ins[i].touch(x, y)) {
return this.ins[i];
}
}
return null;
};
/**
* Collect all of this component and any bends that
* are contained in the rectangle.
* @param rect Rectangle to test
* @param collect Collection (array) to add items to.
*/
Component.prototype.inRect = function (rect, collect) {
if (rect.contains(this.x, this.y)) {
collect.push(this);
}
this.outs.forEach(function (out) {
out.selectRect(rect, collect);
});
};
Component.prototype["delete"] = function () {
// Delete all connection
for (var i = 0; i < this.ins.length; i++) {
this.ins[i].clear();
}
for (var i = 0; i < this.outs.length; i++) {
this.outs[i].clear();
}
this.circuit["delete"](this);
};
/**
* Compute a bounding box that completely contains the component
* @returns {Rect}
*/
Component.prototype.bounds = function () {
var bounds = new _Utility_Rect__WEBPACK_IMPORTED_MODULE_7__.Rect(this.x - this.width / 2, this.y - this.height / 2, this.x + this.width / 2, this.y + this.height / 2);
var _iterator = _createForOfIteratorHelper(this.ins),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var ins = _step.value;
bounds.expand(ins.bounds());
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
var _iterator2 = _createForOfIteratorHelper(this.outs),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var out = _step2.value;
bounds.expand(out.bounds());
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
return bounds;
};
/**
* Draw component object.
*
* Default version for simple box objects
* @param context Display context
* @param view View object
*/
Component.prototype.draw = function (context, view) {
this.selectStyle(context, view);
this.drawBox(context);
this.drawName(context, 0, 3);
this.drawIO(context, view);
};
/**
* Draw the input/output pins for this component.
*
* This also draws the connections.
*/
Component.prototype.drawIO = function (context, view) {
for (var i = 0; i < this.ins.length; i++) {
this.selectStyle(context, view);
this.ins[i].draw(context, view);
}
for (var i = 0; i < this.outs.length; i++) {
this.selectStyle(context, view);
this.outs[i].draw(context, view);
}
};
/**
* Save the component basic properties to an object
*
* The character ' is replaced with `. This is so the
* output JSON won't have any ' characters that would
* cause problems in PHP and Javascript
*
* @returns {{id: *, x: *, y: *, name: string, type: *}}
*/
Component.prototype.save = function () {
var type = this.constructor.type;
var naming = this.naming;
if (naming !== null) {
naming = naming.replace(/'/g, '`');
}
return {
"id": this.id,
"x": this.x,
"y": this.y,
"name": naming,
"type": type
};
};
Component.prototype.load = fun