Source: circuit_components/Node.js

import { INPUT_STATE } from "./Enums.js";
import { wireMng } from "../simulator.js";

export let nodeList = [];

let currentID = 0;

/**
 * Input/Output Node
 * @classdesc Input/Output Node
 */
export class Node {

    /**
     * Constructor
     * @param {Number} posX X Coordinate
     * @param {Number} posY Y Coordinate
     * @param {Boolean} isOutput Flag, True = is output node
     * @param {Boolean} value Default node value
     */
    constructor(posX, posY, isOutput = false, value = false) {
        this.diameter = 10;
        this.value = value;
        this.posX = posX;
        this.posY = posY;
        this.isOutput = isOutput;
        this.hitRange = this.diameter + 10;

        // only once input per node
        this.inputState = INPUT_STATE.FREE;

        this.isAlive = true; // not destroyed
        this.brotherNode = null; // for short circuit

        this.id = currentID;
        currentID++;

        nodeList[this.id] = this;
        //console.log(nodeList);
    }

    /**
     * Destroy this node
     */
    destroy() {
        this.isAlive = false;
        delete nodeList[this.id];
    }

    /**
     * Draw this node
     */
    draw() {
        fillValue(this.value);

        stroke(0);
        strokeWeight(4);
        circle(this.posX, this.posY, this.diameter);

        if (this.isMouseOver()) {
            fill(128, 128);
            noStroke();
            circle(this.posX, this.posY, this.hitRange)
        }

        /*noStroke();
        fill(0);
        textSize(12);
        textStyle(NORMAL);
        text(this.id, this.posX - 20, this.posY + 25);*/
    }

    /**
     * Set this node ID
     * @param {Boolean} newID New ID 
     */
    setID(newID)
    {
        delete nodeList[this.id];
        this.id = newID;
        nodeList[this.id] = this;

        //update max id
        if(this.id > currentID)
            currentID = this.id + 1;
    }

    /**
     * Set node input state
     * @param {Boolean} state New state
     */
    setInputState(state) {
        this.inputState = state;
    }

    /**
     * Set this node brother node
     * @param {Node} brotherNode New brother node 
     */
    setBrother(brotherNode) {
        this.brotherNode = brotherNode;
    }

    /**
     * Get this node brother
     * @return {Node} brother node
     */
    getBrother() {
        return this.brotherNode;
    }

    /**
     * Get this node value
     * @return {Number} node value
     */
    getValue() {
        return this.value;
    }

    /**
     * Set node value state
     * @param {Boolean} value New value
     */
    setValue(value) {
        this.value = value;
    }

    /**
     * Update this node Coordinate
     * @param {Number} posX X Cordinate
     * @param {Number} posY Y Coordinate
     */
    updatePosition(posX, posY) {
        this.posX = posX;
        this.posY = posY;
    }

    /**
     * Called for checking if mouse is over
     * @returns {Boolean} Boolean
     */
    isMouseOver() {
        if (dist(mouseX, mouseY, this.posX, this.posY) < (this.hitRange) / 2)
            return true;
        return false;
    }

    /**
     * Called when mouse is clicked
     * @returns {Boolean} Boolean
     */
    mouseClicked() {
        if (this.isMouseOver() && (this.inputState == INPUT_STATE.FREE || this.isOutput)) {
            wireMng.addNode(this);
            return true;
        }
        return false;
    }


};

/**
 * Node color fill by value
 * @param {Boolean} value Node Value
 */
export function fillValue(value) {
    if (value)
        fill(255, 193, 7);
    else
        fill(52, 58, 64);
}