@teachinglab/omd 0.1.4 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/canvas/tools/EraserTool.js +1 -1
  2. package/canvas/tools/PencilTool.js +1 -1
  3. package/canvas/tools/SelectTool.js +1 -1
  4. package/docs/api/configuration-options.md +198 -104
  5. package/docs/api/eventManager.md +83 -68
  6. package/docs/api/focusFrameManager.md +145 -150
  7. package/docs/api/index.md +106 -91
  8. package/docs/api/main.md +63 -58
  9. package/docs/api/omdBinaryExpressionNode.md +86 -227
  10. package/docs/api/omdCanvas.md +84 -142
  11. package/docs/api/omdConfigManager.md +113 -192
  12. package/docs/api/omdConstantNode.md +53 -117
  13. package/docs/api/omdDisplay.md +87 -121
  14. package/docs/api/omdEquationNode.md +174 -161
  15. package/docs/api/omdEquationSequenceNode.md +259 -301
  16. package/docs/api/omdEquationStack.md +157 -103
  17. package/docs/api/omdFunctionNode.md +83 -141
  18. package/docs/api/omdGroupNode.md +79 -182
  19. package/docs/api/omdHelpers.md +88 -96
  20. package/docs/api/omdLeafNode.md +86 -163
  21. package/docs/api/omdNode.md +202 -101
  22. package/docs/api/omdOperationDisplayNode.md +118 -139
  23. package/docs/api/omdOperatorNode.md +92 -127
  24. package/docs/api/omdParenthesisNode.md +134 -122
  25. package/docs/api/omdPopup.md +192 -117
  26. package/docs/api/omdPowerNode.md +132 -127
  27. package/docs/api/omdRationalNode.md +145 -128
  28. package/docs/api/omdSimplification.md +79 -110
  29. package/docs/api/omdSqrtNode.md +144 -79
  30. package/docs/api/omdStepVisualizer.md +147 -115
  31. package/docs/api/omdStepVisualizerHighlighting.md +66 -61
  32. package/docs/api/omdStepVisualizerInteractiveSteps.md +109 -129
  33. package/docs/api/omdStepVisualizerLayout.md +71 -60
  34. package/docs/api/omdStepVisualizerTextBoxes.md +77 -68
  35. package/docs/api/omdToolbar.md +131 -102
  36. package/docs/api/omdTranscriptionService.md +96 -76
  37. package/docs/api/omdTreeDiff.md +170 -134
  38. package/docs/api/omdUnaryExpressionNode.md +137 -174
  39. package/docs/api/omdUtilities.md +83 -70
  40. package/docs/api/omdVariableNode.md +123 -148
  41. package/index.js +2 -2
  42. package/package.json +1 -1
