@teachinglab/omd 0.2.10 → 0.3.1

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 (58) hide show
  1. package/docs/api/configuration-options.md +198 -198
  2. package/docs/api/eventManager.md +82 -82
  3. package/docs/api/focusFrameManager.md +144 -144
  4. package/docs/api/index.md +105 -105
  5. package/docs/api/main.md +62 -62
  6. package/docs/api/omdBinaryExpressionNode.md +86 -86
  7. package/docs/api/omdCanvas.md +83 -83
  8. package/docs/api/omdConfigManager.md +112 -112
  9. package/docs/api/omdConstantNode.md +52 -52
  10. package/docs/api/omdDisplay.md +87 -87
  11. package/docs/api/omdEquationNode.md +174 -174
  12. package/docs/api/omdEquationSequenceNode.md +258 -258
  13. package/docs/api/omdEquationStack.md +156 -156
  14. package/docs/api/omdFunctionNode.md +82 -82
  15. package/docs/api/omdGroupNode.md +78 -78
  16. package/docs/api/omdHelpers.md +87 -87
  17. package/docs/api/omdLeafNode.md +85 -85
  18. package/docs/api/omdNode.md +201 -201
  19. package/docs/api/omdOperationDisplayNode.md +117 -117
  20. package/docs/api/omdOperatorNode.md +91 -91
  21. package/docs/api/omdParenthesisNode.md +133 -133
  22. package/docs/api/omdPopup.md +191 -191
  23. package/docs/api/omdPowerNode.md +131 -131
  24. package/docs/api/omdRationalNode.md +144 -144
  25. package/docs/api/omdSimplification.md +78 -78
  26. package/docs/api/omdSqrtNode.md +144 -144
  27. package/docs/api/omdStepVisualizer.md +146 -146
  28. package/docs/api/omdStepVisualizerHighlighting.md +65 -65
  29. package/docs/api/omdStepVisualizerInteractiveSteps.md +108 -108
  30. package/docs/api/omdStepVisualizerLayout.md +70 -70
  31. package/docs/api/omdStepVisualizerTextBoxes.md +76 -76
  32. package/docs/api/omdTranscriptionService.md +95 -95
  33. package/docs/api/omdTreeDiff.md +169 -169
  34. package/docs/api/omdUnaryExpressionNode.md +137 -137
  35. package/docs/api/omdUtilities.md +82 -82
  36. package/docs/api/omdVariableNode.md +123 -123
  37. package/omd/nodes/omdConstantNode.js +141 -141
  38. package/omd/nodes/omdGroupNode.js +67 -67
  39. package/omd/nodes/omdLeafNode.js +76 -76
  40. package/omd/nodes/omdOperatorNode.js +108 -108
  41. package/omd/nodes/omdParenthesisNode.js +292 -292
  42. package/omd/nodes/omdPowerNode.js +235 -235
  43. package/omd/nodes/omdRationalNode.js +295 -295
  44. package/omd/nodes/omdVariableNode.js +122 -122
  45. package/omd/simplification/omdSimplification.js +140 -140
  46. package/omd/step-visualizer/omdStepVisualizer.js +947 -947
  47. package/omd/step-visualizer/omdStepVisualizerLayout.js +892 -892
  48. package/omd/utils/omdStepVisualizerInteractiveSteps.js +5 -3
  49. package/package.json +1 -1
  50. package/src/index.js +11 -0
  51. package/src/omdBalanceHanger.js +2 -1
  52. package/src/omdEquation.js +1 -1
  53. package/src/omdNumber.js +1 -1
  54. package/src/omdNumberLine.js +13 -7
  55. package/src/omdRatioChart.js +11 -0
  56. package/src/omdShapes.js +1 -1
  57. package/src/omdTapeDiagram.js +1 -1
  58. package/src/omdTerm.js +1 -1
