@teachinglab/omd 0.1.0

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 (144) hide show
  1. package/README.md +138 -0
  2. package/canvas/core/canvasConfig.js +203 -0
  3. package/canvas/core/omdCanvas.js +475 -0
  4. package/canvas/drawing/segment.js +168 -0
  5. package/canvas/drawing/stroke.js +386 -0
  6. package/canvas/events/eventManager.js +435 -0
  7. package/canvas/events/pointerEventHandler.js +263 -0
  8. package/canvas/features/focusFrameManager.js +287 -0
  9. package/canvas/index.js +49 -0
  10. package/canvas/tools/eraserTool.js +322 -0
  11. package/canvas/tools/pencilTool.js +319 -0
  12. package/canvas/tools/selectTool.js +457 -0
  13. package/canvas/tools/tool.js +223 -0
  14. package/canvas/tools/toolManager.js +394 -0
  15. package/canvas/ui/cursor.js +438 -0
  16. package/canvas/ui/toolbar.js +304 -0
  17. package/canvas/utils/boundingBox.js +378 -0
  18. package/canvas/utils/mathUtils.js +259 -0
  19. package/docs/api/configuration-options.md +104 -0
  20. package/docs/api/eventManager.md +68 -0
  21. package/docs/api/focusFrameManager.md +150 -0
  22. package/docs/api/index.md +91 -0
  23. package/docs/api/main.md +58 -0
  24. package/docs/api/omdBinaryExpressionNode.md +227 -0
  25. package/docs/api/omdCanvas.md +142 -0
  26. package/docs/api/omdConfigManager.md +192 -0
  27. package/docs/api/omdConstantNode.md +117 -0
  28. package/docs/api/omdDisplay.md +121 -0
  29. package/docs/api/omdEquationNode.md +161 -0
  30. package/docs/api/omdEquationSequenceNode.md +301 -0
  31. package/docs/api/omdEquationStack.md +139 -0
  32. package/docs/api/omdFunctionNode.md +141 -0
  33. package/docs/api/omdGroupNode.md +182 -0
  34. package/docs/api/omdHelpers.md +96 -0
  35. package/docs/api/omdLeafNode.md +163 -0
  36. package/docs/api/omdNode.md +101 -0
  37. package/docs/api/omdOperationDisplayNode.md +139 -0
  38. package/docs/api/omdOperatorNode.md +127 -0
  39. package/docs/api/omdParenthesisNode.md +122 -0
  40. package/docs/api/omdPopup.md +117 -0
  41. package/docs/api/omdPowerNode.md +127 -0
  42. package/docs/api/omdRationalNode.md +128 -0
  43. package/docs/api/omdSequenceNode.md +128 -0
  44. package/docs/api/omdSimplification.md +110 -0
  45. package/docs/api/omdSqrtNode.md +79 -0
  46. package/docs/api/omdStepVisualizer.md +115 -0
  47. package/docs/api/omdStepVisualizerHighlighting.md +61 -0
  48. package/docs/api/omdStepVisualizerInteractiveSteps.md +129 -0
  49. package/docs/api/omdStepVisualizerLayout.md +60 -0
  50. package/docs/api/omdStepVisualizerNodeUtils.md +140 -0
  51. package/docs/api/omdStepVisualizerTextBoxes.md +68 -0
  52. package/docs/api/omdToolbar.md +102 -0
  53. package/docs/api/omdTranscriptionService.md +76 -0
  54. package/docs/api/omdTreeDiff.md +134 -0
  55. package/docs/api/omdUnaryExpressionNode.md +174 -0
  56. package/docs/api/omdUtilities.md +70 -0
  57. package/docs/api/omdVariableNode.md +148 -0
  58. package/docs/api/selectTool.md +74 -0
  59. package/docs/api/simplificationEngine.md +98 -0
  60. package/docs/api/simplificationRules.md +77 -0
  61. package/docs/api/simplificationUtils.md +64 -0
  62. package/docs/api/transcribe.md +43 -0
  63. package/docs/api-reference.md +85 -0
  64. package/docs/index.html +454 -0
  65. package/docs/user-guide.md +9 -0
  66. package/index.js +67 -0
  67. package/omd/config/omdConfigManager.js +267 -0
  68. package/omd/core/index.js +150 -0
  69. package/omd/core/omdEquationStack.js +347 -0
  70. package/omd/core/omdUtilities.js +115 -0
  71. package/omd/display/omdDisplay.js +443 -0
  72. package/omd/display/omdToolbar.js +502 -0
  73. package/omd/nodes/omdBinaryExpressionNode.js +460 -0
  74. package/omd/nodes/omdConstantNode.js +142 -0
  75. package/omd/nodes/omdEquationNode.js +1223 -0
  76. package/omd/nodes/omdEquationSequenceNode.js +1273 -0
  77. package/omd/nodes/omdFunctionNode.js +352 -0
  78. package/omd/nodes/omdGroupNode.js +68 -0
  79. package/omd/nodes/omdLeafNode.js +77 -0
  80. package/omd/nodes/omdNode.js +557 -0
  81. package/omd/nodes/omdOperationDisplayNode.js +322 -0
  82. package/omd/nodes/omdOperatorNode.js +109 -0
  83. package/omd/nodes/omdParenthesisNode.js +293 -0
  84. package/omd/nodes/omdPowerNode.js +236 -0
  85. package/omd/nodes/omdRationalNode.js +295 -0
  86. package/omd/nodes/omdSqrtNode.js +308 -0
  87. package/omd/nodes/omdUnaryExpressionNode.js +178 -0
  88. package/omd/nodes/omdVariableNode.js +123 -0
  89. package/omd/simplification/omdSimplification.js +171 -0
  90. package/omd/simplification/omdSimplificationEngine.js +886 -0
  91. package/omd/simplification/package.json +6 -0
  92. package/omd/simplification/rules/binaryRules.js +1037 -0
  93. package/omd/simplification/rules/functionRules.js +111 -0
  94. package/omd/simplification/rules/index.js +48 -0
  95. package/omd/simplification/rules/parenthesisRules.js +19 -0
  96. package/omd/simplification/rules/powerRules.js +143 -0
  97. package/omd/simplification/rules/rationalRules.js +475 -0
  98. package/omd/simplification/rules/sqrtRules.js +48 -0
  99. package/omd/simplification/rules/unaryRules.js +37 -0
  100. package/omd/simplification/simplificationRules.js +32 -0
  101. package/omd/simplification/simplificationUtils.js +1056 -0
  102. package/omd/step-visualizer/omdStepVisualizer.js +597 -0
  103. package/omd/step-visualizer/omdStepVisualizerHighlighting.js +206 -0
  104. package/omd/step-visualizer/omdStepVisualizerLayout.js +245 -0
  105. package/omd/step-visualizer/omdStepVisualizerTextBoxes.js +163 -0
  106. package/omd/utils/omdNodeOverlay.js +638 -0
  107. package/omd/utils/omdPopup.js +1084 -0
  108. package/omd/utils/omdStepVisualizerInteractiveSteps.js +491 -0
  109. package/omd/utils/omdStepVisualizerNodeUtils.js +268 -0
  110. package/omd/utils/omdTranscriptionService.js +125 -0
  111. package/omd/utils/omdTreeDiff.js +734 -0
  112. package/package.json +46 -0
  113. package/src/index.js +62 -0
  114. package/src/json-schemas.md +109 -0
  115. package/src/omd-json-samples.js +115 -0
  116. package/src/omd.js +109 -0
  117. package/src/omdApp.js +391 -0
  118. package/src/omdAppCanvas.js +336 -0
  119. package/src/omdBalanceHanger.js +172 -0
  120. package/src/omdColor.js +13 -0
  121. package/src/omdCoordinatePlane.js +467 -0
  122. package/src/omdEquation.js +125 -0
  123. package/src/omdExpression.js +104 -0
  124. package/src/omdFunction.js +113 -0
  125. package/src/omdMetaExpression.js +287 -0
  126. package/src/omdNaturalExpression.js +564 -0
  127. package/src/omdNode.js +384 -0
  128. package/src/omdNumber.js +53 -0
  129. package/src/omdNumberLine.js +107 -0
  130. package/src/omdNumberTile.js +119 -0
  131. package/src/omdOperator.js +73 -0
  132. package/src/omdPowerExpression.js +92 -0
  133. package/src/omdProblem.js +55 -0
  134. package/src/omdRatioChart.js +232 -0
  135. package/src/omdRationalExpression.js +115 -0
  136. package/src/omdSampleData.js +215 -0
  137. package/src/omdShapes.js +476 -0
  138. package/src/omdSpinner.js +148 -0
  139. package/src/omdString.js +39 -0
  140. package/src/omdTable.js +369 -0
  141. package/src/omdTapeDiagram.js +245 -0
  142. package/src/omdTerm.js +92 -0
  143. package/src/omdTileEquation.js +349 -0
  144. package/src/omdVariable.js +51 -0
