From b6500b84daacd680c05ed8709f0b900cc2a3e2aa Mon Sep 17 00:00:00 2001 From: Nicole Rappe Date: Fri, 30 May 2025 01:02:45 -0600 Subject: [PATCH] Upgraded Math Operation Node --- .../General Purpose/Node_Math_Operation.jsx | 295 +++++++++--------- 1 file changed, 144 insertions(+), 151 deletions(-) diff --git a/Data/Server/WebUI/src/nodes/General Purpose/Node_Math_Operation.jsx b/Data/Server/WebUI/src/nodes/General Purpose/Node_Math_Operation.jsx index 3ded5cc..d245c8e 100644 --- a/Data/Server/WebUI/src/nodes/General Purpose/Node_Math_Operation.jsx +++ b/Data/Server/WebUI/src/nodes/General Purpose/Node_Math_Operation.jsx @@ -1,179 +1,172 @@ ////////// PROJECT FILE SEPARATION LINE ////////// CODE AFTER THIS LINE ARE FROM: /Data/WebUI/src/nodes/General Purpose/Node_Math_Operations.jsx - -/** - * ============================================ - * Borealis - Math Operation Node (Multi-Input A/B) - * ============================================ - * - * COMPONENT ROLE: - * Performs live math operations on *two grouped input sets* (A and B). - * - * FUNCTIONALITY: - * - Inputs connected to Handle A are summed - * - Inputs connected to Handle B are summed - * - Math operation is applied as: A <operator> B - * - Result pushed via BorealisValueBus[id] - * - * SUPPORTED OPERATORS: - * - Add, Subtract, Multiply, Divide, Average - */ - import React, { useEffect, useRef, useState } from "react"; import { Handle, Position, useReactFlow, useStore } from "reactflow"; +import { IconButton } from "@mui/material"; +import SettingsIcon from "@mui/icons-material/Settings"; +// Init shared memory bus if not already set if (!window.BorealisValueBus) window.BorealisValueBus = {}; if (!window.BorealisUpdateRate) window.BorealisUpdateRate = 100; const MathNode = ({ id, data }) => { - const { setNodes } = useReactFlow(); - const edges = useStore(state => state.edges); + const { setNodes } = useReactFlow(); + const edges = useStore(state => state.edges); + const [renderResult, setRenderResult] = useState(data?.value || "0"); + const resultRef = useRef(renderResult); - const [operator, setOperator] = useState(data?.operator || "Add"); - const [result, setResult] = useState("0"); - const resultRef = useRef(0); + useEffect(() => { + let intervalId = null; + let currentRate = window.BorealisUpdateRate; - useEffect(() => { - let intervalId = null; - let currentRate = window.BorealisUpdateRate; + const runLogic = () => { + const operator = data?.operator || "Add"; + const inputsA = edges.filter(e => e.target === id && e.targetHandle === "a"); + const inputsB = edges.filter(e => e.target === id && e.targetHandle === "b"); - const runLogic = () => { - const inputsA = edges.filter(e => e.target === id && e.targetHandle === "a"); - const inputsB = edges.filter(e => e.target === id && e.targetHandle === "b"); + const sum = (list) => + list + .map(e => parseFloat(window.BorealisValueBus[e.source]) || 0) + .reduce((a, b) => a + b, 0); - const sum = (list) => - list.map(e => parseFloat(window.BorealisValueBus[e.source]) || 0).reduce((a, b) => a + b, 0); + const valA = sum(inputsA); + const valB = sum(inputsB); - const valA = sum(inputsA); - const valB = sum(inputsB); + let value = 0; + switch (operator) { + case "Add": + value = valA + valB; + break; + case "Subtract": + value = valA - valB; + break; + case "Multiply": + value = valA * valB; + break; + case "Divide": + value = valB !== 0 ? valA / valB : 0; + break; + case "Average": + const totalInputs = inputsA.length + inputsB.length; + const totalSum = valA + valB; + value = totalInputs > 0 ? totalSum / totalInputs : 0; + break; + } - let value = 0; - switch (operator) { - case "Add": - value = valA + valB; - break; - case "Subtract": - value = valA - valB; - break; - case "Multiply": - value = valA * valB; - break; - case "Divide": - value = valB !== 0 ? valA / valB : 0; - break; - case "Average": - const totalInputs = inputsA.length + inputsB.length; - const totalSum = valA + valB; - value = totalInputs > 0 ? totalSum / totalInputs : 0; - break; - } + resultRef.current = value; + setRenderResult(value.toString()); + window.BorealisValueBus[id] = value.toString(); - resultRef.current = value; - setResult(value.toString()); - window.BorealisValueBus[id] = value.toString(); + setNodes(nds => + nds.map(n => + n.id === id + ? { ...n, data: { ...n.data, value: value.toString() } } + : n + ) + ); + }; - setNodes(nds => - nds.map(n => - n.id === id ? { ...n, data: { ...n.data, operator, value: value.toString() } } : n - ) - ); - }; + intervalId = setInterval(runLogic, currentRate); + // Watch for update rate changes + const monitor = setInterval(() => { + const newRate = window.BorealisUpdateRate; + if (newRate !== currentRate) { + clearInterval(intervalId); + currentRate = newRate; intervalId = setInterval(runLogic, currentRate); + } + }, 250); - const monitor = setInterval(() => { - const newRate = window.BorealisUpdateRate; - if (newRate !== currentRate) { - clearInterval(intervalId); - currentRate = newRate; - intervalId = setInterval(runLogic, currentRate); - } - }, 250); + return () => { + clearInterval(intervalId); + clearInterval(monitor); + }; + }, [id, edges, setNodes, data?.operator]); - return () => { - clearInterval(intervalId); - clearInterval(monitor); - }; - }, [id, operator, edges, setNodes]); + return ( +
+
A
+
B
+ + - return ( -
-
A
-
B
- - +
+ {data?.label || "Math Operation"} +
-
- {data?.label || "Math Operation"} -
+
+ Result: {renderResult} +
-
-
- Aggregates A and B inputs then performs operation. -
- - - - - - -
- - -
- ); -}; - -const dropdownStyle = { - fontSize: "9px", - padding: "4px", - background: "#1e1e1e", - color: "#ccc", - border: "1px solid #444", - borderRadius: "2px", - width: "100%", - marginBottom: "8px" -}; - -const resultBoxStyle = { - fontSize: "9px", - padding: "4px", - background: "#2a2a2a", - color: "#ccc", - border: "1px solid #444", - borderRadius: "2px", - width: "100%" + +
+ ); }; export default { - type: "MathNode", - label: "Math Operation", - description: ` -Perform Math on Aggregated Inputs + type: "MathNode", + label: "Math Operation", + description: ` +Live math node for computing on two grouped inputs. -- A and B groups are independently summed -- Performs: Add, Subtract, Multiply, Divide, or Average -- Result = A B -- Emits result via BorealisValueBus every update tick - `.trim(), - content: "Perform Math Operations", - component: MathNode +- Sums all A and B handle inputs separately +- Performs selected math operation: Add, Subtract, Multiply, Divide, Average +- Emits result as string via BorealisValueBus +- Updates at the global update rate + +**Common Uses:** +Live dashboard math, sensor fusion, calculation chains, dynamic thresholds + `.trim(), + content: "Perform Math Operations", + component: MathNode, + config: [ + { + key: "operator", + label: "Operator", + type: "select", + options: [ + "Add", + "Subtract", + "Multiply", + "Divide", + "Average" + ] + } + ], + usage_documentation: ` +### Math Operation Node + +Performs live math between two groups of inputs (**A** and **B**). + +#### Usage + +- Connect any number of nodes to the **A** and **B** input handles. +- The node **sums all values** from A and from B before applying the operator. +- Select the math operator in the sidebar config: + - **Add**: A + B + - **Subtract**: A - B + - **Multiply**: A * B + - **Divide**: A / B (0 if B=0) + - **Average**: (A + B) / total number of inputs + +#### Output + +- The computed result is pushed as a string to downstream nodes every update tick. + +#### Input Handles + +- **A** (Top Left) +- **B** (Middle Left) + +#### Example + +If three nodes outputting 5, 10, 15 are connected to A, +and one node outputs 2 is connected to B, +and operator is Multiply: + +- **A** = 5 + 10 + 15 = 30 +- **B** = 2 +- **Result** = 30 * 2 = 60 + + `.trim() };