@@ -1,134 +1,134 @@
1
- # omdParenthesisNode
2
-
3
- Represents a parenthetical grouping in a mathematical expression, such as `(x + 2)`. This node is crucial for enforcing the correct order of operations and visually grouping parts of an expression.
4
-
5
- ## Class Definition
6
-
7
- ```javascript
8
- export class omdParenthesisNode extends omdNode
9
- ```
10
-
11
- ## Constructor
12
-
13
- ### `new omdParenthesisNode(astNodeData)`
14
-
15
- Creates a new `omdParenthesisNode` instance.
16
-
17
- - **`astNodeData`** (`object`): The math.js AST node for the parenthesized expression. It must contain a `content` property (or `args[0]`) which is the AST for the inner expression.
18
-
19
- During construction, it creates `omdGroupNode` instances for the opening and closing parentheses and an `omdNode` for the inner expression.
20
-
21
- ## Static Methods
22
-
23
- ### `fromString(expressionString)`
24
-
25
- Creates an `omdParenthesisNode` from a string representation of a parenthesized expression. The input string must start and end with parentheses.
26
-
27
- - **`expressionString`** (`string`): The expression, which must be enclosed in parentheses (e.g., `"(2 * x)"`).
28
- - **Returns**: `omdParenthesisNode` - A new instance.
29
- - **Throws**: `Error` if `math.js` is not available, if the string is not properly enclosed in parentheses, or if it's not a valid parenthesized expression.
30
-
31
- ## Public Properties
32
-
33
- - **`expression`** (`omdNode`): The node representing the mathematical expression inside the parentheses.
34
- - **`open`** (`omdGroupNode`): The `omdGroupNode` for the opening parenthesis `(`.
35
- - **`closed`** (`omdGroupNode`): The `omdGroupNode` for the closing parenthesis `)`.
36
-
37
- ## Public Methods
38
-
39
- ### `computeDimensions()`
40
-
41
- Calculates the dimensions of the parenthesis node. It sums the widths of the opening parenthesis, the inner expression, and the closing parenthesis. The height is determined by the maximum height of these components plus a small amount of padding that scales with font size.
42
-
43
- - **Overrides**: `omdNode.computeDimensions()`.
44
-
45
- ### `updateLayout()`
46
-
47
- Updates the layout of the parenthesis node and its children. It positions the inner `expression` and then centers the `open` and `closed` parentheses vertically around the mathematical baseline of the inner expression. This ensures proper visual alignment, especially for expressions containing superscripts or subscripts.
48
-
49
- - **Overrides**: `omdNode.updateLayout()`.
50
-
51
- ### `getAlignmentBaseline()`
52
-
53
- Returns the vertical y-coordinate for alignment. For a parenthesis node, this is the baseline of its inner expression.
54
-
55
- - **Overrides**: `omdNode.getAlignmentBaseline()`.
56
-
57
- ### `clone()`
58
-
59
- Creates a deep, structural clone of the parenthesis node, including its inner `expression` and `omdGroupNode` children. The cloned node's `provenance` array is updated to include the original node's ID.
60
-
61
- - **Returns**: `omdParenthesisNode` - A new, identical instance of the parenthesis node.
62
-
63
- ### `isConstant()`
64
-
65
- Checks if the inner expression is a constant value.
66
-
67
- - **Returns**: `boolean` - `true` if `this.expression.isConstant()` is `true`, `false` otherwise.
68
-
69
- ### `getValue()`
70
-
71
- Returns the numerical value of the inner expression, if it is constant.
72
-
73
- - **Returns**: `number`.
74
- - **Throws**: `Error` if the inner expression is not constant or cannot be evaluated.
75
-
76
- ### `toMathJSNode()`
77
-
78
- Converts the `omdParenthesisNode` back into its math.js AST representation. It creates a `ParenthesisNode` AST object with the converted inner expression.
79
-
80
- - **Returns**: `object` - A math.js `ParenthesisNode` AST object. The returned object also includes a `clone` method for compatibility.
81
-
82
- ### `toString()`
83
-
84
- Converts the node to its string representation, including the parentheses.
85
-
86
- - **Returns**: `string` - e.g., `"(x + 2)"`.
87
-
88
- ### `evaluate(variables)`
89
-
90
- Evaluates the inner expression of the parenthesis node.
91
-
92
- - **`variables`** (`object`): A map of variable names to their numeric values.
93
- - **Returns**: `number` - The result of the inner expression's evaluation.
94
- - **Throws**: `Error` if the inner expression cannot be evaluated.
95
-
96
- ### `isNecessary()`
97
-
98
- Checks if the parentheses are mathematically necessary to maintain the correct order of operations, based on the parent node's context and the type of the inner expression. For example, parentheses around a simple constant or variable are generally not necessary, but they are often required around complex expressions within a power or binary operation.
99
-
100
- - **Returns**: `boolean` - `true` if the parentheses are required, `false` otherwise.
101
-
102
- ## Internal Methods
103
-
104
- - **`createParenthesis(symbol)`**: Creates an `omdGroupNode` for an opening or closing parenthesis.
105
- - **`createExpression(ast)`**: Creates an `omdNode` instance for the inner expression from its AST.
106
-
107
- ## Example
108
-
109
- ```javascript
110
- import { omdParenthesisNode } from '@teachinglab/omd';
111
- import * as math from 'mathjs';
112
-
113
- // Create a node representing (x + 2)
114
- const innerExpressionAst = math.parse('x + 2');
115
- const parenNode = new omdParenthesisNode({ content: innerExpressionAst });
116
-
117
- // Set font size and render
118
- parenNode.setFontSize(28);
119
- parenNode.initialize();
120
-
121
- // The simplification engine might remove these parentheses if they are not necessary
122
- // const simplified = parenNode.simplify();
123
-
124
- // Add to an SVG container to display
125
- // const svgContainer = new jsvgContainer();
126
- // svgContainer.addChild(parenNode);
127
- // document.body.appendChild(svgContainer.svgObject);
128
- ```
129
-
130
- ## See Also
131
-
132
- - [`omdNode`](./omdNode.md) - The base class for all OMD nodes.
133
- - [`omdGroupNode`](./omdGroupNode.md) - The class used to render the individual `(` and `)` symbols.
1
+ # omdParenthesisNode
2
+
3
+ Represents a parenthetical grouping in a mathematical expression, such as `(x + 2)`. This node is crucial for enforcing the correct order of operations and visually grouping parts of an expression.
4
+
5
+ ## Class Definition
6
+
7
+ ```javascript
8
+ export class omdParenthesisNode extends omdNode
9
+ ```
10
+
11
+ ## Constructor
12
+
13
+ ### `new omdParenthesisNode(astNodeData)`
14
+
15
+ Creates a new `omdParenthesisNode` instance.
16
+
17
+ - **`astNodeData`** (`object`): The math.js AST node for the parenthesized expression. It must contain a `content` property (or `args[0]`) which is the AST for the inner expression.
18
+
19
+ During construction, it creates `omdGroupNode` instances for the opening and closing parentheses and an `omdNode` for the inner expression.
20
+
21
+ ## Static Methods
22
+
23
+ ### `fromString(expressionString)`
24
+
25
+ Creates an `omdParenthesisNode` from a string representation of a parenthesized expression. The input string must start and end with parentheses.
26
+
27
+ - **`expressionString`** (`string`): The expression, which must be enclosed in parentheses (e.g., `"(2 * x)"`).
28
+ - **Returns**: `omdParenthesisNode` - A new instance.
29
+ - **Throws**: `Error` if `math.js` is not available, if the string is not properly enclosed in parentheses, or if it's not a valid parenthesized expression.
30
+
31
+ ## Public Properties
32
+
33
+ - **`expression`** (`omdNode`): The node representing the mathematical expression inside the parentheses.
34
+ - **`open`** (`omdGroupNode`): The `omdGroupNode` for the opening parenthesis `(`.
35
+ - **`closed`** (`omdGroupNode`): The `omdGroupNode` for the closing parenthesis `)`.
36
+
37
+ ## Public Methods
38
+
39
+ ### `computeDimensions()`
40
+
41
+ Calculates the dimensions of the parenthesis node. It sums the widths of the opening parenthesis, the inner expression, and the closing parenthesis. The height is determined by the maximum height of these components plus a small amount of padding that scales with font size.
42
+
43
+ - **Overrides**: `omdNode.computeDimensions()`.
44
+
45
+ ### `updateLayout()`
46
+
47
+ Updates the layout of the parenthesis node and its children. It positions the inner `expression` and then centers the `open` and `closed` parentheses vertically around the mathematical baseline of the inner expression. This ensures proper visual alignment, especially for expressions containing superscripts or subscripts.
48
+
49
+ - **Overrides**: `omdNode.updateLayout()`.
50
+
51
+ ### `getAlignmentBaseline()`
52
+
53
+ Returns the vertical y-coordinate for alignment. For a parenthesis node, this is the baseline of its inner expression.
54
+
55
+ - **Overrides**: `omdNode.getAlignmentBaseline()`.
56
+
57
+ ### `clone()`
58
+
59
+ Creates a deep, structural clone of the parenthesis node, including its inner `expression` and `omdGroupNode` children. The cloned node's `provenance` array is updated to include the original node's ID.
60
+
61
+ - **Returns**: `omdParenthesisNode` - A new, identical instance of the parenthesis node.
62
+
63
+ ### `isConstant()`
64
+
65
+ Checks if the inner expression is a constant value.
66
+
67
+ - **Returns**: `boolean` - `true` if `this.expression.isConstant()` is `true`, `false` otherwise.
68
+
69
+ ### `getValue()`
70
+
71
+ Returns the numerical value of the inner expression, if it is constant.
72
+
73
+ - **Returns**: `number`.
74
+ - **Throws**: `Error` if the inner expression is not constant or cannot be evaluated.
75
+
76
+ ### `toMathJSNode()`
77
+
78
+ Converts the `omdParenthesisNode` back into its math.js AST representation. It creates a `ParenthesisNode` AST object with the converted inner expression.
79
+
80
+ - **Returns**: `object` - A math.js `ParenthesisNode` AST object. The returned object also includes a `clone` method for compatibility.
81
+
82
+ ### `toString()`
83
+
84
+ Converts the node to its string representation, including the parentheses.
85
+
86
+ - **Returns**: `string` - e.g., `"(x + 2)"`.
87
+
88
+ ### `evaluate(variables)`
89
+
90
+ Evaluates the inner expression of the parenthesis node.
91
+
92
+ - **`variables`** (`object`): A map of variable names to their numeric values.
93
+ - **Returns**: `number` - The result of the inner expression's evaluation.
94
+ - **Throws**: `Error` if the inner expression cannot be evaluated.
95
+
96
+ ### `isNecessary()`
97
+
98
+ Checks if the parentheses are mathematically necessary to maintain the correct order of operations, based on the parent node's context and the type of the inner expression. For example, parentheses around a simple constant or variable are generally not necessary, but they are often required around complex expressions within a power or binary operation.
99
+
100
+ - **Returns**: `boolean` - `true` if the parentheses are required, `false` otherwise.
101
+
102
+ ## Internal Methods
103
+
104
+ - **`createParenthesis(symbol)`**: Creates an `omdGroupNode` for an opening or closing parenthesis.
105
+ - **`createExpression(ast)`**: Creates an `omdNode` instance for the inner expression from its AST.
106
+
107
+ ## Example
108
+
109
+ ```javascript
110
+ import { omdParenthesisNode } from '@teachinglab/omd';
111
+ import * as math from 'mathjs';
112
+
113
+ // Create a node representing (x + 2)
114
+ const innerExpressionAst = math.parse('x + 2');
115
+ const parenNode = new omdParenthesisNode({ content: innerExpressionAst });
116
+
117
+ // Set font size and render
118
+ parenNode.setFontSize(28);
119
+ parenNode.initialize();
120
+
121
+ // The simplification engine might remove these parentheses if they are not necessary
122
+ // const simplified = parenNode.simplify();
123
+
124
+ // Add to an SVG container to display
125
+ // const svgContainer = new jsvgContainer();
126
+ // svgContainer.addChild(parenNode);
127
+ // document.body.appendChild(svgContainer.svgObject);
128
+ ```
129
+
130
+ ## See Also
131
+
132
+ - [`omdNode`](./omdNode.md) - The base class for all OMD nodes.
133
+ - [`omdGroupNode`](./omdGroupNode.md) - The class used to render the individual `(` and `)` symbols.
134
134
  - [`omdBinaryExpressionNode`](./omdBinaryExpressionNode.md) - A common type for the inner expression within parentheses.
