UNPKG

@teachinglab/omd

Version:

omd

202 lines (132 loc) 12.1 kB
# omdNode The abstract base class for all nodes in the mathematical expression tree. It provides the core functionality for tree structure (parent-child relationships), layout calculations, rendering, and provenance tracking. All specific mathematical elements (constants, variables, operators, functions, equations) extend this class. ## Class Definition ```javascript export class omdNode extends omdMetaExpression ``` This class is not meant to be instantiated directly. Instead, you should use one of its concrete subclasses (e.g., `omdConstantNode`, `omdBinaryExpressionNode`). ### Key Concepts - **AST (Abstract Syntax Tree):** Each `omdNode` is typically created from a node in the math.js AST, providing a structured representation of the mathematical expression. - **Tree Structure:** Nodes are organized in a hierarchical tree with `parent` and `childList` properties, enabling traversal and manipulation of the expression. - **Layout:** The `computeDimensions()` and `updateLayout()` methods are fundamental for determining the size and position of a node and its children, ensuring correct visual rendering. - **Provenance:** The `provenance` array on each node tracks its history. When a node is cloned (e.g., during a simplification step), the new node's provenance array will contain the ID of the original node, creating a traceable link back to its predecessor. This is crucial for features like step-by-step explanations and highlighting. ## Public Properties - **`id`** (`number`): A unique identifier for each node instance, automatically assigned upon creation. - **`type`** (`string`): A string indicating the specific type of the OMD node (e.g., `"omdConstantNode"`, `"omdBinaryExpressionNode"`). - **`parent`** (`omdNode` | `null`): A reference to the parent node in the expression tree. `null` for the root node. - **`astNodeData`** (`object`): The original math.js AST node from which this `omdNode` was created. This preserves the raw parsed data. - **`provenance`** (`Array<number>`): An array of IDs from which this node was derived. This forms a historical chain, linking a node back through transformations or simplifications. - **`argumentNodeList`** (`object`): A map (or object) containing references to the node's structurally significant children (e.g., `left`, `right` for binary expressions, `args` for functions). This is used for recursive operations and provenance tracking. - **`isExplainHighlighted`** (`boolean`): A flag indicating if the node is currently highlighted for explanation purposes. This acts as a lock, preventing other highlights from overriding it. - **`x`** (`number`): The x-coordinate of the node's top-left corner relative to its parent. - **`y`** (`number`): The y-coordinate of the node's top-left corner relative to its parent. - **`width`** (`number`): The calculated width of the node's bounding box. - **`height`** (`number`): The calculated height of the node's bounding box. - **`fontSize`** (`number`): The base font size applied to this node and its children. - **`svgElement`** (`SVGElement`): The root SVG element that represents this node visually. ## Public Methods ### `initialize()` Initializes the node by recursively computing its dimensions and updating its layout. This method should be called after a node and its children have been fully constructed to ensure proper sizing and positioning. ### `clone()` Creates a deep, structural clone of the node. The new node will have a new `id`, and its `provenance` will link back to the original node's `id`, establishing a historical connection. - **Returns**: `omdNode` - A new instance of the same type as the original, with all children also cloned. ### `replaceWith(newNode, options)` Replaces this node with a `newNode` in the expression tree. This updates all parent and child references and triggers a re-layout and re-rendering of the affected parts of the SVG. - **`newNode`** (`omdNode`): The node to substitute in. - **`options`** (`object`, optional): Configuration for the replacement. - `updateLayout` (`boolean`): If `true` (default), the layout of the entire tree will be recalculated upwards from the point of replacement. - **Returns**: `boolean` - `true` if the replacement was successful. ### `simplify()` Asynchronously attempts to simplify the expression rooted at this node by invoking the central simplification engine (`simplifyStep`). - **Returns**: `Promise<object>` - A promise that resolves to an object like `{ success, foldedCount, newRoot, message }`. Throws an error if the `simplifyStep` function is not set. ### `toMathJSNode()` Converts the `omdNode` and its children back into a math.js-compatible AST object. This method must be implemented by all concrete subclasses. - **Returns**: `object` - The math.js AST node. - **Throws**: `Error` if not implemented by the subclass. ### `toString()` Converts the node into a human-readable string representation. It typically uses the `toMathJSNode()` method internally to leverage math.js's string conversion capabilities. - **Returns**: `string`. ### `render()` Generates or retrieves the SVG representation of the node. This method calls `renderSelf()` if the SVG element has not been created yet. - **Returns**: `SVGElement` - The root SVG element representing this node. ### `renderSelf()` Abstract method that must be implemented by subclasses. This method is responsible for creating the specific SVG elements and structure for the node's visual representation. - **Returns**: `SVGElement` - The SVG element created for this node. - **Throws**: `Error` if not implemented by the subclass. ### `setFontSize(size)` Sets the base font size for this node and recursively propagates the new font size to all its children. - **`size`** (`number`): The font size in pixels. ### `moveTo(x, y)` Moves the node to a new absolute position (`x`, `y`) relative to its parent. It also recursively moves all children by the same delta. - **`x`** (`number`): The new x-coordinate. - **`y`** (`number`): The new y-coordinate. ### `show()` Makes the node and its SVG representation visible. ### `hide()` Hides the node and its SVG representation. ### `getDepth()` Calculates the depth of the node in the expression tree (0 for the root node). - **Returns**: `number` - The depth of the node. ### `findParentOfType(type)` Traverses up the tree to find the nearest parent node of a specific type. - **`type`** (`string`): The `type` property of the node to search for (e.g., `"omdEquationNode"`). - **Returns**: `omdNode` | `null` - The found parent node or `null` if not found. ### `validateProvenance(nodeMap)` Validates the provenance integrity of this node and all its descendants. It checks for duplicate IDs, invalid references, and self-references in the `provenance` arrays. - **`nodeMap`** (`Map`, optional): An optional map of all known nodes in the system, used for cross-referencing provenance IDs. - **Returns**: `Array<object>` - An array of validation issues found, each describing the type of issue, the node involved, and relevant IDs. ### `setHighlight(highlightOn, color)` Applies or removes a highlight from the node's background. If `isExplainHighlighted` is `true`, this method will not override the existing explanation highlight. - **`highlightOn`** (`boolean`): `true` to highlight, `false` to remove. - **`color`** (`string`, optional): The color of the highlight. Defaults to `omdColor.highlightColor`. ### `lowlight()` Reduces the opacity of the node's background. Similar to `setHighlight`, it respects the `isExplainHighlighted` lock. ### `setFillColor(color)` Sets the fill color of the node's background rectangle. This method also respects the `isExplainHighlighted` lock. ## Abstract Methods (to be implemented by subclasses) - **`computeDimensions()`**: Calculates the `width` and `height` of the node based on its content and children. Provides a default empty implementation. - **`updateLayout()`**: Positions the node's children relative to itself. Provides a default empty implementation. - **`getAlignmentBaseline()`**: Returns the vertical y-coordinate within the node's bounding box that should be used for alignment with its siblings. By default, this is the vertical center (`this.height / 2`). - **`isConstant()`**: Determines if the node represents a constant numerical value. Returns `false` by default. - **`getValue()`**: Retrieves the numerical value of a constant node. Throws an error if the node is not constant. - **`getRationalValue()`**: Retrieves the rational value of a constant node as a numerator/denominator pair. Throws an error if the node is not a constant rational expression. ## Internal Methods - **`_syncProvenanceFrom(originalNode)`**: Recursively walks a cloned node tree and sets the provenance of each node to point back to the corresponding node in the original tree. This is a crucial part of maintaining the provenance chain during cloning operations. - **`replaceNodeInParent(newNode)`**: Helper method used by `replaceWith` to update specific references to this node within its parent's `argumentNodeList` and other properties. - **`updateSvg(newNode)`**: Helper method used by `replaceWith` to perform the actual DOM manipulation (replacing SVG elements). - **`updateLayoutUpwards()`**: Traverses up the tree from this node's parent to re-calculate dimensions and layouts for all ancestors, ensuring the entire affected tree is correctly rendered after a change. - **`_validateStepsProvenance(issues)`**: Helper for `validateProvenance` to check provenance within steps. - **`_findOrphanedNodes(issues)`**: Helper for `validateProvenance` to find nodes in the `nodeMap` that are no longer part of the active tree. - **`_collectAllProvenanceIds(newNodeMap)`**: Collects all provenance IDs from nodes in a given map. - **`_collectNodeProvenanceIds(node, referencedIds, processedNodes)`**: Recursively collects provenance IDs for a single node. - **`_preserveReferencedNodes(referencedIds, newNodeMap)`**: Ensures that historical nodes referenced in provenance chains are kept in the `nodeMap`. - **`_preserveNodeAndContext(id, newNodeMap, processedIds)`**: Preserves a historical node and its relevant parent/sibling context. - **`_preserveParentContext(node, newNodeMap)`**: Preserves the parent nodes of a historical node. - **`_preserveSiblingContext(node, newNodeMap)`**: Preserves the sibling nodes of a historical node. ## Example ```javascript // omdNode is an abstract class - use concrete subclasses import { omdConstantNode } from './omdConstantNode.js'; import { omdBinaryExpressionNode } from './omdBinaryExpressionNode.js'; import { omdDisplay } from '../display/omdDisplay.js'; // Create a simple expression tree const two = new omdConstantNode({ value: 2 }); const x = new omdVariableNode({ name: 'x' }); const twoX = new omdBinaryExpressionNode({ type: 'OperatorNode', op: '*', fn: 'multiply', args: [two.astNodeData, x.astNodeData], implicit: true }); // Initialize the root node (this will recursively initialize children) twoX.initialize(); // Render it using omdDisplay const container = document.getElementById('math-container'); const display = new omdDisplay(container); display.render(twoX); console.log(twoX.toString()); // Output: 2x ``` ## See Also - [`omdLeafNode`](./omdLeafNode.md) - The base class for nodes with no children (constants, variables, operators). - [`omdBinaryExpressionNode`](./omdBinaryExpressionNode.md) - For nodes with two children (e.g., addition, subtraction, multiplication). - [`omdFunctionNode`](./omdFunctionNode.md) - For function calls (e.g., `sin(x)`). - [`omdEquationNode`](./omdEquationNode.md) - For representing mathematical equations.