@@ -0,0 +1,76 @@
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.
4
+
5
+ ## Class Definition
6
+
7
+ ```javascript
8
+ export class omdTranscriptionService {
9
+ // ...
10
+ }
11
+ ```
12
+
13
+ ## Constructor
14
+
15
+ ### `new omdTranscriptionService([options])`
16
+
17
+ Creates a new `omdTranscriptionService` instance.
18
+
19
+ * **[options]** (`object`, optional): Configuration options for the service.
20
+ * **endpoint** (`string`, optional): The server endpoint for the transcription service. Defaults to `'/.netlify/functions/transcribe'`.
21
+ * **defaultProvider** (`string`, optional): The default transcription provider to use. Defaults to `'gemini'`.
22
+
23
+ ## Public Methods
24
+
25
+ ### `transcribe(imageBlob, [options])`
26
+
27
+ Transcribes an image containing handwritten content.
28
+
29
+ * **imageBlob** (`Blob`): The image blob to transcribe.
30
+ * **[options]** (`object`, optional): Transcription options.
31
+ * **prompt** (`string`, optional): A custom prompt for the transcription service.
32
+ * **Returns**: `Promise<object>` - A promise that resolves with the transcription result, containing the `text`, `provider`, and `confidence`.
33
+
34
+ ### `transcribeWithFallback(imageBlob, [options])`
35
+
36
+ Transcribes an image with a fallback mechanism (currently, this is the same as `transcribe`).
37
+
38
+ * **imageBlob** (`Blob`): The image blob to transcribe.
39
+ * **[options]** (`object`, optional): Transcription options.
40
+ * **Returns**: `Promise<object>` - A promise that resolves with the transcription result.
41
+
42
+ ### `isAvailable()`
43
+
44
+ Checks if the transcription service is available.
45
+
46
+ * **Returns**: `boolean` - `true` if the service is available, `false` otherwise.
47
+
48
+ ### `getAvailableProviders()`
49
+
50
+ Gets the available transcription providers.
51
+
52
+ * **Returns**: `Array<string>` - An array of available provider names.
53
+
54
+ ### `isProviderAvailable(provider)`
55
+
56
+ Checks if a specific transcription provider is available.
57
+
58
+ * **provider** (`string`): The name of the provider to check.
59
+ * **Returns**: `boolean` - `true` if the provider is available, `false` otherwise.
60
+
61
+ ## Example Usage
62
+
63
+ ```javascript
64
+ // Create a transcription service instance
65
+ const transcriptionService = new omdTranscriptionService();
66
+
67
+ // Get an image blob from a canvas or file input
68
+ const imageBlob = await getMyImageBlob();
69
+
70
+ // Transcribe the image
71
+ const result = await transcriptionService.transcribe(imageBlob, {
72
+ prompt: 'Transcribe the handwritten math equation.'
73
+ });
74
+
75
+ console.log(result.text); // The transcribed text
76
+ ```
@@ -0,0 +1,134 @@
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
+ ```
@@ -0,0 +1,174 @@
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
@@ -0,0 +1,70 @@
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.
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
+ - **Parameters:**
12
+ - `type` {string} - The `type` property of the AST node (e.g., `"OperatorNode"`, `"ParenthesisNode"`).
13
+ - `ast` {Object} - The full AST node object, which may contain additional context (e.g., `op` for `OperatorNode`).
14
+ - **Returns:** {class} The appropriate `omdNode` class constructor.
15
+
16
+ ---
17
+
18
+ #### `getNodeForAST(ast)`
19
+
20
+ A wrapper function that takes a complete math.js AST node and returns the corresponding OMD node class. It uses `astToOmdType` internally.
21
+
22
+ - **Parameters:**
23
+ - `ast` {Object} - The math.js AST node.
24
+ - **Returns:** {class} The appropriate `omdNode` class constructor.
25
+
26
+ ---
27
+
28
+ #### `getTextBounds(text, fontSize)`
29
+
30
+ Calculates the rendered width and height of a given text string at a specific font size. This is used for precise layout calculations.
31
+
32
+ - **Parameters:**
33
+ - `text` {string} - The text content to measure.
34
+ - `fontSize` {number} - The font size in pixels.
35
+ - **Returns:** {Object} An object with `width` and `height` properties.
36
+
37
+ ---
38
+
39
+ #### `shouldUseFractionNotation(ast)`
40
+
41
+ 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 is based on the complexity of the numerator and denominator.
42
+
43
+ - **Parameters:**
44
+ - `ast` {Object} - The AST node representing a division operation.
45
+ - **Returns:** {boolean} `true` if it should be a fraction, `false` otherwise.
46
+
47
+ ---
48
+
49
+ #### `isComplexExpression(ast)`
50
+
51
+ Checks if an AST node represents a "complex" expression, typically one that contains multiple operations or nested structures. This is used by `shouldUseFractionNotation` to decide on rendering style.
52
+
53
+ - **Parameters:**
54
+ - `ast` {Object} - The AST node to check.
55
+ - **Returns:** {boolean} `true` if the expression is considered complex, `false` otherwise.
56
+
57
+ ### Example
58
+
59
+ ```javascript
60
+ import { getNodeForAST, getTextBounds } from './omd/omdUtilities.js';
61
+
62
+ // Example of getting a node class
63
+ const ast = math.parse('x + 2');
64
+ const NodeClass = getNodeForAST(ast);
65
+ const node = new NodeClass(ast);
66
+
67
+ // Example of getting text bounds
68
+ const bounds = getTextBounds('Hello World', 24);
69
+ console.log(`Text width: ${bounds.width}, height: ${bounds.height}`);
70
+ ```
@@ -0,0 +1,148 @@
1
+ # omdVariableNode
2
+
3
+ Represents a variable (like x, y, a, b) in mathematical expressions.
4
+
5
+ ## Class: `omdVariableNode extends omdLeafNode`
6
+
7
+ ```javascript
8
+ import { omdVariableNode } from './omd/nodes/omdVariableNode.js';
9
+ ```
10
+
11
+ ### Constructor
12
+
13
+ ```javascript
14
+ new omdVariableNode(nodeData)
15
+ ```
16
+
17
+ **Parameters:**
18
+ - `nodeData` {Object|string} - The AST node data or variable name
19
+
20
+ **Description:**
21
+ Creates a node representing a variable. Usually created automatically when parsing expressions.
22
+
23
+ ### Properties
24
+
25
+ Inherits all properties from [`omdLeafNode`](./omdLeafNode.md), plus:
26
+
27
+ #### `name`
28
+ - **Type:** string
29
+ - **Description:** The variable name (e.g., 'x', 'y', 'theta')
30
+
31
+ #### `type`
32
+ - **Type:** string
33
+ - **Description:** Always "variable"
34
+
35
+ #### `textElement`
36
+ - **Type:** SVGElement
37
+ - **Description:** The SVG text element displaying the variable name
38
+
39
+ ### Methods
40
+
41
+ Inherits all methods from [`omdLeafNode`](./omdLeafNode.md), plus:
42
+
43
+ #### `parseName(nodeData)`
44
+ Internal method to extract variable name from AST data.
45
+ - **Returns:** string
46
+
47
+ ---
48
+
49
+ #### `parseType()`
50
+ Internal method to set node type.
51
+ - **Returns:** "variable"
52
+
53
+ ---
54
+
55
+ #### `computeDimensions()`
56
+ Calculates dimensions with padding around the variable.
57
+ Overrides base class method.
58
+
59
+ ---
60
+
61
+ #### `updateLayout()`
62
+ Updates the layout of the node.
63
+ Overrides base class method.
64
+
65
+ ---
66
+
67
+ #### `toMathJSNode()`
68
+ Converts to math.js AST format.
69
+ - **Returns:** Object - A math.js-compatible AST node with:
70
+ - `type`: "SymbolNode"
71
+ - `name`: The variable name
72
+ - `id`: Node ID
73
+ - `provenance`: Provenance array
74
+
75
+ ---
76
+
77
+ #### `highlight(color)`
78
+ Highlights the node and sets text color to white.
79
+ - `color` {omdColor} - The highlight color
80
+
81
+ ---
82
+
83
+ #### `clearProvenanceHighlights()`
84
+ Clears highlights and resets text color.
85
+
86
+ ---
87
+
88
+ #### `toString()`
89
+ Convert to string representation.
90
+ - **Returns:** string - The variable name
91
+
92
+ ---
93
+
94
+ #### `evaluate(variables)`
95
+ Evaluates the variable by looking up its value in a map.
96
+ - `variables` {Object} - A map of variable names to their numeric values
97
+ - **Returns:** number - The value of the variable
98
+ - **Throws:** Error if variable is not defined in the map
99
+
100
+ ---
101
+
102
+ #### `simplify()`
103
+ Attempt to simplify the variable.
104
+ - **Returns:** Object
105
+ - `success`: false (variables cannot be simplified)
106
+ - `newRoot`: null
107
+ - `message`: "Cannot simplify a variable"
108
+
109
+ ### Static Methods
110
+
111
+ #### `fromName(name)`
112
+ Create a variable node from a name.
113
+ - `name` {string} - The variable name
114
+ - **Returns:** omdVariableNode
115
+
116
+ ### Examples
117
+
118
+ #### Creating Variables
119
+
120
+ ```javascript
121
+ // From a name
122
+ const nodeX = omdVariableNode.fromName('x');
123
+ const nodeTheta = omdVariableNode.fromName('θ');
124
+
125
+ // From AST data
126
+ const node = new omdVariableNode({
127
+ type: 'SymbolNode',
128
+ name: 'x'
129
+ });
130
+
131
+ // Direct string name
132
+ const nodeY = new omdVariableNode('y');
133
+ ```
134
+
135
+ #### Rendering Variables
136
+
137
+ ```javascript
138
+ const node = omdVariableNode.fromName('x');
139
+ node.setFontSize(24);
140
+ node.computeDimensions(); // Calculate size with padding
141
+ node.updateLayout(); // Position the text element
142
+ ```
143
+
144
+ ### See Also
145
+
146
+ - [omdLeafNode](./omdLeafNode.md) - Parent class
147
+ - [omdNode](./omdNode.md) - Base class
148
+ - [omdConstantNode](./omdConstantNode.md) - For numeric values
@@ -0,0 +1,74 @@
1
+
2
+ # SelectTool
3
+
4
+ The `SelectTool` is a tool for selecting, moving, and deleting stroke segments on the canvas. It extends the `Tool` class.
5
+
6
+ ## Class Definition
7
+
8
+ ```javascript
9
+ export class SelectTool extends Tool {
10
+ // ...
11
+ }
12
+ ```
13
+
14
+ ## Constructor
15
+
16
+ ### `new SelectTool(canvas, [options])`
17
+
18
+ Creates a new `SelectTool` instance.
19
+
20
+ * **canvas** (`OMDCanvas`): The canvas instance.
21
+ * **[options]** (`object`, optional): Configuration options for the tool.
22
+ * **selectionColor** (`string`, optional): The color of the selection box. Defaults to `'#007bff'`.
23
+ * **selectionOpacity** (`number`, optional): The opacity of the selection box. Defaults to `0.3`.
24
+
25
+ ## Public Methods
26
+
27
+ ### `onPointerDown(event)`
28
+
29
+ Handles the pointer down event to start a selection.
30
+
31
+ * **event** (`PointerEvent`): The pointer event.
32
+
33
+ ### `onPointerMove(event)`
34
+
35
+ Handles the pointer move event to update the selection box.
36
+
37
+ * **event** (`PointerEvent`): The pointer event.
38
+
39
+ ### `onPointerUp(event)`
40
+
41
+ Handles the pointer up event to complete the selection.
42
+
43
+ * **event** (`PointerEvent`): The pointer event.
44
+
45
+ ### `onCancel()`
46
+
47
+ Cancels the current selection operation.
48
+
49
+ ### `onKeyboardShortcut(key, event)`
50
+
51
+ Handles keyboard shortcuts for selection-related actions.
52
+
53
+ * **key** (`string`): The key that was pressed.
54
+ * **event** (`KeyboardEvent`): The keyboard event.
55
+ * **Returns**: `boolean` - True if the shortcut was handled, false otherwise.
56
+
57
+ ### `getCursor()`
58
+
59
+ Gets the cursor for the tool.
60
+
61
+ * **Returns**: `string` - The CSS cursor name.
62
+
63
+ ### `clearSelection()`
64
+
65
+ Clears the current selection.
66
+
67
+ ## Properties
68
+
69
+ * **displayName** (`string`): The display name of the tool.
70
+ * **description** (`string`): A description of the tool.
71
+ * **icon** (`string`): The icon for the tool.
72
+ * **shortcut** (`string`): The keyboard shortcut for the tool.
73
+ * **category** (`string`): The category of the tool.
74
+ * **selectedSegments** (`Map<string, Set<number>>`): A map of selected segments, where the key is the stroke ID and the value is a set of segment indices.