@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,113 @@
1
+
2
+ import { omdColor } from "./omdColor.js";
3
+ import { jsvgLayoutGroup, jsvgGroup } from "@teachinglab/jsvg";
4
+ import { omdOperator } from "./omdOperator.js";
5
+ import { omdExpression } from "./omdExpression.js";
6
+ import { omdVariable } from "./omdVariable.js";
7
+ import { omdString } from "./omdString.js";
8
+ import { omdMetaExpression } from "./omdMetaExpression.js"
9
+
10
+ export class omdFunction extends omdMetaExpression
11
+ {
12
+ constructor()
13
+ {
14
+ // initialization
15
+ super();
16
+
17
+ this.type = "omdPowerExpression";
18
+
19
+ this.leftExpression = null;
20
+ this.rightExpresion = null;
21
+ this.functionName = 'f';
22
+ this.inputVariableArray = [];
23
+
24
+ this.centerEquation = false;
25
+ this.inset = 5;
26
+
27
+ this.equationStack = new jsvgLayoutGroup();
28
+ this.equationStack.setSpacer(-7);
29
+ this.addChild( this.equationStack );
30
+
31
+ this.leftHolder = new jsvgGroup();
32
+ this.equationStack.addChild( this.leftHolder );
33
+
34
+ this.equalSign = new omdOperator('=');
35
+ this.equationStack.addChild( this.equalSign );
36
+
37
+ this.rightHolder = new jsvgGroup();
38
+ this.equationStack.addChild( this.rightHolder );
39
+ }
40
+
41
+ loadFromJSON( data )
42
+ {
43
+ if ( typeof data.name != "undefined" )
44
+ {
45
+ this.functionName = data.name;
46
+ }
47
+
48
+ if ( typeof data.inputVariables != "undefined" )
49
+ {
50
+ this.inputVariableArray = data.inputVariables;
51
+ }
52
+
53
+ if ( typeof data.expression != "undefined" )
54
+ {
55
+ // console.log("A");
56
+ // console.log( data.expression );
57
+ if ( data.expression.omdType == "expression" )
58
+ this.rightExpresion = new omdExpression();
59
+
60
+ this.rightExpresion.loadFromJSON( data.expression );
61
+ this.rightHolder.removeAllChildren();
62
+ this.rightHolder.addChild( this.rightExpresion );
63
+ }
64
+
65
+ // format the f(x) part on the left
66
+ this.leftHolder.removeAllChildren();
67
+ var funcText = this.functionName + "(" + this.inputVariableArray[0] + ")"; // this should be refactored as a function call
68
+ this.leftExpression = new omdString(funcText);
69
+ this.leftHolder.addChild( this.leftExpression );
70
+
71
+ this.updateLayout();
72
+ }
73
+
74
+ setNameVariableAndExpression( funcName, funcVariable, rightExp )
75
+ {
76
+ this.leftHolder.removeAllChildren();
77
+ var funcText = funcName + "(" + funcVariable + ")"; // this should be refactored as a function call
78
+ this.leftExpression = new omdString(funcText);
79
+ this.leftHolder.addChild( this.leftExpression );
80
+
81
+ this.rightExpresion = rightExp;
82
+ this.rightHolder.removeAllChildren();
83
+ this.rightHolder.addChild( rightExp );
84
+
85
+ this.equalSign.hideBackgroundByDefault();
86
+ this.leftExpression.hideBackgroundByDefault();
87
+ this.rightExpresion.hideBackgroundByDefault();
88
+
89
+ this.updateLayout();
90
+ }
91
+
92
+ updateLayout()
93
+ {
94
+ this.leftHolder.setWidthAndHeight( this.leftExpression.width, this.leftExpression.height );
95
+ this.rightHolder.setWidthAndHeight( this.rightExpresion.width, this.rightExpresion.height );
96
+
97
+ this.equationStack.doHorizontalLayout();
98
+ this.equationStack.setPosition( this.inset, 0 );
99
+
100
+ var W = this.equationStack.width;
101
+ this.backRect.setWidthAndHeight( W + this.inset*2, 30 );
102
+
103
+ this.setWidthAndHeight( this.backRect.width, this.backRect.height );
104
+
105
+ if ( this.centerEquation )
106
+ {
107
+ var leftShift = this.leftExpression.width + this.equalSign.width*0.50;
108
+ this.backRect.setPosition( -1.0 * leftShift + this.inset/2, 0 );
109
+ this.equationStack.setPosition( -1.0 * leftShift + this.inset + this.inset/2, 0 );
110
+ }
111
+ }
112
+
113
+ }
@@ -0,0 +1,287 @@
1
+ import { omdColor } from "./omdColor.js";
2
+ import { jsvgGroup, jsvgRect } from "@teachinglab/jsvg";
3
+
4
+ export class omdMetaExpression extends jsvgGroup
5
+ {
6
+ constructor( V = 1 )
7
+ {
8
+ // initialization
9
+ super();
10
+
11
+ this.type = "";
12
+ this.value = V;
13
+
14
+ this.defaultOpaqueBack = true;
15
+
16
+ this.backRect = new jsvgRect();
17
+ this.backRect.setWidthAndHeight( 30,30 );
18
+ this.backRect.setCornerRadius( 5 );
19
+ this.backRect.setFillColor( omdColor.lightGray );
20
+ this.addChild( this.backRect );
21
+
22
+ // Old events for selection - we will replace these with provenance highlighting
23
+ // this.svgObject.onmouseenter = this.select.bind(this);
24
+ // this.svgObject.onmouseleave = this.deselect.bind(this);
25
+
26
+ // New events for provenance highlighting
27
+ this.svgObject.onmouseenter = this.highlightProvenance.bind(this);
28
+ this.svgObject.onmouseleave = this.clearProvenance.bind(this);
29
+ this.svgObject.style.cursor = "pointer";
30
+ }
31
+
32
+ /* Gerard - ADDED */
33
+ setWidthAndHeight(w, h) {
34
+ super.setWidthAndHeight(w, h);
35
+ this.backRect.setWidthAndHeight(w, h);
36
+ }
37
+ setFontSize(fontSize) {
38
+ this.fontSize = fontSize;
39
+
40
+ // Propagate font size to all children that support it
41
+ if (this.childList) {
42
+ this.childList.forEach(child => {
43
+ if (child && typeof child.setFontSize === 'function') {
44
+ child.setFontSize(fontSize);
45
+ }
46
+ });
47
+ }
48
+ }
49
+ getFontSize() {
50
+ if (this.fontSize) return this.fontSize;
51
+
52
+ if (this.parent && typeof this.parent.getFontSize === 'function') {
53
+ return this.parent.getFontSize();
54
+ }
55
+
56
+ return 16; // Default fallback
57
+ }
58
+ getRootFontSize() {
59
+ if (this.parent && (this.parent instanceof omdMetaExpression)) {
60
+ return this.parent.getRootFontSize();
61
+ }
62
+ // No parent, so this is the root. Return its font size or default.
63
+ return this.fontSize || 16;
64
+ }
65
+
66
+ // ===== PROVENANCE HIGHLIGHTING =====
67
+
68
+ highlightProvenance(event, color = omdColor.hiliteColor, minStepNumber = -Infinity) {
69
+ // Prevent event from bubbling up to parent containers and causing flickering
70
+ event.stopPropagation();
71
+
72
+ const rootNode = this.getRootNode();
73
+ if (!rootNode || !rootNode.nodeMap) return;
74
+
75
+ // Clear any previous highlights from the entire sequence
76
+ rootNode.clearProvenanceHighlights();
77
+
78
+ // Highlight the node being hovered over
79
+ this.highlight(color);
80
+
81
+ // Use an iterative approach to traverse the provenance chain
82
+ let nodesToProcess = [...this.provenance];
83
+ const visited = new Set(nodesToProcess);
84
+
85
+ while (nodesToProcess.length > 0) {
86
+ const currentId = nodesToProcess.shift(); // Get the next node to process
87
+ const node = rootNode.nodeMap.get(currentId);
88
+
89
+ if (node) {
90
+ node.highlight(color);
91
+ if (node.provenance) {
92
+ node.provenance.forEach(pId => {
93
+ if (!visited.has(pId)) {
94
+ visited.add(pId);
95
+ nodesToProcess.push(pId);
96
+ }
97
+ });
98
+ }
99
+ }
100
+ }
101
+ }
102
+
103
+ clearProvenance(event) {
104
+ event.stopPropagation();
105
+ const rootNode = this.getRootNode();
106
+ if (rootNode) {
107
+ rootNode.clearProvenanceHighlights();
108
+ }
109
+ }
110
+
111
+ highlight(color) {
112
+ this.backRect.setFillColor(color);
113
+ this.backRect.setOpacity(1.0);
114
+
115
+ // also highlight children
116
+ this.childList.forEach((child) => {
117
+ if (child instanceof omdMetaExpression)
118
+ child.highlight(color);
119
+ });
120
+ }
121
+
122
+ clearProvenanceHighlights() {
123
+ // Preserve step visualizer highlights (explain highlights) if present
124
+ if (this.isExplainHighlighted) {
125
+ // Restore the explain highlight color and ensure full opacity
126
+ this.backRect.setFillColor(omdColor.explainColor);
127
+ this.backRect.setOpacity(1.0);
128
+ } else if (this.isProvenanceHighlighted) {
129
+ // Preserve step visualizer provenance highlights
130
+ this.backRect.setFillColor(omdColor.explainColor);
131
+ this.backRect.setOpacity(1.0);
132
+ } else {
133
+ // Reset to the default background state
134
+ this.backRect.setFillColor(omdColor.lightGray);
135
+ if (!this.defaultOpaqueBack) {
136
+ this.backRect.setOpacity(0.01);
137
+ }
138
+ }
139
+
140
+ // Recursively clear highlights for all children in the tree
141
+ this.childList.forEach((child) => {
142
+ if (child instanceof omdMetaExpression && typeof child.clearProvenanceHighlights === 'function') {
143
+ child.clearProvenanceHighlights();
144
+ }
145
+ });
146
+ }
147
+
148
+ /**
149
+ * Recursively applies or clears a persistent "explain" highlight.
150
+ * This is used by the step visualizer to mark nodes that have changed between steps.
151
+ * The highlight is preserved during hover events.
152
+ * @param {boolean} isOn - True to apply the highlight, false to clear it.
153
+ * @param {string} color - The color to use for the highlight.
154
+ */
155
+ setExplainHighlight(isOn = true, color = omdColor.explainColor) {
156
+ this.isExplainHighlighted = isOn;
157
+
158
+ if (isOn) {
159
+ this.backRect.setFillColor(color);
160
+ this.backRect.setOpacity(1.0);
161
+ } else {
162
+ // Reset to default state
163
+ this.backRect.setFillColor(omdColor.lightGray);
164
+ if (!this.defaultOpaqueBack) {
165
+ this.backRect.setOpacity(0.01);
166
+ }
167
+ }
168
+
169
+ // Use the same traversal logic as hover highlighting to recurse
170
+ if (this.argumentNodeList) {
171
+ Object.values(this.argumentNodeList).forEach(child => {
172
+ if (child && typeof child.setExplainHighlight === 'function') {
173
+ child.setExplainHighlight(isOn, color);
174
+ }
175
+ });
176
+ }
177
+ }
178
+
179
+ getRootNode() {
180
+ let current = this;
181
+ // Traverse upwards as long as the parent is also part of the omd expression system
182
+ while (current.parent && (current.parent instanceof omdMetaExpression)) {
183
+ current = current.parent;
184
+ }
185
+ return current;
186
+ }
187
+
188
+ findAllNodes(nodes = []) {
189
+ nodes.push(this);
190
+ if (this.childList) {
191
+ this.childList.forEach(child => {
192
+ if (child.findAllNodes) { // Ensure child has the method
193
+ child.findAllNodes(nodes);
194
+ }
195
+ });
196
+ }
197
+ return nodes;
198
+ }
199
+
200
+ // ===== OLD SELECTION LOGIC (can be removed or kept for other purposes) =====
201
+
202
+ select(root) {
203
+ if (root === this) return;
204
+
205
+ if (!(root instanceof omdMetaExpression)) root = this;
206
+
207
+ this.backRect.setFillColor( omdColor.hiliteColor );
208
+ this.backRect.setOpacity( 1.0 );
209
+
210
+ this.childList.forEach((child) => {
211
+ if (child instanceof omdMetaExpression)
212
+ child.select(root);
213
+ });
214
+
215
+ if (this === root && this.parent instanceof omdMetaExpression)
216
+ root.parent.deselect(root);
217
+ }
218
+
219
+ deselect(root) {
220
+ if (!(root instanceof omdMetaExpression)) root = this;
221
+
222
+ if (this === root && this.parent instanceof omdMetaExpression)
223
+ root.parent.select(root);
224
+
225
+ if (root === this && this.parent instanceof omdMetaExpression) return;
226
+
227
+ this.backRect.setFillColor( omdColor.lightGray );
228
+ if ( this.defaultOpaqueBack == false )
229
+ this.backRect.setOpacity(0.01);
230
+
231
+ this.childList.forEach((child) => {
232
+ if (child !== root && child instanceof omdMetaExpression)
233
+ child.deselect(root);
234
+ });
235
+
236
+ }
237
+
238
+ // select(root)
239
+ // {
240
+ // this.backRect.setFillColor( omdColor.hiliteColor );
241
+ // this.backRect.setOpacity( 1.0 );
242
+
243
+ // if (!(root instanceof omdMetaExpression))
244
+ // root = this;
245
+
246
+ // this.childList.forEach((child) => {
247
+ // if (child instanceof omdMetaExpression)
248
+ // child.select(root);
249
+ // });
250
+ // if (this === root)
251
+ // this.unselectParents(root);
252
+ // }
253
+
254
+ // deselect(root)
255
+ // {
256
+ // this.backRect.setFillColor( omdColor.lightGray );
257
+ // if ( this.defaultOpaqueBack == false )
258
+ // this.backRect.setOpacity(0.01);
259
+
260
+ // this.childList.forEach((child) => {
261
+ // if (child !== root && child instanceof omdMetaExpression) {
262
+ // child.deselect(root);
263
+ // }
264
+ // });
265
+
266
+ // if (this.parent instanceof omdMetaExpression)
267
+ // this.parent.select(this.parent);
268
+ // }
269
+
270
+ // unselectParents(root)
271
+ // {
272
+ // if (this.parent instanceof omdMetaExpression) {
273
+ // this.parent.unselectParents(root);
274
+ // this.parent.deselect(root);
275
+ // }
276
+ // }
277
+
278
+ hideBackgroundByDefault()
279
+ {
280
+ this.defaultOpaqueBack = false;
281
+ this.backRect.setOpacity(0.01);
282
+ }
283
+
284
+ makeBackgroundLight() { this.backRect.setFillColor( omdColor.lightGray ) }
285
+ makeBackgroundDark() { this.backRect.setFillColor( omdColor.mediumGray ) }
286
+
287
+ }