@teachinglab/omd 0.5.7 → 0.5.8
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.
- package/index.js +3 -0
- package/npm-docs/DOCUMENTATION_SUMMARY.md +220 -0
- package/npm-docs/README.md +251 -0
- package/npm-docs/api/api-reference.md +85 -0
- package/npm-docs/api/configuration-options.md +198 -0
- package/npm-docs/api/eventManager.md +83 -0
- package/npm-docs/api/expression-nodes.md +561 -0
- package/npm-docs/api/focusFrameManager.md +145 -0
- package/npm-docs/api/index.md +106 -0
- package/npm-docs/api/main.md +63 -0
- package/npm-docs/api/omdBinaryExpressionNode.md +86 -0
- package/npm-docs/api/omdCanvas.md +84 -0
- package/npm-docs/api/omdConfigManager.md +113 -0
- package/npm-docs/api/omdConstantNode.md +53 -0
- package/npm-docs/api/omdDisplay.md +87 -0
- package/npm-docs/api/omdEquationNode.md +174 -0
- package/npm-docs/api/omdEquationSequenceNode.md +259 -0
- package/npm-docs/api/omdEquationStack.md +193 -0
- package/npm-docs/api/omdFunctionNode.md +83 -0
- package/npm-docs/api/omdGroupNode.md +79 -0
- package/npm-docs/api/omdHelpers.md +88 -0
- package/npm-docs/api/omdLeafNode.md +86 -0
- package/npm-docs/api/omdNode.md +202 -0
- package/npm-docs/api/omdOperationDisplayNode.md +118 -0
- package/npm-docs/api/omdOperatorNode.md +92 -0
- package/npm-docs/api/omdParenthesisNode.md +134 -0
- package/npm-docs/api/omdPopup.md +192 -0
- package/npm-docs/api/omdPowerNode.md +132 -0
- package/npm-docs/api/omdRationalNode.md +145 -0
- package/npm-docs/api/omdSequenceNode.md +128 -0
- package/npm-docs/api/omdSimplification.md +79 -0
- package/npm-docs/api/omdSqrtNode.md +144 -0
- package/npm-docs/api/omdStepVisualizer.md +147 -0
- package/npm-docs/api/omdStepVisualizerHighlighting.md +66 -0
- package/npm-docs/api/omdStepVisualizerInteractiveSteps.md +109 -0
- package/npm-docs/api/omdStepVisualizerLayout.md +71 -0
- package/npm-docs/api/omdStepVisualizerNodeUtils.md +140 -0
- package/npm-docs/api/omdStepVisualizerTextBoxes.md +77 -0
- package/npm-docs/api/omdToolbar.md +131 -0
- package/npm-docs/api/omdTranscriptionService.md +96 -0
- package/npm-docs/api/omdTreeDiff.md +170 -0
- package/npm-docs/api/omdUnaryExpressionNode.md +137 -0
- package/npm-docs/api/omdUtilities.md +83 -0
- package/npm-docs/api/omdVariableNode.md +123 -0
- package/npm-docs/api/selectTool.md +74 -0
- package/npm-docs/api/simplificationEngine.md +98 -0
- package/npm-docs/api/simplificationRules.md +77 -0
- package/npm-docs/api/simplificationUtils.md +64 -0
- package/npm-docs/api/transcribe.md +43 -0
- package/npm-docs/guides/equations.md +854 -0
- package/npm-docs/guides/factory-functions.md +354 -0
- package/npm-docs/guides/getting-started.md +318 -0
- package/npm-docs/guides/quick-examples.md +525 -0
- package/npm-docs/guides/visualizations.md +682 -0
- package/npm-docs/json-schemas.md +826 -0
- package/omd/utils/omdTranscriptionService.js +1 -1
- package/package.json +2 -1
- package/src/index.js +2 -0
- package/src/omdFactory.js +150 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# omdTranscriptionService
|
|
2
|
+
|
|
3
|
+
The `omdTranscriptionService` class provides an interface to an AI-powered transcription service for handwritten content. It sends image data to a server-side endpoint for processing, abstracting away the complexities of AI model interaction and API key management.
|
|
4
|
+
|
|
5
|
+
## Class Definition
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
export class omdTranscriptionService
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Constructor
|
|
12
|
+
|
|
13
|
+
### `new omdTranscriptionService([options])`
|
|
14
|
+
|
|
15
|
+
Creates a new `omdTranscriptionService` instance.
|
|
16
|
+
|
|
17
|
+
- **`options`** (`object`, optional): Configuration options for the service:
|
|
18
|
+
- `endpoint` (`string`): The server endpoint for the transcription service. Defaults to `'/.netlify/functions/transcribe'`.
|
|
19
|
+
- `defaultProvider` (`string`): The default transcription provider to use. Defaults to `'gemini'`.
|
|
20
|
+
|
|
21
|
+
## Public Properties
|
|
22
|
+
|
|
23
|
+
- **`options`** (`object`): The configuration options for the service, including `endpoint` and `defaultProvider`.
|
|
24
|
+
|
|
25
|
+
## Public Methods
|
|
26
|
+
|
|
27
|
+
### `async transcribe(imageBlob, [options])`
|
|
28
|
+
|
|
29
|
+
Transcribes an image containing handwritten content by sending it to the configured server endpoint. The image is converted to base64 before transmission.
|
|
30
|
+
|
|
31
|
+
- **`imageBlob`** (`Blob`): The image blob to transcribe.
|
|
32
|
+
- **`options`** (`object`, optional): Transcription options:
|
|
33
|
+
- `prompt` (`string`): A custom prompt for the transcription service. If not provided, a default mathematical transcription prompt is used.
|
|
34
|
+
- **Returns**: `Promise<object>` - A promise that resolves with the transcription result, containing the `text`, `provider`, and `confidence`.
|
|
35
|
+
- **Throws**: `Error` if the API call fails.
|
|
36
|
+
|
|
37
|
+
### `async transcribeWithFallback(imageBlob, [options])`
|
|
38
|
+
|
|
39
|
+
Transcribes an image with a fallback mechanism. Currently, this method simply calls `transcribe()`, but it is designed to allow for future implementations of fallback transcription providers or strategies.
|
|
40
|
+
|
|
41
|
+
- **`imageBlob`** (`Blob`): The image blob to transcribe.
|
|
42
|
+
- **`options`** (`object`, optional): Transcription options.
|
|
43
|
+
- **Returns**: `Promise<object>` - A promise that resolves with the transcription result.
|
|
44
|
+
|
|
45
|
+
### `isAvailable()`
|
|
46
|
+
|
|
47
|
+
Checks if the transcription service is available. In the current implementation, this always returns `true` as it relies on a serverless function endpoint.
|
|
48
|
+
|
|
49
|
+
- **Returns**: `boolean` - `true` if the service is available, `false` otherwise.
|
|
50
|
+
|
|
51
|
+
### `getAvailableProviders()`
|
|
52
|
+
|
|
53
|
+
Gets the list of available transcription providers. In the current implementation, this always returns `['gemini']` as the server handles the actual provider selection.
|
|
54
|
+
|
|
55
|
+
- **Returns**: `Array<string>` - An array of available provider names.
|
|
56
|
+
|
|
57
|
+
### `isProviderAvailable(provider)`
|
|
58
|
+
|
|
59
|
+
Checks if a specific transcription provider is available. In the current implementation, this only returns `true` for the `'gemini'` provider.
|
|
60
|
+
|
|
61
|
+
- **`provider`** (`string`): The name of the provider to check.
|
|
62
|
+
- **Returns**: `boolean` - `true` if the provider is available, `false` otherwise.
|
|
63
|
+
|
|
64
|
+
## Internal Methods
|
|
65
|
+
|
|
66
|
+
- **`_getDefaultEndpoint()`**: Returns the default server endpoint URL for the transcription service (`'/.netlify/functions/transcribe'`).
|
|
67
|
+
- **`_blobToBase64(blob)`**: Converts an `imageBlob` into a base64 encoded string, suitable for sending in a JSON payload.
|
|
68
|
+
|
|
69
|
+
## Example Usage
|
|
70
|
+
|
|
71
|
+
```javascript
|
|
72
|
+
import { omdTranscriptionService } from '@teachinglab/omd';
|
|
73
|
+
|
|
74
|
+
// Create a transcription service instance
|
|
75
|
+
const transcriptionService = new omdTranscriptionService();
|
|
76
|
+
|
|
77
|
+
// Assume getMyImageBlob() is a function that returns an image Blob
|
|
78
|
+
async function getMyImageBlob() {
|
|
79
|
+
// Example: Create a dummy canvas and get its blob
|
|
80
|
+
const canvas = document.createElement('canvas');
|
|
81
|
+
canvas.width = 100; canvas.height = 50;
|
|
82
|
+
const ctx = canvas.getContext('2d');
|
|
83
|
+
ctx.fillText('2x + 3', 10, 30);
|
|
84
|
+
return new Promise(resolve => canvas.toBlob(resolve, 'image/png'));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Get an image blob from a canvas or file input
|
|
88
|
+
const imageBlob = await getMyImageBlob();
|
|
89
|
+
|
|
90
|
+
// Transcribe the image
|
|
91
|
+
const result = await transcriptionService.transcribe(imageBlob, {
|
|
92
|
+
prompt: 'Transcribe the handwritten math equation. Return only the mathematical expression.'
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
console.log(result.text); // The transcribed text (e.g., "2x + 3")
|
|
96
|
+
```
|
|
@@ -0,0 +1,170 @@
|
|
|
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
|
+
```
|
|
@@ -0,0 +1,137 @@
|
|
|
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.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# omdUtilities
|
|
2
|
+
|
|
3
|
+
This module provides a collection of utility functions primarily used for mapping math.js AST nodes to OMD node classes, determining rendering behavior, and calculating text dimensions. These functions are internal helpers that support the core OMD node system.
|
|
4
|
+
|
|
5
|
+
## Functions
|
|
6
|
+
|
|
7
|
+
### `astToOmdType(type, ast)`
|
|
8
|
+
|
|
9
|
+
Maps a math.js AST node type to its corresponding OMD node class. This function is crucial for dynamically creating the correct `omdNode` subclass based on the parsed expression.
|
|
10
|
+
|
|
11
|
+
- **`type`** (`string`): The `type` property of the AST node (e.g., `"OperatorNode"`, `"ParenthesisNode"`).
|
|
12
|
+
- **`ast`** (`object`): The full AST node object, which may contain additional context (e.g., `op` for `OperatorNode`, `fn` for `FunctionNode`).
|
|
13
|
+
- **Returns**: `class` - The appropriate `omdNode` class constructor.
|
|
14
|
+
|
|
15
|
+
**Detailed Logic:**
|
|
16
|
+
|
|
17
|
+
- **`AssignmentNode`**: Returns `omdEquationNode`.
|
|
18
|
+
- **`OperatorNode`**:
|
|
19
|
+
- If `op` is `'-'` and `args.length` is `1` (unary minus), returns `omdUnaryExpressionNode`.
|
|
20
|
+
- If `op` is `'='`, returns `omdEquationNode`.
|
|
21
|
+
- If `op` is `'^'`, returns `omdPowerNode`.
|
|
22
|
+
- If `op` is `'/'`, returns `omdRationalNode`.
|
|
23
|
+
- Otherwise (binary operator), returns `omdBinaryExpressionNode`.
|
|
24
|
+
- **`ParenthesisNode`**: Returns `omdParenthesisNode`.
|
|
25
|
+
- **`ConstantNode`**: Returns `omdConstantNode`.
|
|
26
|
+
- **`SymbolNode`**: Returns `omdVariableNode`.
|
|
27
|
+
- **`FunctionNode`**:
|
|
28
|
+
- If `fn.name` or `name` is `'multiply'` and `ast.implicit` is `true` (implicit multiplication), returns `omdBinaryExpressionNode`.
|
|
29
|
+
- If `fn.name` or `name` is `'sqrt'`, returns `omdSqrtNode`.
|
|
30
|
+
- Otherwise, returns `omdFunctionNode`.
|
|
31
|
+
- **Default**: Returns `omdNode`.
|
|
32
|
+
|
|
33
|
+
### `getNodeForAST(ast)`
|
|
34
|
+
|
|
35
|
+
A wrapper function that takes a complete math.js AST node and returns the corresponding OMD node class. It uses `astToOmdType` internally, handling cases where the AST might have a `mathjs` property indicating its type.
|
|
36
|
+
|
|
37
|
+
- **`ast`** (`object`): The math.js AST node.
|
|
38
|
+
- **Returns**: `class` - The appropriate `omdNode` class constructor.
|
|
39
|
+
|
|
40
|
+
### `getTextBounds(text, fontSize)`
|
|
41
|
+
|
|
42
|
+
Calculates the rendered width and height of a given text string at a specific font size. This is achieved by creating a temporary, hidden `<span>` element in the DOM, applying the text and styling, measuring its dimensions, and then removing it.
|
|
43
|
+
|
|
44
|
+
- **`text`** (`string`): The text content to measure.
|
|
45
|
+
- **`fontSize`** (`number`): The font size in pixels.
|
|
46
|
+
- **Returns**: `object` - An object with `width` and `height` properties.
|
|
47
|
+
|
|
48
|
+
### `shouldUseFractionNotation(ast)`
|
|
49
|
+
|
|
50
|
+
Determines whether a division operation (represented by an AST node) should be rendered as a fraction (stacked numerator over denominator) or as a linear division (e.g., `a / b`). This decision is based on the complexity of the numerator and denominator.
|
|
51
|
+
|
|
52
|
+
- **`ast`** (`object`): The AST node representing a division operation.
|
|
53
|
+
- **Returns**: `boolean` - `true` if the division should be rendered as a fraction, `false` otherwise.
|
|
54
|
+
|
|
55
|
+
### `isComplexExpression(ast)`
|
|
56
|
+
|
|
57
|
+
Checks if an AST node represents a "complex" expression, typically one that contains multiple operations or nested structures. This function is used by `shouldUseFractionNotation` to decide on the appropriate rendering style for fractions.
|
|
58
|
+
|
|
59
|
+
- **`ast`** (`object`): The AST node to check.
|
|
60
|
+
- **Returns**: `boolean` - `true` if the expression is considered complex, `false` otherwise.
|
|
61
|
+
|
|
62
|
+
## Example
|
|
63
|
+
|
|
64
|
+
```javascript
|
|
65
|
+
import { getNodeForAST, getTextBounds } from '@teachinglab/omd'; // Assuming @teachinglab/omd exports these
|
|
66
|
+
import * as math from 'mathjs';
|
|
67
|
+
|
|
68
|
+
// Example of getting a node class for an expression
|
|
69
|
+
const astExpression = math.parse('x + 2');
|
|
70
|
+
const NodeClassExpression = getNodeForAST(astExpression);
|
|
71
|
+
const nodeExpression = new NodeClassExpression(astExpression);
|
|
72
|
+
console.log(nodeExpression.type); // e.g., "omdBinaryExpressionNode"
|
|
73
|
+
|
|
74
|
+
// Example of getting a node class for an equation
|
|
75
|
+
const astEquation = math.parse('y = 2x');
|
|
76
|
+
const NodeClassEquation = getNodeForAST(astEquation);
|
|
77
|
+
const nodeEquation = new NodeClassEquation(astEquation);
|
|
78
|
+
console.log(nodeEquation.type); // "omdEquationNode"
|
|
79
|
+
|
|
80
|
+
// Example of getting text bounds
|
|
81
|
+
const bounds = getTextBounds('Hello World', 24);
|
|
82
|
+
console.log(`Text width: ${bounds.width}, height: ${bounds.height}`);
|
|
83
|
+
```
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# omdVariableNode
|
|
2
|
+
|
|
3
|
+
Represents a variable (like `x`, `y`, `a`, `b`) in mathematical expressions. This node handles the visual representation of variables, their evaluation, and conversion to math.js AST.
|
|
4
|
+
|
|
5
|
+
## Class Definition
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
export class omdVariableNode extends omdLeafNode
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Constructor
|
|
12
|
+
|
|
13
|
+
### `new omdVariableNode(nodeData)`
|
|
14
|
+
|
|
15
|
+
Creates a new `omdVariableNode` instance.
|
|
16
|
+
|
|
17
|
+
- **`nodeData`** (`object` | `string`): The AST node data (from math.js, typically a `SymbolNode` with a `name` property) or the variable name as a string (e.g., `"x"`). The constructor extracts the variable `name` and creates the `textElement` for display.
|
|
18
|
+
|
|
19
|
+
## Static Methods
|
|
20
|
+
|
|
21
|
+
### `fromName(name)`
|
|
22
|
+
|
|
23
|
+
Creates a variable node directly from a given name string. This is a convenience method for creating simple variable nodes without needing to construct a full AST object.
|
|
24
|
+
|
|
25
|
+
- **`name`** (`string`): The variable name (e.g., `"x"`, `"theta"`).
|
|
26
|
+
- **Returns**: `omdVariableNode` - A new instance of `omdVariableNode`.
|
|
27
|
+
|
|
28
|
+
## Public Properties
|
|
29
|
+
|
|
30
|
+
- **`name`** (`string`): The name of the variable (e.g., `'x'`, `'y'`, `'theta'`).
|
|
31
|
+
- **`type`** (`string`): Always `"omdVariableNode"`.
|
|
32
|
+
- **`textElement`** (`jsvgTextLine`): The internal `jsvgTextLine` instance that displays the variable name.
|
|
33
|
+
|
|
34
|
+
## Public Methods
|
|
35
|
+
|
|
36
|
+
### `computeDimensions()`
|
|
37
|
+
|
|
38
|
+
Calculates the dimensions of the node based on its text content, adding a small amount of padding around the variable name to improve visual spacing.
|
|
39
|
+
|
|
40
|
+
- **Overrides**: `omdLeafNode.computeDimensions()`.
|
|
41
|
+
|
|
42
|
+
### `updateLayout()`
|
|
43
|
+
|
|
44
|
+
Updates the layout of the node. This method primarily calls the superclass's `updateLayout`.
|
|
45
|
+
|
|
46
|
+
- **Overrides**: `omdLeafNode.updateLayout()`.
|
|
47
|
+
|
|
48
|
+
### `toMathJSNode()`
|
|
49
|
+
|
|
50
|
+
Converts the `omdVariableNode` to a math.js-compatible AST format. It creates a `SymbolNode` with the variable's `name`, `id`, and `provenance`.
|
|
51
|
+
|
|
52
|
+
- **Returns**: `object` - A math.js-compatible AST node with `type: "SymbolNode"` and `name` set to the variable name. The returned object also includes `id`, `provenance`, and a `clone` method for compatibility.
|
|
53
|
+
|
|
54
|
+
### `highlight(color)`
|
|
55
|
+
|
|
56
|
+
Applies a highlight to the node's background and sets the variable's text color to white for better contrast. This method respects the `isExplainHighlighted` lock.
|
|
57
|
+
|
|
58
|
+
- **`color`** (`string`): The color of the highlight.
|
|
59
|
+
|
|
60
|
+
### `clearProvenanceHighlights()`
|
|
61
|
+
|
|
62
|
+
Clears any provenance-related highlights from the node and resets the variable's text color to its default (black).
|
|
63
|
+
|
|
64
|
+
### `toString()`
|
|
65
|
+
|
|
66
|
+
Converts the variable node to its string representation, which is simply its `name`.
|
|
67
|
+
|
|
68
|
+
- **Returns**: `string` - The variable name.
|
|
69
|
+
|
|
70
|
+
### `evaluate(variables)`
|
|
71
|
+
|
|
72
|
+
Evaluates the variable by looking up its value in the provided `variables` map. If the variable is not defined in the map, it throws an error.
|
|
73
|
+
|
|
74
|
+
- **`variables`** (`object`): A map of variable names to their numeric values.
|
|
75
|
+
- **Returns**: `number` - The value of the variable.
|
|
76
|
+
- **Throws**: `Error` if the variable is not defined in the map.
|
|
77
|
+
|
|
78
|
+
## Internal Methods
|
|
79
|
+
|
|
80
|
+
- **`parseName(nodeData)`**: Extracts the variable name from the constructor's `nodeData`. It handles both string input and AST objects with a `name` property.
|
|
81
|
+
- **`parseType()`**: Sets the node's type. Always returns `"variable"`.
|
|
82
|
+
|
|
83
|
+
## Examples
|
|
84
|
+
|
|
85
|
+
#### Creating Variables
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
import { omdVariableNode } from '@teachinglab/omd';
|
|
89
|
+
import * as math from 'mathjs';
|
|
90
|
+
|
|
91
|
+
// From a name string
|
|
92
|
+
const nodeX = omdVariableNode.fromName('x');
|
|
93
|
+
const nodeTheta = omdVariableNode.fromName('θ');
|
|
94
|
+
|
|
95
|
+
// From AST data (e.g., from math.js parse result)
|
|
96
|
+
const astNode = math.parse('y');
|
|
97
|
+
const nodeY = new omdVariableNode(astNode);
|
|
98
|
+
|
|
99
|
+
// Direct string name (less common, but supported)
|
|
100
|
+
const nodeZ = new omdVariableNode('z');
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
#### Rendering Variables
|
|
104
|
+
|
|
105
|
+
```javascript
|
|
106
|
+
import { omdVariableNode } from '@teachinglab/omd';
|
|
107
|
+
// import { jsvgContainer } from '@teachinglab/jsvg'; // if rendering directly
|
|
108
|
+
|
|
109
|
+
const node = omdVariableNode.fromName('x');
|
|
110
|
+
node.setFontSize(24);
|
|
111
|
+
node.initialize(); // Computes dimensions and layout
|
|
112
|
+
|
|
113
|
+
// To render, typically add to a parent node or an omdDisplay
|
|
114
|
+
// const svgContainer = new jsvgContainer();
|
|
115
|
+
// svgContainer.addChild(node);
|
|
116
|
+
// document.body.appendChild(svgContainer.svgObject);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## See Also
|
|
120
|
+
|
|
121
|
+
- [`omdLeafNode`](./omdLeafNode.md) - Parent class.
|
|
122
|
+
- [`omdNode`](./omdNode.md) - Base class.
|
|
123
|
+
- [`omdConstantNode`](./omdConstantNode.md) - For numeric values.
|