@@ -1,192 +1,192 @@
1
- # omdPopup
2
-
3
- The `omdPopup` class handles the creation and management of interactive popups for node overlays. These popups can be used for text input or for drawing with a pen tool, often integrated with a transcription service for converting handwriting to text.
4
-
5
- ## Class Definition
6
-
7
- ```javascript
8
- export class omdPopup
9
- ```
10
-
11
- ## Constructor
12
-
13
- ### `new omdPopup(targetNode, parentElement, [options])`
14
-
15
- Creates a new `omdPopup` instance.
16
-
17
- - **`targetNode`** (`omdNode`): The OMD node to which the popup is logically attached. Its dimensions can influence the popup's size.
18
- - **`parentElement`** (`jsvgElement`): The parent `jsvgElement` (or `jsvgGroup`) to which the popup's SVG elements will be added.
19
- - **`options`** (`object`, optional): Configuration options for the popup:
20
- - `editable` (`boolean`): Whether the popup's input area is editable. Default: `true`.
21
- - `animationDuration` (`number`): The duration of the show/hide animation in milliseconds. Default: `200`.
22
-
23
- ## Public Properties
24
-
25
- - **`popup`** (`jsvgLayoutGroup`): The main SVG group element that contains all popup components.
26
- - **`popupBackground`** (`jsvgRect`): The background rectangle of the popup.
27
- - **`popupTextInput`** (`jsvgTextInput`): The text input field element (active in `'text'` mode).
28
- - **`penCanvas`** (`omdCanvas`): The drawing canvas instance (active in `'pen'` mode).
29
- - **`penCanvasCleanup`** (`function`): A cleanup function for the `penCanvas`.
30
- - **`currentMode`** (`string`): The current mode of the popup (`'text'` or `'pen'`).
31
- - **`popupAnimationId`** (`number`): The ID of the current animation frame request.
32
- - **`penButton`** (`jsvgButton`): The button to switch to `'pen'` mode.
33
- - **`textButton`** (`jsvgButton`): The button to switch to `'text'` mode.
34
- - **`clearButton`** (`jsvgButton`): The button to clear the current input.
35
- - **`submitButton`** (`jsvgButton`): The button to submit the input.
36
- - **`onValidateCallback`** (`function`): The callback function to execute when the user submits input.
37
- - **`onClearCallback`** (`function`): The callback function to execute when the user clears input.
38
- - **`popupWidth`** (`number`): The fixed width of the popup.
39
- - **`buttonSize`** (`number`): The size (width and height) of the control buttons.
40
- - **`margin`** (`number`): General margin/padding value used for layout.
41
- - **`buttonSpacing`** (`number`): Spacing between buttons.
42
- - **`canvasMinWidth`** (`number`): Minimum width for the pen canvas.
43
- - **`canvasMinHeight`** (`number`): Minimum height for the pen canvas.
44
- - **`popupHeightMultiplier`** (`number`): Multiplier for the target node's height to determine popup height.
45
- - **`targetNodeDefaultHeight`** (`number`): Default height for the target node if not available.
46
- - **`canvasTopOffset`** (`number`): Vertical offset for the pen canvas within the popup.
47
- - **`canvasLeftOffset`** (`number`): Horizontal offset for the pen canvas within the popup.
48
- - **`transcribedText`** (`string` | `null`): Stores the text result from pen-to-text transcription.
49
-
50
- ## Public Methods
51
-
52
- ### `show(x, y)`
53
-
54
- Creates and displays the popup at the specified coordinates with an animation.
55
-
56
- - **`x`** (`number`): The x-coordinate for the popup's top-left corner.
57
- - **`y`** (`number`): The y-coordinate for the popup's top-left corner.
58
- - **Returns**: `Promise` - A promise that resolves when the show animation is complete.
59
-
60
- ### `hide()`
61
-
62
- Hides the popup with an animation and performs cleanup.
63
-
64
- - **Returns**: `Promise` - A promise that resolves when the hide animation is complete.
65
-
66
- ### `toggle(x, y)`
67
-
68
- Toggles the visibility of the popup. If visible, it hides; otherwise, it shows.
69
-
70
- - **`x`** (`number`): The x-coordinate for showing the popup.
71
- - **`y`** (`number`): The y-coordinate for showing the popup.
72
- - **Returns**: `Promise` - A promise that resolves when the animation is complete.
73
-
74
- ### `setValidationCallback(callback)`
75
-
76
- Sets the callback function to be invoked when the user submits their input (e.g., by clicking the submit button).
77
-
78
- - **`callback`** (`Function`): The function to call for validation.
79
-
80
- ### `setClearCallback(callback)`
81
-
82
- Sets the callback function to be invoked when the user clears the input (e.g., by clicking the clear button).
83
-
84
- - **`callback`** (`Function`): The function to call when clearing.
85
-
86
- ### `getValue()`
87
-
88
- Retrieves the current input value from the popup. If in pen mode, it returns the last transcribed text and then clears it.
89
-
90
- - **Returns**: `string` - The current input value.
91
-
92
- ### `setValue(value)`
93
-
94
- Sets the input value of the popup's text field.
95
-
96
- - **`value`** (`string`): The value to set.
97
-
98
- ### `switchToMode(mode)`
99
-
100
- Switches the popup between `'text'` and `'pen'` input modes. This updates the visible input area and button states.
101
-
102
- - **`mode`** (`string`): The mode to switch to. Can be `'text'` or `'pen'`.
103
-
104
- ### `flashValidation(isValid)`
105
-
106
- Flashes the popup background (and associated elements) to visually indicate whether the user's input was valid or invalid.
107
-
108
- - **`isValid`** (`boolean`): `true` for a success flash (greenish), `false` for an error flash (reddish).
109
-
110
- ### `areExpressionsEquivalent(expr1, expr2)`
111
-
112
- Compares two mathematical expressions for equivalence. It uses `math.js` to simplify and evaluate expressions with random variable assignments to robustly check for mathematical equality.
113
-
114
- - **`expr1`** (`string`): The first expression string.
115
- - **`expr2`** (`string`): The second expression string.
116
- - **Returns**: `boolean` - `true` if the expressions are mathematically equivalent, `false` otherwise.
117
-
118
- ### `destroy()`
119
-
120
- Completely destroys the popup, removing all associated DOM elements, event listeners, and internal references. This method calls `hide()` internally to ensure a clean animated exit.
121
-
122
- ### `repositionCanvasRelativeToPopup()`
123
-
124
- Manually triggers an update to the pen canvas's position to ensure it remains correctly aligned with the popup, especially after layout changes.
125
-
126
- ## Internal Methods
127
-
128
- - **`_createPopup()`**: Creates the main `jsvgLayoutGroup` for the popup, its background, and initializes buttons and input areas.
129
- - **`_createButtons(popupWidth, popupHeight, buttonSize, margin, buttonSpacing)`**: Creates and positions the clear, submit, pen, and text mode switch buttons.
130
- - **`_createTextInput(popupWidth, popupHeight, margin)`**: Creates and styles the `jsvgTextInput` element for text input mode.
131
- - **`_createPenCanvas()`**: Initializes the `omdCanvas` instance for drawing in pen mode. It handles embedding the HTML canvas within an SVG `foreignObject` if necessary.
132
- - **`_showPenMode()`**: Activates the pen drawing mode, hiding the text input and showing/creating the pen canvas.
133
- - **`_showTextMode()`**: Activates the text input mode, hiding the pen canvas and showing the text input.
134
- - **`_addCanvasToParent(element)`**: Adds the pen canvas's DOM element (or its `foreignObject` wrapper) to the appropriate parent, handling positioning.
135
- - **`_updateButtonStates()`**: Updates the visual appearance of the mode switch buttons to reflect the `currentMode`.
136
- - **`_positionPopup(x, y)`**: Sets the absolute position of the main popup SVG group.
137
- - **`_animateOpacity(fromOpacity, toOpacity, duration)`**: Handles the smooth opacity animation for showing and hiding the popup.
138
- - **`_flashAllElements(flashColor)`**: Applies a temporary background color flash to all relevant popup elements (background, canvas) to indicate validation feedback.
139
- - **`_downloadCanvasAsBitmap()`**: Converts the content of the pen canvas to a PNG bitmap and initiates the transcription process.
140
- - **`_transcribeCanvas(imageBlob)`**: Sends the pen canvas image data to the `omdTranscriptionService` for handwriting recognition.
141
- - **`_setSubmitButtonLoading(isLoading)`**: Controls the loading state of the submit button, including a blinking animation.
142
- - **`_startBlinkingAnimation()`**: Initiates the blinking animation for the submit button.
143
- - **`_stopBlinkingAnimation()`**: Stops the blinking animation for the submit button.
144
- - **`_setupResizeObserver()`**: Sets up a `ResizeObserver` to monitor changes in the popup's dimensions and reposition the pen canvas accordingly.
145
- - **`_updateCanvasPosition()`**: Recalculates and applies the correct position and size for the pen canvas within the popup's content area.
146
- - **`_cleanup()`**: Performs comprehensive cleanup of all popup-related DOM elements, event listeners, and internal references.
147
-
148
- ## Modes
149
-
150
- The `omdPopup` has two primary interaction modes:
151
-
152
- - **Text Mode**: This is the default mode, providing a standard text input field (`jsvgTextInput`).
153
- - **Pen Mode**: This mode allows the user to draw directly inside the popup using an embedded `omdCanvas`. The drawing can then be transcribed to text using an external OCR service (via `omdTranscriptionService`).
154
-
155
- Users can switch between modes using the `'T'` (Text) and `'P'` (Pen) buttons on the popup.
156
-
157
- ## Example Usage
158
-
159
- ```javascript
160
- import { omdPopup } from '@teachinglab/omd';
161
- import { omdNode } from '@teachinglab/omd'; // Assuming you have an omdNode instance
162
- import { jsvgGroup } from '@teachinglab/jsvg'; // Assuming a parent jsvgElement
163
-
164
- // Create a dummy node and parent element for demonstration
165
- const targetNode = new omdNode({});
166
- const parentElement = new jsvgGroup();
167
-
168
- // Create a popup for a node
169
- const popup = new omdPopup(targetNode, parentElement);
170
-
171
- // Set a validation callback
172
- popup.setValidationCallback(() => {
173
- const value = popup.getValue();
174
- if (popup.areExpressionsEquivalent(value, 'correct')) {
175
- popup.flashValidation(true);
176
- popup.hide();
177
- } else {
178
- popup.flashValidation(false);
179
- }
180
- });
181
-
182
- // Set a clear callback
183
- popup.setClearCallback(() => {
184
- console.log('Popup input cleared!');
185
- });
186
-
187
- // Show the popup at a specific position
188
- // popup.show(100, 100);
189
-
190
- // To add the parentElement to the DOM for actual display:
191
- // document.body.appendChild(parentElement.svgObject);
1
+ # omdPopup
2
+
3
+ The `omdPopup` class handles the creation and management of interactive popups for node overlays. These popups can be used for text input or for drawing with a pen tool, often integrated with a transcription service for converting handwriting to text.
4
+
5
+ ## Class Definition
6
+
7
+ ```javascript
8
+ export class omdPopup
9
+ ```
10
+
11
+ ## Constructor
12
+
13
+ ### `new omdPopup(targetNode, parentElement, [options])`
14
+
15
+ Creates a new `omdPopup` instance.
16
+
17
+ - **`targetNode`** (`omdNode`): The OMD node to which the popup is logically attached. Its dimensions can influence the popup's size.
18
+ - **`parentElement`** (`jsvgElement`): The parent `jsvgElement` (or `jsvgGroup`) to which the popup's SVG elements will be added.
19
+ - **`options`** (`object`, optional): Configuration options for the popup:
20
+ - `editable` (`boolean`): Whether the popup's input area is editable. Default: `true`.
21
+ - `animationDuration` (`number`): The duration of the show/hide animation in milliseconds. Default: `200`.
22
+
23
+ ## Public Properties
24
+
25
+ - **`popup`** (`jsvgLayoutGroup`): The main SVG group element that contains all popup components.
26
+ - **`popupBackground`** (`jsvgRect`): The background rectangle of the popup.
27
+ - **`popupTextInput`** (`jsvgTextInput`): The text input field element (active in `'text'` mode).
28
+ - **`penCanvas`** (`omdCanvas`): The drawing canvas instance (active in `'pen'` mode).
29
+ - **`penCanvasCleanup`** (`function`): A cleanup function for the `penCanvas`.
30
+ - **`currentMode`** (`string`): The current mode of the popup (`'text'` or `'pen'`).
31
+ - **`popupAnimationId`** (`number`): The ID of the current animation frame request.
32
+ - **`penButton`** (`jsvgButton`): The button to switch to `'pen'` mode.
33
+ - **`textButton`** (`jsvgButton`): The button to switch to `'text'` mode.
34
+ - **`clearButton`** (`jsvgButton`): The button to clear the current input.
35
+ - **`submitButton`** (`jsvgButton`): The button to submit the input.
36
+ - **`onValidateCallback`** (`function`): The callback function to execute when the user submits input.
37
+ - **`onClearCallback`** (`function`): The callback function to execute when the user clears input.
38
+ - **`popupWidth`** (`number`): The fixed width of the popup.
39
+ - **`buttonSize`** (`number`): The size (width and height) of the control buttons.
40
+ - **`margin`** (`number`): General margin/padding value used for layout.
41
+ - **`buttonSpacing`** (`number`): Spacing between buttons.
42
+ - **`canvasMinWidth`** (`number`): Minimum width for the pen canvas.
43
+ - **`canvasMinHeight`** (`number`): Minimum height for the pen canvas.
44
+ - **`popupHeightMultiplier`** (`number`): Multiplier for the target node's height to determine popup height.
45
+ - **`targetNodeDefaultHeight`** (`number`): Default height for the target node if not available.
46
+ - **`canvasTopOffset`** (`number`): Vertical offset for the pen canvas within the popup.
47
+ - **`canvasLeftOffset`** (`number`): Horizontal offset for the pen canvas within the popup.
48
+ - **`transcribedText`** (`string` | `null`): Stores the text result from pen-to-text transcription.
49
+
50
+ ## Public Methods
51
+
52
+ ### `show(x, y)`
53
+
54
+ Creates and displays the popup at the specified coordinates with an animation.
55
+
56
+ - **`x`** (`number`): The x-coordinate for the popup's top-left corner.
57
+ - **`y`** (`number`): The y-coordinate for the popup's top-left corner.
58
+ - **Returns**: `Promise` - A promise that resolves when the show animation is complete.
59
+
60
+ ### `hide()`
61
+
62
+ Hides the popup with an animation and performs cleanup.
63
+
64
+ - **Returns**: `Promise` - A promise that resolves when the hide animation is complete.
65
+
66
+ ### `toggle(x, y)`
67
+
68
+ Toggles the visibility of the popup. If visible, it hides; otherwise, it shows.
69
+
70
+ - **`x`** (`number`): The x-coordinate for showing the popup.
71
+ - **`y`** (`number`): The y-coordinate for showing the popup.
72
+ - **Returns**: `Promise` - A promise that resolves when the animation is complete.
73
+
74
+ ### `setValidationCallback(callback)`
75
+
76
+ Sets the callback function to be invoked when the user submits their input (e.g., by clicking the submit button).
77
+
78
+ - **`callback`** (`Function`): The function to call for validation.
79
+
80
+ ### `setClearCallback(callback)`
81
+
82
+ Sets the callback function to be invoked when the user clears the input (e.g., by clicking the clear button).
83
+
84
+ - **`callback`** (`Function`): The function to call when clearing.
85
+
86
+ ### `getValue()`
87
+
88
+ Retrieves the current input value from the popup. If in pen mode, it returns the last transcribed text and then clears it.
89
+
90
+ - **Returns**: `string` - The current input value.
91
+
92
+ ### `setValue(value)`
93
+
94
+ Sets the input value of the popup's text field.
95
+
96
+ - **`value`** (`string`): The value to set.
97
+
98
+ ### `switchToMode(mode)`
99
+
100
+ Switches the popup between `'text'` and `'pen'` input modes. This updates the visible input area and button states.
101
+
102
+ - **`mode`** (`string`): The mode to switch to. Can be `'text'` or `'pen'`.
103
+
104
+ ### `flashValidation(isValid)`
105
+
106
+ Flashes the popup background (and associated elements) to visually indicate whether the user's input was valid or invalid.
107
+
108
+ - **`isValid`** (`boolean`): `true` for a success flash (greenish), `false` for an error flash (reddish).
109
+
110
+ ### `areExpressionsEquivalent(expr1, expr2)`
111
+
112
+ Compares two mathematical expressions for equivalence. It uses `math.js` to simplify and evaluate expressions with random variable assignments to robustly check for mathematical equality.
113
+
114
+ - **`expr1`** (`string`): The first expression string.
115
+ - **`expr2`** (`string`): The second expression string.
116
+ - **Returns**: `boolean` - `true` if the expressions are mathematically equivalent, `false` otherwise.
117
+
118
+ ### `destroy()`
119
+
120
+ Completely destroys the popup, removing all associated DOM elements, event listeners, and internal references. This method calls `hide()` internally to ensure a clean animated exit.
121
+
122
+ ### `repositionCanvasRelativeToPopup()`
123
+
124
+ Manually triggers an update to the pen canvas's position to ensure it remains correctly aligned with the popup, especially after layout changes.
125
+
126
+ ## Internal Methods
127
+
128
+ - **`_createPopup()`**: Creates the main `jsvgLayoutGroup` for the popup, its background, and initializes buttons and input areas.
129
+ - **`_createButtons(popupWidth, popupHeight, buttonSize, margin, buttonSpacing)`**: Creates and positions the clear, submit, pen, and text mode switch buttons.
130
+ - **`_createTextInput(popupWidth, popupHeight, margin)`**: Creates and styles the `jsvgTextInput` element for text input mode.
131
+ - **`_createPenCanvas()`**: Initializes the `omdCanvas` instance for drawing in pen mode. It handles embedding the HTML canvas within an SVG `foreignObject` if necessary.
132
+ - **`_showPenMode()`**: Activates the pen drawing mode, hiding the text input and showing/creating the pen canvas.
133
+ - **`_showTextMode()`**: Activates the text input mode, hiding the pen canvas and showing the text input.
134
+ - **`_addCanvasToParent(element)`**: Adds the pen canvas's DOM element (or its `foreignObject` wrapper) to the appropriate parent, handling positioning.
135
+ - **`_updateButtonStates()`**: Updates the visual appearance of the mode switch buttons to reflect the `currentMode`.
136
+ - **`_positionPopup(x, y)`**: Sets the absolute position of the main popup SVG group.
137
+ - **`_animateOpacity(fromOpacity, toOpacity, duration)`**: Handles the smooth opacity animation for showing and hiding the popup.
138
+ - **`_flashAllElements(flashColor)`**: Applies a temporary background color flash to all relevant popup elements (background, canvas) to indicate validation feedback.
139
+ - **`_downloadCanvasAsBitmap()`**: Converts the content of the pen canvas to a PNG bitmap and initiates the transcription process.
140
+ - **`_transcribeCanvas(imageBlob)`**: Sends the pen canvas image data to the `omdTranscriptionService` for handwriting recognition.
141
+ - **`_setSubmitButtonLoading(isLoading)`**: Controls the loading state of the submit button, including a blinking animation.
142
+ - **`_startBlinkingAnimation()`**: Initiates the blinking animation for the submit button.
143
+ - **`_stopBlinkingAnimation()`**: Stops the blinking animation for the submit button.
144
+ - **`_setupResizeObserver()`**: Sets up a `ResizeObserver` to monitor changes in the popup's dimensions and reposition the pen canvas accordingly.
145
+ - **`_updateCanvasPosition()`**: Recalculates and applies the correct position and size for the pen canvas within the popup's content area.
146
+ - **`_cleanup()`**: Performs comprehensive cleanup of all popup-related DOM elements, event listeners, and internal references.
147
+
148
+ ## Modes
149
+
150
+ The `omdPopup` has two primary interaction modes:
151
+
152
+ - **Text Mode**: This is the default mode, providing a standard text input field (`jsvgTextInput`).
153
+ - **Pen Mode**: This mode allows the user to draw directly inside the popup using an embedded `omdCanvas`. The drawing can then be transcribed to text using an external OCR service (via `omdTranscriptionService`).
154
+
155
+ Users can switch between modes using the `'T'` (Text) and `'P'` (Pen) buttons on the popup.
156
+
157
+ ## Example Usage
158
+
159
+ ```javascript
160
+ import { omdPopup } from '@teachinglab/omd';
161
+ import { omdNode } from '@teachinglab/omd'; // Assuming you have an omdNode instance
162
+ import { jsvgGroup } from '@teachinglab/jsvg'; // Assuming a parent jsvgElement
163
+
164
+ // Create a dummy node and parent element for demonstration
165
+ const targetNode = new omdNode({});
166
+ const parentElement = new jsvgGroup();
167
+
168
+ // Create a popup for a node
169
+ const popup = new omdPopup(targetNode, parentElement);
170
+
171
+ // Set a validation callback
172
+ popup.setValidationCallback(() => {
173
+ const value = popup.getValue();
174
+ if (popup.areExpressionsEquivalent(value, 'correct')) {
175
+ popup.flashValidation(true);
176
+ popup.hide();
177
+ } else {
178
+ popup.flashValidation(false);
179
+ }
180
+ });
181
+
182
+ // Set a clear callback
183
+ popup.setClearCallback(() => {
184
+ console.log('Popup input cleared!');
185
+ });
186
+
187
+ // Show the popup at a specific position
188
+ // popup.show(100, 100);
189
+
190
+ // To add the parentElement to the DOM for actual display:
191
+ // document.body.appendChild(parentElement.svgObject);
192
192
  ```