@@ -1,134 +1,170 @@
1
-
2
- # omdTreeDiff
3
-
4
- Implements a robust tree differencing algorithm to identify changes between two `omdNode` expression trees. Used by `omdStepVisualizerHighlighting` to provide visual feedback on how mathematical expressions transform from one step to the next.
5
-
6
- ## Algorithm Overview
7
-
8
- `omdTreeDiff` uses a multi-stage approach:
9
- 1. **Special Cases:** Attempts to identify common pedagogical patterns (like adding/subtracting the same value from both sides). If found, highlights those nodes.
10
- 2. **Generate All Matches:** Finds all possible pairs of subtrees between the old and new expressions that are either structurally identical or semantically equivalent (e.g., `2+3` and `5`).
11
- 3. **Select Optimal Set:** Selects the largest, non-overlapping set of matches, identifying the largest common sub-expressions between the two trees.
12
- 4. **Identify Changes:** Any parts of the new tree that are *not* part of these optimal matches are considered changes and are returned for highlighting.
13
- 5. **Educational Mode:** In educational mode, includes additional heuristics to highlight subtle simplifications that might not involve a direct structural change but are important for understanding the transformation.
14
-
15
- ## Class: `omdTreeDiff`
16
-
17
- ```javascript
18
- import { omdTreeDiff } from './omd/utils/omdTreeDiff.js';
19
- ```
20
-
21
-
22
- ## Static Methods
23
-
24
-
25
- ### `findChangedNodes(oldEquation, newEquation, options)`
26
-
27
- Main entry point for the tree differencing algorithm. Compares two `omdEquationNode` instances (or any `omdNode` subtrees) and returns a list of nodes in the `newEquation` that have changed or are new.
28
-
29
- - **Parameters:**
30
- - `oldEquation` {omdNode} - The root node of the previous expression tree.
31
- - `newEquation` {omdNode} - The root node of the current expression tree.
32
- - `options` {Object} (optional) - Configuration options:
33
- - `educationalMode` {boolean} - If `true`, the diff algorithm will also highlight mathematically neutral changes that are pedagogically significant (e.g., removing `+ 0`). Default: `false`.
34
- - **Returns:** {Array<omdNode>} An array of `omdNode` instances from `newEquation` that should be highlighted.
35
-
36
- ---
37
-
38
-
39
- ### `findEquationSpecialCases(oldEquation, newEquation)`
40
-
41
- Identifies specific equation-level transformation patterns, such as adding the same operation (e.g., `+ X` or `- X`) to both sides of an equation. Allows for more intuitive highlighting in common step-by-step solution scenarios.
42
-
43
- - **Parameters:**
44
- - `oldEquation` {omdEquationNode} - The previous equation.
45
- - `newEquation` {omdEquationNode} - The current equation.
46
- - **Returns:** {Array<omdNode>} An array of nodes to highlight for these special cases, or an empty array if no such pattern is found.
47
-
48
- ---
49
-
50
-
51
- ### `diffSubtrees(oldTree, newTree, educationalMode)`
52
-
53
- Core recursive differencing method. Attempts to find an optimal matching between subtrees of the `oldTree` and `newTree`. Nodes in `newTree` that do not have a match in `oldTree` are considered changed.
54
-
55
- - **Parameters:**
56
- - `oldTree` {omdNode} - The root of the old subtree.
57
- - `newTree` {omdNode} - The root of the new subtree.
58
- - `educationalMode` {boolean} - Same as in `findChangedNodes`.
59
- - **Returns:** {Array<omdNode>} An array of unmatched leaf nodes in `newTree`.
60
-
61
- ---
62
-
63
-
64
- ### `findEducationalHighlights(oldTree, newTree, optimalMatches)`
65
-
66
- When `educationalMode` is enabled, identifies additional nodes to highlight for pedagogical reasons, even if they don't represent a structural change. Includes cases like the removal of additive/multiplicative identities or double negations.
67
-
68
- - **Parameters:**
69
- - `oldTree` {omdNode} - The old expression tree.
70
- - `newTree` {omdNode} - The new expression tree.
71
- - `optimalMatches` {Array} - The list of optimally matched subtrees.
72
- - **Returns:** {Array<omdNode>} Additional nodes to highlight.
73
-
74
- ---
75
-
76
-
77
- ### `findAllSubtreeMatches(oldTree, newTree)`
78
-
79
- Generates all possible subtree matches between two expression trees. A match is determined by structural or string equivalence.
80
-
81
- - **Parameters:**
82
- - `oldTree` {omdNode} - The old expression tree.
83
- - `newTree` {omdNode} - The new expression tree.
84
- - **Returns:** {Array<Object>} An array of match objects, each containing `oldNode`, `newNode`, `size`, `score`, and `type` of match.
85
-
86
- ---
87
-
88
-
89
- ### `selectOptimalMatching(matches)`
90
-
91
- Given a list of all possible subtree matches, selects the optimal, non-overlapping set of matches. Uses a greedy approach, prioritizing larger and higher-scoring matches.
92
-
93
- - **Parameters:**
94
- - `matches` {Array<Object>} - The array of potential matches from `findAllSubtreeMatches`.
95
- - **Returns:** {Array<Object>} The selected optimal matches.
96
-
97
- ---
98
-
99
-
100
- ### `findUnmatchedLeafNodes(newTree, matches)`
101
-
102
- Identifies all leaf nodes in the `newTree` that are not covered by any of the `optimalMatches`. These are the nodes that represent the actual changes.
103
-
104
- - **Parameters:**
105
- - `newTree` {omdNode} - The new expression tree.
106
- - `matches` {Array<Object>} - The array of selected optimal matches.
107
- - **Returns:** {Array<omdNode>} An array of unmatched leaf nodes.
108
-
109
-
110
- ## Internal Helper Methods
111
-
112
- - `_findCommonPrefix(str1, str2)`: Finds the longest common string prefix.
113
- - `getAllSubtrees(root)`: Recursively collects all subtrees from a given root node.
114
- - `calculateSimilarity(tree1, tree2)`: Determines the similarity score between two subtrees.
115
- - `treesStructurallyEqual(tree1, tree2)`: Checks for exact structural equality between two subtrees.
116
- - `getSubtreeSize(root)`: Calculates the number of nodes in a subtree.
117
- - `hasNodeOverlap(node, usedNodes)`: Checks if a node or its descendants overlap with a set of used nodes.
118
- - `markSubtreeAsUsed(root, usedNodes)`: Marks all nodes in a subtree as used.
119
- - `findUnmatchedOldNodes(oldTree, matches)`: Finds leaf nodes in the old tree that were removed.
120
-
121
-
122
- ## How it Works
123
-
124
- See the Algorithm Overview above for a summary of the process. The class is designed for internal use by step visualizer components.
125
-
126
- ### Example
127
-
128
- This class is typically used internally by `omdStepVisualizerHighlighting`.
129
-
130
- ```javascript
131
- // Example of internal usage within omdStepVisualizerHighlighting:
132
- // const changedNodes = omdTreeDiff.findChangedNodes(previousEquation, currentEquation, { educationalMode: true });
133
- // changedNodes.forEach(node => node.setExplainHighlight(true));
134
- ```
1
+ # omdTreeDiff
2
+
3
+ Implements a robust tree differencing algorithm to identify changes between two `omdNode` expression trees. This module is crucial for `omdStepVisualizerHighlighting`, providing precise visual feedback on how mathematical expressions transform from one step to the next.
4
+
5
+ ## Algorithm Overview
6
+
7
+ `omdTreeDiff` uses a multi-stage approach to compare two expression trees (`oldEquation` and `newEquation`):
8
+
9
+ 1. **Special Cases**: It first attempts to identify common pedagogical patterns (like adding/subtracting the same value from both sides, or simple identity/double negative simplifications). If found, these specific changes are highlighted directly.
10
+ 2. **Optimal Subtree Matching**: If no special cases apply, it proceeds to find the largest, non-overlapping set of matched subtrees between the old and new expressions. A match can be either structurally identical or semantically equivalent (e.g., `2+3` and `5`).
11
+ 3. **Identify Changes**: Any parts of the `newEquation` that are *not* part of these optimal matches are considered the actual changes and are returned for highlighting.
12
+ 4. **Educational Mode**: When enabled, the algorithm includes additional heuristics to highlight subtle simplifications that might not involve a direct structural change but are important for understanding the transformation (e.g., removing `+ 0`).
13
+
14
+ ## Class Definition
15
+
16
+ ```javascript
17
+ export class omdTreeDiff
18
+ ```
19
+
20
+ This class is not meant to be instantiated. All its methods are static.
21
+
22
+ ## Static Methods
23
+
24
+ ### `findChangedNodes(oldEquation, newEquation, options)`
25
+
26
+ Main entry point for the tree differencing algorithm. Compares two `omdEquationNode` instances (or any `omdNode` subtrees) and returns a list of nodes in the `newEquation` that have changed or are new.
27
+
28
+ - **`oldEquation`** (`omdNode`): The root node of the previous expression tree.
29
+ - **`newEquation`** (`omdNode`): The root node of the current expression tree.
30
+ - **`options`** (`object`, optional): Configuration options:
31
+ - `educationalMode` (`boolean`): If `true`, the diff algorithm will also highlight mathematically neutral changes that are pedagogically significant (e.g., removing `+ 0`). Default: `false`.
32
+ - **Returns**: `Array<omdNode>` - An array of `omdNode` instances from `newEquation` that should be highlighted.
33
+
34
+ ### `findEquationSpecialCases(oldEquation, newEquation)`
35
+
36
+ Identifies specific equation-level transformation patterns, such as adding/subtracting the same operation to both sides of an equation. This allows for more intuitive highlighting in common step-by-step solution scenarios.
37
+
38
+ - **`oldEquation`** (`omdEquationNode`): The previous equation.
39
+ - **`newEquation`** (`omdEquationNode`): The current equation.
40
+ - **Returns**: `Array<omdNode>` - An array of nodes to highlight for these special cases, or an empty array if no such pattern is found.
41
+
42
+ ### `diffSubtrees(oldTree, newTree, educationalMode)`
43
+
44
+ Core recursive differencing method. It first checks for various pedagogical highlighting patterns (common prefix, variable preservation, type differences, subtraction patterns). If none apply, it falls back to finding an optimal matching between subtrees of the `oldTree` and `newTree`. Nodes in `newTree` that do not have a match in `oldTree` are considered changed.
45
+
46
+ - **`oldTree`** (`omdNode`): The root of the old subtree.
47
+ - **`newTree`** (`omdNode`): The root of the new subtree.
48
+ - **`educationalMode`** (`boolean`): Same as in `findChangedNodes`.
49
+ - **Returns**: `Array<omdNode>` - An array of unmatched leaf nodes in `newTree`.
50
+
51
+ ### `findEducationalHighlights(oldTree, newTree, optimalMatches)`
52
+
53
+ When `educationalMode` is enabled, this method identifies additional nodes to highlight for pedagogical reasons, even if they don't represent a structural change. This includes cases like the removal of additive/multiplicative identities or double negations.
54
+
55
+ - **`oldTree`** (`omdNode`): The old expression tree.
56
+ - **`newTree`** (`omdNode`): The new expression tree.
57
+ - **`optimalMatches`** (`Array`): The list of optimally matched subtrees.
58
+ - **Returns**: `Array<omdNode>` - Additional nodes to highlight.
59
+
60
+ ### `findAdditiveIdentityChanges(oldTree, newTree)`
61
+
62
+ Identifies changes related to the removal of additive identities (e.g., `+ 0` or `- 0`).
63
+
64
+ - **`oldTree`** (`omdNode`): The old expression tree.
65
+ - **`newTree`** (`omdNode`): The new expression tree.
66
+ - **Returns**: `Array<omdNode>` - Nodes to highlight for additive identity changes.
67
+
68
+ ### `findMultiplicativeIdentityChanges(oldTree, newTree)`
69
+
70
+ Identifies changes related to the removal of multiplicative identities (e.g., `* 1` or `/ 1`).
71
+
72
+ - **`oldTree`** (`omdNode`): The old expression tree.
73
+ - **`newTree`** (`omdNode`): The new expression tree.
74
+ - **Returns**: `Array<omdNode>` - Nodes to highlight for multiplicative identity changes.
75
+
76
+ ### `findDoubleNegativeChanges(oldTree, newTree)`
77
+
78
+ Identifies changes related to the simplification of double negatives (e.g., `--x` to `x`).
79
+
80
+ - **`oldTree`** (`omdNode`): The old expression tree.
81
+ - **`newTree`** (`omdNode`): The new expression tree.
82
+ - **Returns**: `Array<omdNode>` - Nodes to highlight for double negative removal.
83
+
84
+ ### `findCommonPrefixHighlights(oldTree, newTree)`
85
+
86
+ Identifies highlighting patterns based on common prefixes between the string representations of the old and new trees. For example, if `"2x + 4"` becomes `"2x + 4 - 4"`, it highlights only the `"- 4"` part.
87
+
88
+ - **`oldTree`** (`omdNode`): The old expression tree.
89
+ - **`newTree`** (`omdNode`): The new expression tree.
90
+ - **Returns**: `Array<omdNode>` - Nodes to highlight for common prefix patterns.
91
+
92
+ ### `findVariablePreservationHighlights(oldTree, newTree)`
93
+
94
+ Identifies highlighting patterns where a variable term remains the same but associated constants change. For example, `"2x + 4"` becoming `"2x + 2"` should highlight only the changed constant.
95
+
96
+ - **`oldTree`** (`omdNode`): The old expression tree.
97
+ - **`newTree`** (`omdNode`): The new expression tree.
98
+ - **Returns**: `Array<omdNode>` - Nodes to highlight for variable preservation patterns.
99
+
100
+ ### `findTypeDifferenceHighlights(oldTree, newTree)`
101
+
102
+ Identifies highlighting patterns where the type of an expression changes significantly (e.g., a constant becoming a binary expression). In such cases, it highlights the new expression.
103
+
104
+ - **`oldTree`** (`omdNode`): The old expression tree.
105
+ - **`newTree`** (`omdNode`): The new expression tree.
106
+ - **Returns**: `Array<omdNode>` - Nodes to highlight for type difference patterns.
107
+
108
+ ### `findSubtractionPatternHighlights(oldTree, newTree)`
109
+
110
+ Identifies highlighting patterns specific to subtraction, where the old tree matches the left side of a new subtraction. For example, `"x + 2"` becoming `"x + 2 - 2"` should highlight only the `"- 2"` part.
111
+
112
+ - **`oldTree`** (`omdNode`): The old expression tree.
113
+ - **`newTree`** (`omdNode`): The new expression tree.
114
+ - **Returns**: `Array<omdNode>` - Nodes to highlight for subtraction patterns.
115
+
116
+ ### `findAllSubtreeMatches(oldTree, newTree)`
117
+
118
+ Generates all possible subtree matches between two expression trees. A match is determined by structural or string equivalence.
119
+
120
+ - **`oldTree`** (`omdNode`): The old expression tree.
121
+ - **`newTree`** (`omdNode`): The new expression tree.
122
+ - **Returns**: `Array<object>` - An array of match objects, each containing `oldNode`, `newNode`, `size`, `score`, and `type` of match.
123
+
124
+ ### `selectOptimalMatching(matches)`
125
+
126
+ Given a list of all possible subtree matches, this method selects the optimal, non-overlapping set of matches. It uses a greedy approach, prioritizing larger and higher-scoring matches.
127
+
128
+ - **`matches`** (`Array<object>`): The array of potential matches from `findAllSubtreeMatches`.
129
+ - **Returns**: `Array<object>` - The selected optimal matches.
130
+
131
+ ### `findUnmatchedLeafNodes(newTree, matches)`
132
+
133
+ Identifies all leaf nodes in the `newTree` that are not covered by any of the `optimalMatches`. These are the nodes that represent the actual changes.
134
+
135
+ - **`newTree`** (`omdNode`): The new expression tree.
136
+ - **`matches`** (`Array<object>`): The array of selected optimal matches.
137
+ - **Returns**: `Array<omdNode>` - An array of unmatched leaf nodes.
138
+
139
+ ### `findUnmatchedOldNodes(oldTree, matches)`
140
+
141
+ Finds leaf nodes in the `oldTree` that are not covered by any match. These represent nodes that were removed or transformed.
142
+
143
+ - **`oldTree`** (`omdNode`): The old expression tree.
144
+ - **`matches`** (`Array<object>`): The array of selected optimal matches.
145
+ - **Returns**: `Array<omdNode>` - An array of unmatched leaf nodes from the old tree.
146
+
147
+ ## Internal Helper Methods
148
+
149
+ - **`_findCommonPrefix(str1, str2)`**: Finds the longest common string prefix between two strings.
150
+ - **`getAllSubtrees(root)`**: Recursively collects all subtrees from a given root node.
151
+ - **`calculateSimilarity(tree1, tree2)`**: Determines the similarity score between two subtrees, considering structural and string equivalence.
152
+ - **`treesStructurallyEqual(tree1, tree2)`**: Checks for exact structural equality between two subtrees.
153
+ - **`getSubtreeSize(root)`**: Calculates the number of nodes in a subtree.
154
+ - **`hasNodeOverlap(node, usedNodes)`**: Checks if a node or any of its descendants overlap with a set of already used nodes.
155
+ - **`markSubtreeAsUsed(root, usedNodes)`**: Marks all nodes in a subtree as used by adding them to a `Set`.
156
+ - **`debugPrintTree(node, depth)`**: A utility function for debugging that prints the structure of an `omdNode` tree to the console.
157
+
158
+ ## How it Works
159
+
160
+ See the Algorithm Overview above for a summary of the process. The class is designed for internal use by step visualizer components.
161
+
162
+ ### Example
163
+
164
+ This class is typically used internally by `omdStepVisualizerHighlighting`:
165
+
166
+ ```javascript
167
+ // Example of internal usage within omdStepVisualizerHighlighting:
168
+ // const changedNodes = omdTreeDiff.findChangedNodes(previousEquation, currentEquation, { educationalMode: true });
169
+ // changedNodes.forEach(node => node.setExplainHighlight(true));
170
+ ```
@@ -1,174 +1,137 @@
1
- # omdUnaryExpressionNode
2
-
3
- Represents unary operations (like negation) in mathematical expressions (e.g., `-x`, `-(a + b)`). Handles rendering, layout, evaluation, and conversion to math.js AST.
4
-
5
- ## Class: `omdUnaryExpressionNode extends omdNode`
6
-
7
- ```javascript
8
- import { omdUnaryExpressionNode } from './omd/nodes/omdUnaryExpressionNode.js';
9
- ```
10
-
11
- ### Constructor
12
-
13
- ```javascript
14
- new omdUnaryExpressionNode(ast)
15
- ```
16
-
17
- **Parameters:**
18
- - `ast` {Object} - The AST node containing:
19
- - `args`: Array with exactly 1 operand AST node
20
- - `op`: Operator symbol (e.g., '-')
21
- - `fn`: Operation name (e.g., 'unaryMinus')
22
-
23
- **Description:**
24
- Creates a node representing a unary operation (like negation) on an expression. Throws an error if the AST does not have exactly one argument.
25
-
26
- ### Properties
27
-
28
- Inherits all properties from [omdNode](./omdNode.md), plus:
29
-
30
- #### `op`
31
- - **Type:** [omdOperatorNode](./omdOperatorNode.md)
32
- - **Description:** The unary operator node (e.g., '-')
33
-
34
- #### `operand`
35
- - **Type:** [omdNode](./omdNode.md)
36
- - **Description:** The expression being operated on
37
-
38
- #### `operation`
39
- - **Type:** string
40
- - **Description:** The operation name (e.g., 'unaryMinus')
41
-
42
- ### Methods
43
-
44
- Inherits all methods from [omdNode](./omdNode.md), plus:
45
-
46
- #### `createOperatorNode(ast)`
47
- Internal method to create operator node.
48
- - `ast` {Object} - The AST with operator info
49
- - **Returns:** omdOperatorNode
50
-
51
- ---
52
-
53
- #### `createExpressionNode(ast)`
54
- Internal method to create operand node.
55
- - `ast` {Object} - The AST for the operand
56
- - **Returns:** omdNode
57
-
58
- ---
59
-
60
- #### `computeDimensions()`
61
- Calculates dimensions of expression.
62
- - Computes dimensions of operator and operand
63
- - Sets total width and height
64
- - No extra spacing for unary minus
65
-
66
- ---
67
-
68
- #### `updateLayout()`
69
- Updates positions of elements.
70
- - Centers operator and operand vertically
71
- - Places operator before operand
72
-
73
- ---
74
-
75
- #### `clone()`
76
- Creates a deep clone of the expression node, including operator and operand, and preserves provenance.
77
- - **Returns:** omdUnaryExpressionNode - New instance with:
78
- - Cloned AST data
79
- - Preserved background rectangle
80
- - Cloned operator and operand
81
- - Rebuilt argument list
82
- - Original node's ID added to provenance array
83
-
84
- ---
85
-
86
- #### `toMathJSNode()`
87
- Converts to math.js AST format.
88
- - **Returns:** Object - A math.js-compatible AST node with:
89
- - `type`: "OperatorNode"
90
- - `op`: Operator symbol
91
- - `fn`: Operation name
92
- - `args`: [operand AST]
93
- - `id`: Node ID
94
- - `provenance`: Provenance array
95
-
96
- ---
97
-
98
- #### `toString()`
99
- Convert to string representation.
100
- - Adds parentheses if needed
101
- - **Returns:** string - Format: "-operand" or "-(operand)"
102
-
103
- ---
104
-
105
- #### `needsParentheses()`
106
- Check if operand needs parentheses.
107
- - **Returns:** boolean - True if operand is binary expression
108
-
109
- ---
110
-
111
- #### `evaluate(variables)`
112
- Evaluate the expression.
113
- - `variables` {Object} - Variable name to value mapping
114
- - **Returns:** number - Negated value for '-', same value for '+'
115
- - **Returns:** NaN if operand can't be evaluated
116
-
117
- ---
118
-
119
- #### `simplify()`
120
- Attempt to simplify expression using the central simplification engine.
121
- - **Returns:** Object with:
122
- - `success`: Whether simplified
123
- - `newRoot`: Simplified expression
124
- - `message`: Description of changes
125
-
126
- ### Static Methods
127
-
128
- #### `fromString(expressionString)`
129
- Create node from string.
130
- - `expressionString` {string} - Expression with unary operation
131
- - **Returns:** omdUnaryExpressionNode
132
- - **Throws:** Error if not unary minus operation or if parsing fails
133
-
134
- ### Example
135
-
136
- ```javascript
137
- // Create from AST
138
- const node = new omdUnaryExpressionNode({
139
- type: 'OperatorNode',
140
- op: '-',
141
- fn: 'unaryMinus',
142
- args: [
143
- { type: 'SymbolNode', name: 'x' }
144
- ]
145
- });
146
-
147
- // Complex operand
148
- const complex = new omdUnaryExpressionNode({
149
- type: 'OperatorNode',
150
- op: '-',
151
- fn: 'unaryMinus',
152
- args: [{
153
- type: 'OperatorNode',
154
- op: '+',
155
- fn: 'add',
156
- args: [
157
- { type: 'SymbolNode', name: 'x' },
158
- { type: 'ConstantNode', value: 1 }
159
- ]
160
- }]
161
- });
162
-
163
- // Render with proper spacing
164
- node.setFontSize(24);
165
- node.computeDimensions();
166
- node.updateLayout();
167
- ```
168
-
169
- ### See Also
170
-
171
- - [omdNode](./omdNode.md) - Parent class
172
- - [omdOperatorNode](./omdOperatorNode.md) - For operator symbol
173
- - [omdBinaryExpressionNode](./omdBinaryExpressionNode.md) - For complex operands
174
- - [omdConstantNode](./omdConstantNode.md) - For numeric operands
1
+ # omdUnaryExpressionNode
2
+
3
+ Represents unary operations (like negation) in mathematical expressions (e.g., `-x`, `-(a + b)`). This node handles rendering, layout, evaluation, and conversion to math.js AST for expressions with a single operand.
4
+
5
+ ## Class Definition
6
+
7
+ ```javascript
8
+ export class omdUnaryExpressionNode extends omdNode
9
+ ```
10
+
11
+ ## Constructor
12
+
13
+ ### `new omdUnaryExpressionNode(ast)`
14
+
15
+ Creates a new `omdUnaryExpressionNode` instance.
16
+
17
+ - **`ast`** (`object`): The math.js AST node for the unary operation. It must contain:
18
+ - `args`: An array with exactly one operand AST node.
19
+ - `op`: The operator symbol (e.g., `'-'`, `'+'`).
20
+ - `fn`: The operation name (e.g., `'unaryMinus'`, `'unaryPlus'`).
21
+
22
+ During construction, it creates an `omdOperatorNode` for the unary operator and an `omdNode` for the operand. It throws an error if the AST does not have exactly one argument.
23
+
24
+ ## Static Methods
25
+
26
+ ### `fromString(expressionString)`
27
+
28
+ Creates an `omdUnaryExpressionNode` from a string representation of a unary expression. Requires `window.math` (math.js) to be available globally for parsing.
29
+
30
+ - **`expressionString`** (`string`): The unary expression as a string (e.g., `"-x"`, `"-(a+b)"`).
31
+ - **Returns**: `omdUnaryExpressionNode` - A new instance.
32
+ - **Throws**: `Error` if `math.js` is not available, if the string cannot be parsed, or if it does not represent a valid unary minus operation.
33
+
34
+ ## Public Properties
35
+
36
+ - **`op`** (`omdOperatorNode`): The `omdOperatorNode` representing the unary operator (e.g., `-`).
37
+ - **`operand`** (`omdNode`): The `omdNode` representing the expression being operated on.
38
+ - **`operation`** (`string`): The name of the operation (e.g., `'unaryMinus'`).
39
+
40
+ ## Public Methods
41
+
42
+ ### `computeDimensions()`
43
+
44
+ Calculates the dimensions of the unary expression node. It sums the widths of the operator and the operand to get the total width. The height is the maximum of the operator's and operand's heights. No extra spacing is added between the unary operator and its operand.
45
+
46
+ - **Overrides**: `omdNode.computeDimensions()`.
47
+
48
+ ### `updateLayout()`
49
+
50
+ Updates the layout of the unary expression node. It positions the operator to the left and the operand to its right, both vertically centered within the node's total height.
51
+
52
+ - **Overrides**: `omdNode.updateLayout()`.
53
+
54
+ ### `clone()`
55
+
56
+ Creates a deep, structural clone of the unary expression node, including its `op` and `operand` nodes. The cloned node's `provenance` array is updated to include the original node's ID.
57
+
58
+ - **Returns**: `omdUnaryExpressionNode` - A new, identical instance of the unary expression node.
59
+
60
+ ### `toMathJSNode()`
61
+
62
+ Converts the `omdUnaryExpressionNode` back into its math.js AST representation. It creates an `OperatorNode` with the unary operator and the converted operand AST.
63
+
64
+ - **Returns**: `object` - A math.js `OperatorNode` for the unary operation. The returned object also includes a `clone` method for compatibility.
65
+
66
+ ### `toString()`
67
+
68
+ Converts the unary expression node to its string representation. It adds parentheses around the operand if `needsParentheses()` returns `true` (e.g., for binary expressions).
69
+
70
+ - **Returns**: `string` - Format: `"-operand"` or `"-(operand)"`.
71
+
72
+ ### `needsParentheses()`
73
+
74
+ Checks if the operand needs to be wrapped in parentheses when converted to a string. This is typically `true` if the operand is a binary expression, to maintain correct order of operations.
75
+
76
+ - **Returns**: `boolean` - `true` if parentheses are required around the operand.
77
+
78
+ ### `evaluate(variables)`
79
+
80
+ Evaluates the unary expression. It evaluates the `operand` and then applies the unary operation (e.g., negation for `'-'`).
81
+
82
+ - **`variables`** (`object`): A map of variable names to their numeric values.
83
+ - **Returns**: `number` - The result of the unary operation, or `NaN` if the operand cannot be evaluated to a number.
84
+
85
+ ## Internal Methods
86
+
87
+ - **`createOperatorNode(ast)`**: Creates an `omdOperatorNode` for the unary operator from its AST, setting its parent to this node.
88
+ - **`createExpressionNode(ast)`**: Creates an `omdNode` instance for the operand from its AST, setting its parent to this node.
89
+
90
+ ## Example
91
+
92
+ ```javascript
93
+ import { omdUnaryExpressionNode } from '@teachinglab/omd';
94
+ import * as math from 'mathjs';
95
+
96
+ // Create from AST: -x
97
+ const node = new omdUnaryExpressionNode({
98
+ type: 'OperatorNode',
99
+ op: '-',
100
+ fn: 'unaryMinus',
101
+ args: [
102
+ { type: 'SymbolNode', name: 'x' }
103
+ ]
104
+ });
105
+
106
+ // Create from AST: -(x + 1)
107
+ const complex = new omdUnaryExpressionNode({
108
+ type: 'OperatorNode',
109
+ op: '-',
110
+ fn: 'unaryMinus',
111
+ args: [{
112
+ type: 'OperatorNode',
113
+ op: '+',
114
+ fn: 'add',
115
+ args: [
116
+ { type: 'SymbolNode', name: 'x' },
117
+ { type: 'ConstantNode', value: 1 }
118
+ ]
119
+ }]
120
+ });
121
+
122
+ // Render and layout
123
+ node.setFontSize(24);
124
+ node.initialize();
125
+
126
+ // Add to an SVG container to display
127
+ // const svgContainer = new jsvgContainer();
128
+ // svgContainer.addChild(node);
129
+ // document.body.appendChild(svgContainer.svgObject);
130
+ ```
131
+
132
+ ## See Also
133
+
134
+ - [`omdNode`](./omdNode.md) - Parent class.
135
+ - [`omdOperatorNode`](./omdOperatorNode.md) - For the operator symbol.
136
+ - [`omdBinaryExpressionNode`](./omdBinaryExpressionNode.md) - Often used for complex operands within a unary expression.
137
+ - [`omdConstantNode`](./omdConstantNode.md) - For numeric operands.