@teachinglab/omd 0.2.9 → 0.3.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.
- package/README.md +1 -1
- package/canvas/core/omdCanvas.js +5 -0
- package/canvas/index.js +1 -1
- package/canvas/tools/PencilTool.js +6 -1
- package/docs/api-reference.md +1 -1
- package/docs/index.md +39 -0
- package/omd/core/omdEquationStack.js +8 -0
- package/omd/nodes/omdEquationNode.js +14 -0
- package/omd/step-visualizer/omdStepVisualizer.js +25 -1
- package/omd/step-visualizer/omdStepVisualizerHighlighting.js +41 -0
- package/omd/step-visualizer/omdStepVisualizerLayout.js +5 -0
- package/omd/utils/omdPopup.js +141 -20
- package/omd/utils/omdStepVisualizerInteractiveSteps.js +5 -3
- package/package.json +12 -6
- package/readme.html +320 -0
- package/docs/user-guide.md +0 -9
- /package/canvas/drawing/{Segment.js → segment.js} +0 -0
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# OMD (
|
|
1
|
+
# OMD (Open Math Display)
|
|
2
2
|
|
|
3
3
|
OMD is a JavaScript library for creating interactive mathematical interfaces in web applications. Build everything from simple equation displays to complex step-by-step solution systems with rich visual feedback and user interaction.
|
|
4
4
|
|
package/canvas/core/omdCanvas.js
CHANGED
|
@@ -217,6 +217,8 @@ export class omdCanvas {
|
|
|
217
217
|
const stroke = this.strokes.get(strokeId);
|
|
218
218
|
if (!stroke) return false;
|
|
219
219
|
|
|
220
|
+
console.log('[Canvas Debug] Removing stroke:', strokeId, 'Remaining strokes:', this.strokes.size - 1);
|
|
221
|
+
|
|
220
222
|
if (stroke.element.parentNode) {
|
|
221
223
|
stroke.element.parentNode.removeChild(stroke.element);
|
|
222
224
|
}
|
|
@@ -232,6 +234,8 @@ export class omdCanvas {
|
|
|
232
234
|
* Clear all strokes
|
|
233
235
|
*/
|
|
234
236
|
clear() {
|
|
237
|
+
console.log('[Canvas Debug] Clearing all strokes. Current count:', this.strokes.size);
|
|
238
|
+
|
|
235
239
|
this.strokes.forEach((stroke, id) => {
|
|
236
240
|
if (stroke.element.parentNode) {
|
|
237
241
|
stroke.element.parentNode.removeChild(stroke.element);
|
|
@@ -241,6 +245,7 @@ export class omdCanvas {
|
|
|
241
245
|
this.strokes.clear();
|
|
242
246
|
this.selectedStrokes.clear();
|
|
243
247
|
|
|
248
|
+
console.log('[Canvas Debug] Canvas cleared. Stroke count now:', this.strokes.size);
|
|
244
249
|
this.emit('cleared');
|
|
245
250
|
}
|
|
246
251
|
|
package/canvas/index.js
CHANGED
|
@@ -19,7 +19,7 @@ export { Cursor } from './ui/cursor.js';
|
|
|
19
19
|
|
|
20
20
|
// Drawing objects
|
|
21
21
|
export { Stroke } from './drawing/stroke.js';
|
|
22
|
-
export { segment } from './drawing/
|
|
22
|
+
export { segment } from './drawing/segment.js';
|
|
23
23
|
|
|
24
24
|
// Utilities
|
|
25
25
|
export { BoundingBox } from './utils/boundingBox.js';
|
|
@@ -33,6 +33,8 @@ export class PencilTool extends Tool {
|
|
|
33
33
|
onPointerDown(event) {
|
|
34
34
|
if (!this.canUse()) return;
|
|
35
35
|
|
|
36
|
+
console.log('[Pencil Debug] Starting new stroke at:', event.x, event.y);
|
|
37
|
+
|
|
36
38
|
this.isDrawing = true;
|
|
37
39
|
this.points = [];
|
|
38
40
|
this.lastPoint = { x: event.x, y: event.y };
|
|
@@ -51,7 +53,8 @@ export class PencilTool extends Tool {
|
|
|
51
53
|
this.addPoint(event.x, event.y, event.pressure);
|
|
52
54
|
|
|
53
55
|
// Add stroke to canvas
|
|
54
|
-
this.canvas.addStroke(this.currentStroke);
|
|
56
|
+
const strokeId = this.canvas.addStroke(this.currentStroke);
|
|
57
|
+
console.log('[Pencil Debug] Added stroke to canvas with ID:', strokeId, 'Total strokes:', this.canvas.strokes.size);
|
|
55
58
|
|
|
56
59
|
this.canvas.emit('strokeStarted', {
|
|
57
60
|
stroke: this.currentStroke,
|
|
@@ -99,6 +102,8 @@ export class PencilTool extends Tool {
|
|
|
99
102
|
// Finish the stroke
|
|
100
103
|
this.currentStroke.finish();
|
|
101
104
|
|
|
105
|
+
console.log('[Pencil Debug] Finished stroke with', this.points.length, 'points. Canvas now has', this.canvas.strokes.size, 'strokes');
|
|
106
|
+
|
|
102
107
|
this.canvas.emit('strokeCompleted', {
|
|
103
108
|
stroke: this.currentStroke,
|
|
104
109
|
tool: this.name,
|
package/docs/api-reference.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# OMD Library API Reference
|
|
2
2
|
|
|
3
|
-
> This is the complete API reference for the OMD (
|
|
3
|
+
> This is the complete API reference for the OMD (Open Math Display) library. Use the table of contents below to navigate to the detailed documentation for each module and class.
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
package/docs/index.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# OMD Documentation
|
|
2
|
+
|
|
3
|
+
Welcome to the Open Math Display (OMD) documentation.
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
- [User Guide](user-guide.html) - Learn how to use OMD in your projects
|
|
8
|
+
- [API Reference](api-reference.html) - Complete API documentation
|
|
9
|
+
|
|
10
|
+
## API Documentation
|
|
11
|
+
|
|
12
|
+
### Core Classes
|
|
13
|
+
- [omdNode](api/omdNode.html) - Base node class
|
|
14
|
+
- [omdLeafNode](api/omdLeafNode.html) - Leaf nodes (numbers, variables)
|
|
15
|
+
- [omdGroupNode](api/omdGroupNode.html) - Group/container nodes
|
|
16
|
+
- [omdOperatorNode](api/omdOperatorNode.html) - Mathematical operators
|
|
17
|
+
- [omdFunctionNode](api/omdFunctionNode.html) - Function nodes
|
|
18
|
+
- [omdPowerNode](api/omdPowerNode.html) - Exponent/power nodes
|
|
19
|
+
- [omdRationalNode](api/omdRationalNode.html) - Fraction nodes
|
|
20
|
+
- [omdSqrtNode](api/omdSqrtNode.html) - Square root nodes
|
|
21
|
+
|
|
22
|
+
### Display & Visualization
|
|
23
|
+
- [omdStepVisualizer](api/omdStepVisualizer.html) - Step-by-step visualization
|
|
24
|
+
- [omdSimplification](api/omdSimplification.html) - Expression simplification
|
|
25
|
+
- [omdPopup](api/omdPopup.html) - Popup overlay system
|
|
26
|
+
|
|
27
|
+
### Utilities & Helpers
|
|
28
|
+
- [omdHelpers](api/omdHelpers.html) - Utility functions
|
|
29
|
+
- [eventManager](api/eventManager.html) - Event handling
|
|
30
|
+
- [focusFrameManager](api/focusFrameManager.html) - Focus frame management
|
|
31
|
+
- [configuration-options](api/configuration-options.html) - Configuration options
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
Visit the [examples directory](../examples/index.html) to see OMD in action.
|
|
36
|
+
|
|
37
|
+
## Contributing
|
|
38
|
+
|
|
39
|
+
See the main [README](../readme.html) for information about contributing to OMD.
|
|
@@ -467,10 +467,18 @@ export class omdEquationStack extends jsvgGroup {
|
|
|
467
467
|
// If this is a step visualizer, rebuild its dots/lines
|
|
468
468
|
if (typeof seq.rebuildVisualizer === 'function') {
|
|
469
469
|
try {
|
|
470
|
+
// Clear all step visualizer highlights before rebuilding
|
|
471
|
+
if (seq.highlighting && typeof seq.highlighting.clearAllExplainHighlights === 'function') {
|
|
472
|
+
seq.highlighting.clearAllExplainHighlights();
|
|
473
|
+
}
|
|
470
474
|
seq.rebuildVisualizer();
|
|
471
475
|
} catch (_) {}
|
|
472
476
|
} else if (typeof seq._initializeVisualElements === 'function') {
|
|
473
477
|
try {
|
|
478
|
+
// Clear all step visualizer highlights before rebuilding
|
|
479
|
+
if (seq.highlighting && typeof seq.highlighting.clearAllExplainHighlights === 'function') {
|
|
480
|
+
seq.highlighting.clearAllExplainHighlights();
|
|
481
|
+
}
|
|
474
482
|
seq._initializeVisualElements();
|
|
475
483
|
if (typeof seq.computeDimensions === 'function') seq.computeDimensions();
|
|
476
484
|
if (typeof seq.updateLayout === 'function') seq.updateLayout();
|
|
@@ -1279,6 +1279,20 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1279
1279
|
if (node.operation === 'add' || node.operation === 'plus') {
|
|
1280
1280
|
values.push(...leftValues, ...rightValues);
|
|
1281
1281
|
}
|
|
1282
|
+
// For subtraction, add left values and negate right values
|
|
1283
|
+
else if (node.operation === 'subtract' || node.operation === 'minus') {
|
|
1284
|
+
values.push(...leftValues);
|
|
1285
|
+
// For subtraction, we need to represent negative values
|
|
1286
|
+
for (const rightValue of rightValues) {
|
|
1287
|
+
if (typeof rightValue === 'number') {
|
|
1288
|
+
// Negate numeric values
|
|
1289
|
+
values.push(-rightValue);
|
|
1290
|
+
} else {
|
|
1291
|
+
// For variables/expressions, prepend with negative sign
|
|
1292
|
+
values.push(`-${rightValue}`);
|
|
1293
|
+
}
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1282
1296
|
// For multiplication, handle special cases
|
|
1283
1297
|
else if (node.operation === 'multiply') {
|
|
1284
1298
|
// Check if one operand is a constant (coefficient)
|
|
@@ -346,6 +346,11 @@ export class omdStepVisualizer extends omdEquationSequenceNode {
|
|
|
346
346
|
* Force rebuild visual container (dots/lines) from scratch
|
|
347
347
|
*/
|
|
348
348
|
rebuildVisualizer() {
|
|
349
|
+
// Clear all step visualizer highlights before rebuilding
|
|
350
|
+
if (this.highlighting && typeof this.highlighting.clearAllExplainHighlights === 'function') {
|
|
351
|
+
this.highlighting.clearAllExplainHighlights();
|
|
352
|
+
}
|
|
353
|
+
|
|
349
354
|
if (this.visualContainer) {
|
|
350
355
|
this.removeChild(this.visualContainer);
|
|
351
356
|
}
|
|
@@ -455,6 +460,11 @@ export class omdStepVisualizer extends omdEquationSequenceNode {
|
|
|
455
460
|
* Override addStep to update visual elements when new steps are added
|
|
456
461
|
*/
|
|
457
462
|
addStep(step, options = {}) {
|
|
463
|
+
// Clear all step visualizer highlights when adding new steps (stack expansion)
|
|
464
|
+
if (this.highlighting && typeof this.highlighting.clearAllExplainHighlights === 'function') {
|
|
465
|
+
this.highlighting.clearAllExplainHighlights();
|
|
466
|
+
}
|
|
467
|
+
|
|
458
468
|
// Call parent first to add the step properly
|
|
459
469
|
super.addStep(step, options);
|
|
460
470
|
|
|
@@ -546,6 +556,11 @@ export class omdStepVisualizer extends omdEquationSequenceNode {
|
|
|
546
556
|
* @returns {boolean} Whether an operation was undone
|
|
547
557
|
*/
|
|
548
558
|
undoLastOperation() {
|
|
559
|
+
// Clear all step visualizer highlights before undoing
|
|
560
|
+
if (this.highlighting && typeof this.highlighting.clearAllExplainHighlights === 'function') {
|
|
561
|
+
this.highlighting.clearAllExplainHighlights();
|
|
562
|
+
}
|
|
563
|
+
|
|
549
564
|
// Remove bottom-most equation and its preceding operation display
|
|
550
565
|
const beforeCount = this.steps.length;
|
|
551
566
|
const removed = super.undoLastOperation ? super.undoLastOperation() : false;
|
|
@@ -592,6 +607,14 @@ export class omdStepVisualizer extends omdEquationSequenceNode {
|
|
|
592
607
|
*/
|
|
593
608
|
setDotsClickable(enabled) {
|
|
594
609
|
this.dotsClickable = enabled;
|
|
610
|
+
|
|
611
|
+
// If disabling, clear any active highlights and dots
|
|
612
|
+
if (!enabled) {
|
|
613
|
+
this._clearActiveDot();
|
|
614
|
+
// Use the more thorough clearing to ensure no stale highlights remain
|
|
615
|
+
this.highlighting.clearAllExplainHighlights();
|
|
616
|
+
}
|
|
617
|
+
|
|
595
618
|
this.stepDots.forEach(dot => {
|
|
596
619
|
this.layoutManager.updateDotClickability(dot);
|
|
597
620
|
});
|
|
@@ -674,7 +697,8 @@ export class omdStepVisualizer extends omdEquationSequenceNode {
|
|
|
674
697
|
this.setLineAboveColor(this.activeDotIndex, this.styling.lineColor);
|
|
675
698
|
this.textBoxManager.removeTextBoxForDot(this.activeDotIndex);
|
|
676
699
|
|
|
677
|
-
|
|
700
|
+
// Use thorough clearing to ensure no stale highlights remain
|
|
701
|
+
this.highlighting.clearAllExplainHighlights();
|
|
678
702
|
|
|
679
703
|
// Temporarily disable equation repositioning for simple dot state changes
|
|
680
704
|
const originalRepositioning = this.layoutManager.allowEquationRepositioning;
|
|
@@ -101,6 +101,47 @@ export class omdStepVisualizerHighlighting {
|
|
|
101
101
|
this.stepVisualizer.stepVisualizerHighlights.clear();
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
/**
|
|
105
|
+
* Clears ALL explain highlights from the entire sequence, not just tracked ones.
|
|
106
|
+
* This is more thorough than clearHighlights() and should be used when
|
|
107
|
+
* the step visualizer is disabled or when we need to ensure no stale highlights remain.
|
|
108
|
+
*/
|
|
109
|
+
clearAllExplainHighlights() {
|
|
110
|
+
// Clear tracked highlights first
|
|
111
|
+
this.clearHighlights();
|
|
112
|
+
|
|
113
|
+
// Also clear any explain highlights from the entire sequence tree
|
|
114
|
+
const rootNode = this.stepVisualizer.getRootNode ? this.stepVisualizer.getRootNode() : null;
|
|
115
|
+
if (rootNode) {
|
|
116
|
+
this._clearExplainHighlightsFromTree(rootNode);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Recursively clears explain highlights from an entire tree
|
|
122
|
+
* @param {omdNode} node - The root node to start clearing from
|
|
123
|
+
* @private
|
|
124
|
+
*/
|
|
125
|
+
_clearExplainHighlightsFromTree(node) {
|
|
126
|
+
if (node && typeof node.setExplainHighlight === 'function') {
|
|
127
|
+
node.setExplainHighlight(false);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Recursively clear from children
|
|
131
|
+
if (node && node.childList && Array.isArray(node.childList)) {
|
|
132
|
+
node.childList.forEach(child => {
|
|
133
|
+
this._clearExplainHighlightsFromTree(child);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Also check argumentNodeList if it exists
|
|
138
|
+
if (node && node.argumentNodeList) {
|
|
139
|
+
Object.values(node.argumentNodeList).forEach(child => {
|
|
140
|
+
this._clearExplainHighlightsFromTree(child);
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
104
145
|
/**
|
|
105
146
|
* Highlights nodes in the previous equation based on provenance from changed nodes.
|
|
106
147
|
* This creates a visual connection between the current changes and their origins.
|
|
@@ -723,6 +723,11 @@ export class omdStepVisualizerLayout {
|
|
|
723
723
|
_handleExpansionDotClick(expansionDot) {
|
|
724
724
|
const sv = this.stepVisualizer;
|
|
725
725
|
|
|
726
|
+
// Clear all step visualizer highlights when expanding/contracting
|
|
727
|
+
if (sv.highlighting && typeof sv.highlighting.clearAllExplainHighlights === 'function') {
|
|
728
|
+
sv.highlighting.clearAllExplainHighlights();
|
|
729
|
+
}
|
|
730
|
+
|
|
726
731
|
if (expansionDot.isCollapseDot) {
|
|
727
732
|
// Handle collapse dot click - hide only the specific group of intermediate steps
|
|
728
733
|
|
package/omd/utils/omdPopup.js
CHANGED
|
@@ -73,20 +73,19 @@ export class omdPopup {
|
|
|
73
73
|
|
|
74
74
|
// Store original opacities for animation
|
|
75
75
|
const originalPopupOpacity = this.popup.opacity;
|
|
76
|
-
const originalCanvasOpacity = this.penCanvas?.container?.style.opacity || '1';
|
|
77
76
|
const originalTextInputOpacity = this.popupTextInput?.div?.style.opacity || '1';
|
|
78
77
|
|
|
79
|
-
// Ensure canvas and text input are visible for animation
|
|
78
|
+
// Ensure canvas and text input are visible for animation but preserve canvas drawing
|
|
80
79
|
if (this.penCanvas && this.penCanvas.container) {
|
|
81
80
|
this.penCanvas.container.style.display = 'block';
|
|
82
|
-
|
|
81
|
+
// Don't fade canvas opacity - keep strokes visible during popup hide
|
|
83
82
|
}
|
|
84
83
|
if (this.popupTextInput && this.popupTextInput.div) {
|
|
85
84
|
this.popupTextInput.div.style.display = 'flex';
|
|
86
85
|
this.popupTextInput.div.style.opacity = originalTextInputOpacity;
|
|
87
86
|
}
|
|
88
87
|
|
|
89
|
-
// Animate
|
|
88
|
+
// Animate popup and canvas together
|
|
90
89
|
const duration = this.options.animationDuration || 300;
|
|
91
90
|
const startTime = performance.now();
|
|
92
91
|
|
|
@@ -103,7 +102,7 @@ export class omdPopup {
|
|
|
103
102
|
this.popup.setOpacity(currentOpacity);
|
|
104
103
|
}
|
|
105
104
|
|
|
106
|
-
// Animate canvas with
|
|
105
|
+
// Animate canvas container with same opacity curve
|
|
107
106
|
if (this.penCanvas && this.penCanvas.container) {
|
|
108
107
|
this.penCanvas.container.style.opacity = currentOpacity;
|
|
109
108
|
}
|
|
@@ -116,9 +115,10 @@ export class omdPopup {
|
|
|
116
115
|
if (progress < 1) {
|
|
117
116
|
this.popupAnimationId = requestAnimationFrame(animate);
|
|
118
117
|
} else {
|
|
119
|
-
// Animation complete - hide and cleanup
|
|
118
|
+
// Animation complete - hide and cleanup both popup and canvas
|
|
120
119
|
if (this.penCanvas && this.penCanvas.container) {
|
|
121
120
|
this.penCanvas.container.style.display = 'none';
|
|
121
|
+
this.penCanvas.container.style.opacity = '1'; // Reset for next show
|
|
122
122
|
}
|
|
123
123
|
if (this.popupTextInput && this.popupTextInput.div) {
|
|
124
124
|
this.popupTextInput.div.style.display = 'none';
|
|
@@ -131,7 +131,7 @@ export class omdPopup {
|
|
|
131
131
|
|
|
132
132
|
return new Promise((resolve) => {
|
|
133
133
|
setTimeout(resolve, duration);
|
|
134
|
-
|
|
134
|
+
});
|
|
135
135
|
}
|
|
136
136
|
|
|
137
137
|
/**
|
|
@@ -475,19 +475,22 @@ export class omdPopup {
|
|
|
475
475
|
// Add click debugging
|
|
476
476
|
canvasContainer.addEventListener('click', (e) => {});
|
|
477
477
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
478
|
+
// Store cleanup function
|
|
479
|
+
this.penCanvasCleanup = () => {
|
|
480
|
+
if (this.penCanvas) {
|
|
481
|
+
this.penCanvas.destroy();
|
|
482
|
+
}
|
|
483
|
+
if (foreignObject && foreignObject.parentNode) {
|
|
484
|
+
foreignObject.parentNode.removeChild(foreignObject);
|
|
485
|
+
} else if (canvasContainer && canvasContainer.parentNode) {
|
|
486
|
+
canvasContainer.parentNode.removeChild(canvasContainer);
|
|
487
|
+
}
|
|
488
|
+
// Remove step visualizer listeners
|
|
489
|
+
this._removeStepVisualizerListeners();
|
|
490
|
+
};
|
|
491
|
+
|
|
492
|
+
// Set up step visualizer change detection
|
|
493
|
+
this._setupStepVisualizerListeners(); // If we're currently in pen mode, show the canvas
|
|
491
494
|
if (this.currentMode === 'pen' && this.popup) {
|
|
492
495
|
this._addCanvasToParent(foreignObject || canvasContainer);
|
|
493
496
|
}
|
|
@@ -510,6 +513,12 @@ export class omdPopup {
|
|
|
510
513
|
if (!this.penCanvas) {
|
|
511
514
|
this._createPenCanvas();
|
|
512
515
|
} else {
|
|
516
|
+
// Show existing canvas and ensure it's fully opaque
|
|
517
|
+
const element = this.penCanvas.foreignObject || this.penCanvas.container;
|
|
518
|
+
if (element) {
|
|
519
|
+
element.style.display = 'block';
|
|
520
|
+
element.style.opacity = '1'; // Ensure full opacity for stroke visibility
|
|
521
|
+
}
|
|
513
522
|
this._addCanvasToParent();
|
|
514
523
|
}
|
|
515
524
|
}
|
|
@@ -679,12 +688,22 @@ export class omdPopup {
|
|
|
679
688
|
const easedProgress = 1 - Math.pow(1 - progress, 3);
|
|
680
689
|
const currentOpacity = fromOpacity + (deltaOpacity * easedProgress);
|
|
681
690
|
|
|
691
|
+
// Animate popup
|
|
682
692
|
this.popup.setOpacity(currentOpacity);
|
|
683
693
|
|
|
694
|
+
// Animate canvas with same opacity if it exists
|
|
695
|
+
if (this.penCanvas && this.penCanvas.container && this.currentMode === 'pen') {
|
|
696
|
+
this.penCanvas.container.style.opacity = currentOpacity;
|
|
697
|
+
}
|
|
698
|
+
|
|
684
699
|
if (progress < 1) {
|
|
685
700
|
this.popupAnimationId = requestAnimationFrame(animate);
|
|
686
701
|
} else {
|
|
687
702
|
this.popupAnimationId = null;
|
|
703
|
+
// Ensure canvas is fully opaque when animation completes
|
|
704
|
+
if (this.penCanvas && this.penCanvas.container && this.currentMode === 'pen') {
|
|
705
|
+
this.penCanvas.container.style.opacity = '1';
|
|
706
|
+
}
|
|
688
707
|
resolve();
|
|
689
708
|
}
|
|
690
709
|
};
|
|
@@ -820,6 +839,9 @@ export class omdPopup {
|
|
|
820
839
|
this.resizeObserver = null;
|
|
821
840
|
}
|
|
822
841
|
|
|
842
|
+
// Clean up step visualizer listeners
|
|
843
|
+
this._removeStepVisualizerListeners();
|
|
844
|
+
|
|
823
845
|
// Clean up animation
|
|
824
846
|
if (this.popupAnimationId) {
|
|
825
847
|
cancelAnimationFrame(this.popupAnimationId);
|
|
@@ -897,6 +919,87 @@ export class omdPopup {
|
|
|
897
919
|
this.resizeObserver.observe(document.body);
|
|
898
920
|
}
|
|
899
921
|
|
|
922
|
+
/**
|
|
923
|
+
* Setup step visualizer listeners to track expand/collapse
|
|
924
|
+
* @private
|
|
925
|
+
*/
|
|
926
|
+
_setupStepVisualizerListeners() {
|
|
927
|
+
if (!this.penCanvas) return;
|
|
928
|
+
|
|
929
|
+
// Listen for step visualizer events that might change layout
|
|
930
|
+
this._stepVisualizerUpdateHandler = () => {
|
|
931
|
+
console.log('[Step Visualizer Debug] Layout change detected, updating canvas position');
|
|
932
|
+
// Small delay to allow layout to settle
|
|
933
|
+
setTimeout(() => this._updateCanvasPosition(), 50);
|
|
934
|
+
};
|
|
935
|
+
|
|
936
|
+
// Listen for various events that might indicate step visualizer changes
|
|
937
|
+
document.addEventListener('click', this._stepVisualizerUpdateHandler);
|
|
938
|
+
window.addEventListener('resize', this._stepVisualizerUpdateHandler);
|
|
939
|
+
|
|
940
|
+
// Listen for custom step visualizer events if they exist
|
|
941
|
+
if (this.parentElement && this.parentElement.element) {
|
|
942
|
+
this.parentElement.element.addEventListener('stepVisualizerChanged', this._stepVisualizerUpdateHandler);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
// Set up mutation observer to detect DOM changes in step visualizer
|
|
946
|
+
if (this.parentElement && this.parentElement.element) {
|
|
947
|
+
this._mutationObserver = new MutationObserver((mutations) => {
|
|
948
|
+
let shouldUpdate = false;
|
|
949
|
+
for (const mutation of mutations) {
|
|
950
|
+
// Check if any changes might affect layout
|
|
951
|
+
if (mutation.type === 'attributes' &&
|
|
952
|
+
(mutation.attributeName === 'style' ||
|
|
953
|
+
mutation.attributeName === 'class' ||
|
|
954
|
+
mutation.attributeName === 'transform')) {
|
|
955
|
+
console.log('[Step Visualizer Debug] Mutation detected:', mutation.attributeName, mutation.target);
|
|
956
|
+
shouldUpdate = true;
|
|
957
|
+
break;
|
|
958
|
+
}
|
|
959
|
+
if (mutation.type === 'childList' &&
|
|
960
|
+
(mutation.addedNodes.length > 0 || mutation.removedNodes.length > 0)) {
|
|
961
|
+
console.log('[Step Visualizer Debug] Child list mutation detected');
|
|
962
|
+
shouldUpdate = true;
|
|
963
|
+
break;
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (shouldUpdate) {
|
|
967
|
+
setTimeout(() => this._updateCanvasPosition(), 10);
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
// Observe the parent element and its children
|
|
972
|
+
this._mutationObserver.observe(this.parentElement.element, {
|
|
973
|
+
childList: true,
|
|
974
|
+
attributes: true,
|
|
975
|
+
subtree: true,
|
|
976
|
+
attributeFilter: ['style', 'class', 'transform', 'viewBox']
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
/**
|
|
982
|
+
* Remove step visualizer listeners
|
|
983
|
+
* @private
|
|
984
|
+
*/
|
|
985
|
+
_removeStepVisualizerListeners() {
|
|
986
|
+
if (this._stepVisualizerUpdateHandler) {
|
|
987
|
+
document.removeEventListener('click', this._stepVisualizerUpdateHandler);
|
|
988
|
+
window.removeEventListener('resize', this._stepVisualizerUpdateHandler);
|
|
989
|
+
|
|
990
|
+
if (this.parentElement && this.parentElement.element) {
|
|
991
|
+
this.parentElement.element.removeEventListener('stepVisualizerChanged', this._stepVisualizerUpdateHandler);
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
this._stepVisualizerUpdateHandler = null;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
if (this._mutationObserver) {
|
|
998
|
+
this._mutationObserver.disconnect();
|
|
999
|
+
this._mutationObserver = null;
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
|
|
900
1003
|
/**
|
|
901
1004
|
* Update canvas position to match popup
|
|
902
1005
|
* @private
|
|
@@ -907,6 +1010,13 @@ export class omdPopup {
|
|
|
907
1010
|
const container = this.penCanvas.container;
|
|
908
1011
|
const popupRect = this.popup.svgObject ? this.popup.svgObject.getBoundingClientRect() : null;
|
|
909
1012
|
|
|
1013
|
+
console.log('[Canvas Position Debug] Update triggered:', {
|
|
1014
|
+
hasCanvas: !!this.penCanvas,
|
|
1015
|
+
hasContainer: !!container,
|
|
1016
|
+
strokeCount: this.penCanvas?.strokes?.size || 0,
|
|
1017
|
+
popupRect: popupRect ? `${popupRect.width}x${popupRect.height}` : 'null'
|
|
1018
|
+
});
|
|
1019
|
+
|
|
910
1020
|
if (popupRect && popupRect.width > 0 && popupRect.height > 0) {
|
|
911
1021
|
// Calculate button areas based on popup dimensions
|
|
912
1022
|
const leftButtonArea = this.buttonSize + (this.margin * 2);
|
|
@@ -927,10 +1037,21 @@ export class omdPopup {
|
|
|
927
1037
|
const finalWidth = Math.min(Math.max(contentWidth, this.canvasMinWidth), maxWidth);
|
|
928
1038
|
const finalHeight = Math.min(Math.max(contentHeight, this.canvasMinHeight), maxHeight);
|
|
929
1039
|
|
|
1040
|
+
console.log('[Canvas Position Debug] Moving canvas:', {
|
|
1041
|
+
from: `${container.style.left}, ${container.style.top}`,
|
|
1042
|
+
to: `${absoluteX}px, ${absoluteY}px`,
|
|
1043
|
+
size: `${finalWidth}x${finalHeight}`
|
|
1044
|
+
});
|
|
1045
|
+
|
|
930
1046
|
container.style.left = `${absoluteX}px`;
|
|
931
1047
|
container.style.top = `${absoluteY}px`;
|
|
932
1048
|
container.style.width = `${finalWidth}px`;
|
|
933
1049
|
container.style.height = `${finalHeight}px`;
|
|
1050
|
+
|
|
1051
|
+
// Check stroke count after move
|
|
1052
|
+
setTimeout(() => {
|
|
1053
|
+
console.log('[Canvas Position Debug] After move stroke count:', this.penCanvas?.strokes?.size || 0);
|
|
1054
|
+
}, 50);
|
|
934
1055
|
}
|
|
935
1056
|
}
|
|
936
1057
|
|
|
@@ -375,9 +375,11 @@ export class omdStepVisualizerInteractiveSteps {
|
|
|
375
375
|
alignItems: 'flex-start !important'
|
|
376
376
|
};
|
|
377
377
|
|
|
378
|
-
// Add drop shadow if requested
|
|
379
|
-
|
|
380
|
-
|
|
378
|
+
// Add drop shadow if requested - but NOT to individual step boxes
|
|
379
|
+
// The drop shadow should only be on the outer background rectangle
|
|
380
|
+
// Remove any previous drop shadow from individual steps
|
|
381
|
+
if (stepBox.div) {
|
|
382
|
+
stepBox.div.style.boxShadow = 'none';
|
|
381
383
|
}
|
|
382
384
|
|
|
383
385
|
// Set font family if specified
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teachinglab/omd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "omd",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"module": "./index.js",
|
|
@@ -32,20 +32,26 @@
|
|
|
32
32
|
"author": "jaredschiffman",
|
|
33
33
|
"license": "MIT",
|
|
34
34
|
"dependencies": {
|
|
35
|
+
"@netlify/vite-plugin": "^2.5.4",
|
|
36
|
+
"@teachinglab/jsvg": "0.1.1",
|
|
35
37
|
"dotenv": "^17.2.1",
|
|
36
38
|
"express": "^4.18.2",
|
|
37
39
|
"mathjs": "^14.5.2",
|
|
38
40
|
"openai": "^4.28.0",
|
|
39
|
-
"@teachinglab/jsvg": "0.1.1",
|
|
40
|
-
"@netlify/vite-plugin": "^2.5.4",
|
|
41
41
|
"vite": "^5.4.0"
|
|
42
42
|
},
|
|
43
43
|
"scripts": {
|
|
44
|
-
"dev": "vite",
|
|
45
|
-
"build": "vite build",
|
|
46
|
-
"
|
|
44
|
+
"dev": "npm run build:docs && vite",
|
|
45
|
+
"build": "vite build && node copy-static.js && node build-docs.js",
|
|
46
|
+
"build:docs": "node build-docs.js",
|
|
47
|
+
"build:static": "node copy-static.js",
|
|
48
|
+
"dev:netlify": "npm run build:docs && netlify dev"
|
|
47
49
|
},
|
|
48
50
|
"publishConfig": {
|
|
49
51
|
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"glob": "^11.0.3",
|
|
55
|
+
"marked": "^16.2.1"
|
|
50
56
|
}
|
|
51
57
|
}
|
package/readme.html
ADDED
|
@@ -0,0 +1,320 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>OMD (Open Math Display) - OMD Documentation</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
10
|
+
line-height: 1.6;
|
|
11
|
+
color: #333;
|
|
12
|
+
max-width: 1200px;
|
|
13
|
+
margin: 0 auto;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
background: #fff;
|
|
16
|
+
}
|
|
17
|
+
.header {
|
|
18
|
+
border-bottom: 1px solid #eee;
|
|
19
|
+
margin-bottom: 2rem;
|
|
20
|
+
padding-bottom: 1rem;
|
|
21
|
+
}
|
|
22
|
+
.header h1 {
|
|
23
|
+
margin: 0;
|
|
24
|
+
color: #2c3e50;
|
|
25
|
+
}
|
|
26
|
+
.nav {
|
|
27
|
+
margin: 1rem 0;
|
|
28
|
+
}
|
|
29
|
+
.nav a {
|
|
30
|
+
color: #3498db;
|
|
31
|
+
text-decoration: none;
|
|
32
|
+
margin-right: 1rem;
|
|
33
|
+
padding: 0.5rem 1rem;
|
|
34
|
+
border-radius: 4px;
|
|
35
|
+
transition: background-color 0.2s;
|
|
36
|
+
}
|
|
37
|
+
.nav a:hover {
|
|
38
|
+
background-color: #f8f9fa;
|
|
39
|
+
text-decoration: none;
|
|
40
|
+
}
|
|
41
|
+
.content h1, .content h2, .content h3, .content h4, .content h5, .content h6 {
|
|
42
|
+
color: #2c3e50;
|
|
43
|
+
margin-top: 2rem;
|
|
44
|
+
margin-bottom: 1rem;
|
|
45
|
+
}
|
|
46
|
+
.content h1 {
|
|
47
|
+
border-bottom: 2px solid #3498db;
|
|
48
|
+
padding-bottom: 0.5rem;
|
|
49
|
+
}
|
|
50
|
+
.content h2 {
|
|
51
|
+
border-bottom: 1px solid #eee;
|
|
52
|
+
padding-bottom: 0.3rem;
|
|
53
|
+
}
|
|
54
|
+
.content pre {
|
|
55
|
+
background: #f8f9fa;
|
|
56
|
+
border: 1px solid #e9ecef;
|
|
57
|
+
border-radius: 4px;
|
|
58
|
+
padding: 1rem;
|
|
59
|
+
overflow-x: auto;
|
|
60
|
+
}
|
|
61
|
+
.content code {
|
|
62
|
+
background: #f8f9fa;
|
|
63
|
+
padding: 0.2rem 0.4rem;
|
|
64
|
+
border-radius: 3px;
|
|
65
|
+
font-family: 'SFMono-Regular', Monaco, 'Cascadia Code', 'Roboto Mono', Consolas, 'Courier New', monospace;
|
|
66
|
+
}
|
|
67
|
+
.content pre code {
|
|
68
|
+
background: none;
|
|
69
|
+
padding: 0;
|
|
70
|
+
}
|
|
71
|
+
.content blockquote {
|
|
72
|
+
border-left: 4px solid #3498db;
|
|
73
|
+
margin: 1rem 0;
|
|
74
|
+
padding-left: 1rem;
|
|
75
|
+
color: #666;
|
|
76
|
+
}
|
|
77
|
+
.content table {
|
|
78
|
+
border-collapse: collapse;
|
|
79
|
+
width: 100%;
|
|
80
|
+
margin: 1rem 0;
|
|
81
|
+
}
|
|
82
|
+
.content th, .content td {
|
|
83
|
+
border: 1px solid #ddd;
|
|
84
|
+
padding: 0.75rem;
|
|
85
|
+
text-align: left;
|
|
86
|
+
}
|
|
87
|
+
.content th {
|
|
88
|
+
background: #f8f9fa;
|
|
89
|
+
font-weight: 600;
|
|
90
|
+
}
|
|
91
|
+
.content ul {
|
|
92
|
+
margin: 1rem 0;
|
|
93
|
+
}
|
|
94
|
+
.content li {
|
|
95
|
+
margin: 0.25rem 0;
|
|
96
|
+
}
|
|
97
|
+
.content a {
|
|
98
|
+
color: #3498db;
|
|
99
|
+
text-decoration: none;
|
|
100
|
+
}
|
|
101
|
+
.content a:hover {
|
|
102
|
+
text-decoration: underline;
|
|
103
|
+
}
|
|
104
|
+
.back-to-top {
|
|
105
|
+
position: fixed;
|
|
106
|
+
bottom: 20px;
|
|
107
|
+
right: 20px;
|
|
108
|
+
background: #3498db;
|
|
109
|
+
color: white;
|
|
110
|
+
padding: 10px 15px;
|
|
111
|
+
border-radius: 50px;
|
|
112
|
+
text-decoration: none;
|
|
113
|
+
opacity: 0.8;
|
|
114
|
+
transition: opacity 0.2s;
|
|
115
|
+
}
|
|
116
|
+
.back-to-top:hover {
|
|
117
|
+
opacity: 1;
|
|
118
|
+
text-decoration: none;
|
|
119
|
+
color: white;
|
|
120
|
+
}
|
|
121
|
+
@media (max-width: 768px) {
|
|
122
|
+
body {
|
|
123
|
+
padding: 10px;
|
|
124
|
+
}
|
|
125
|
+
.nav {
|
|
126
|
+
flex-direction: column;
|
|
127
|
+
}
|
|
128
|
+
.nav a {
|
|
129
|
+
display: block;
|
|
130
|
+
margin: 0.25rem 0;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
</style>
|
|
134
|
+
</head>
|
|
135
|
+
<body>
|
|
136
|
+
<div class="header">
|
|
137
|
+
<h1>OMD Documentation</h1>
|
|
138
|
+
<div class="nav">
|
|
139
|
+
<a href="./../index.html">Home</a>
|
|
140
|
+
<a href="./index.html">Documentation</a>
|
|
141
|
+
<a href="./api-reference.html">API Reference</a>
|
|
142
|
+
<a href="./../examples/index.html">Examples</a>
|
|
143
|
+
<a href="./../readme.html">README</a>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
|
|
147
|
+
<div class="content">
|
|
148
|
+
<h1 id="omd-open-math-display">OMD (Open Math Display)</h1>
|
|
149
|
+
<p>OMD is a JavaScript library for creating interactive mathematical interfaces in web applications. Build everything from simple equation displays to complex step-by-step solution systems with rich visual feedback and user interaction.</p>
|
|
150
|
+
<p><img src="https://i.imgur.com/CdtEi33.png" alt="OMD Demo"></p>
|
|
151
|
+
<h2 id="features">Features</h2>
|
|
152
|
+
<h3 id="interactive-math-rendering"><strong>Interactive Math Rendering</strong></h3>
|
|
153
|
+
<ul>
|
|
154
|
+
<li>High-quality SVG-based mathematical notation</li>
|
|
155
|
+
<li>Real-time expression manipulation and visualization</li>
|
|
156
|
+
<li>Automatic layout and alignment for complex equations</li>
|
|
157
|
+
</ul>
|
|
158
|
+
<h3 id="step-by-step-solutions"><strong>Step-by-Step Solutions</strong></h3>
|
|
159
|
+
<ul>
|
|
160
|
+
<li>Visual step tracking with detailed explanations</li>
|
|
161
|
+
<li>Simplification engine with rule-based transformations</li>
|
|
162
|
+
<li>Provenance tracking for highlighting related elements</li>
|
|
163
|
+
</ul>
|
|
164
|
+
<h3 id="rich-ui-components"><strong>Rich UI Components</strong></h3>
|
|
165
|
+
<ul>
|
|
166
|
+
<li>Built-in toolbar for common mathematical operations</li>
|
|
167
|
+
<li>Drag & drop interface for intuitive manipulation</li>
|
|
168
|
+
<li>Customizable canvas for multi-expression layouts</li>
|
|
169
|
+
</ul>
|
|
170
|
+
<h3 id="educational-features"><strong>Educational Features</strong></h3>
|
|
171
|
+
<ul>
|
|
172
|
+
<li>Interactive learning experiences</li>
|
|
173
|
+
<li>Progressive step revelation</li>
|
|
174
|
+
<li>Visual operation feedback and highlighting</li>
|
|
175
|
+
</ul>
|
|
176
|
+
<h2 id="installation">Installation</h2>
|
|
177
|
+
<h3 id="npm">npm</h3>
|
|
178
|
+
<pre><code class="language-bash">npm install @teachinglab/omd
|
|
179
|
+
</code></pre>
|
|
180
|
+
<h2 id="basic-usage">Basic Usage</h2>
|
|
181
|
+
<pre><code class="language-javascript">import { omdDisplay } from '@teachinglab/omd';
|
|
182
|
+
|
|
183
|
+
// Create a math display
|
|
184
|
+
const container = document.getElementById('math-container');
|
|
185
|
+
const display = new omdDisplay(container);
|
|
186
|
+
|
|
187
|
+
// Render an equation
|
|
188
|
+
display.render('2x + 3 = 11');
|
|
189
|
+
</code></pre>
|
|
190
|
+
<h3 id="step-by-step-solutions">Step-by-Step Solutions</h3>
|
|
191
|
+
<pre><code class="language-javascript">import { omdEquationStack, omdEquationNode } from '@teachinglab/omd';
|
|
192
|
+
|
|
193
|
+
// Create solution steps
|
|
194
|
+
const steps = [
|
|
195
|
+
omdEquationNode.fromString('2x + 3 = 11'),
|
|
196
|
+
omdEquationNode.fromString('2x = 8'),
|
|
197
|
+
omdEquationNode.fromString('x = 4')
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
// Create interactive equation stack
|
|
201
|
+
const stack = new omdEquationStack(steps, {
|
|
202
|
+
toolbar: true,
|
|
203
|
+
stepVisualizer: true
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
display.render(stack);
|
|
207
|
+
</code></pre>
|
|
208
|
+
<h2 id="core-concepts">Core Concepts</h2>
|
|
209
|
+
<h3 id="nodes-building-blocks"><strong>Nodes</strong> - Building Blocks</h3>
|
|
210
|
+
<p>Every mathematical element is a node in an expression tree:</p>
|
|
211
|
+
<ul>
|
|
212
|
+
<li><code>omdEquationNode</code> - Complete equations (e.g., <code>2x + 3 = 11</code>)</li>
|
|
213
|
+
<li><code>omdConstantNode</code> - Numbers (e.g., <code>5</code>, <code>3.14</code>)</li>
|
|
214
|
+
<li><code>omdVariableNode</code> - Variables (e.g., <code>x</code>, <code>y</code>)</li>
|
|
215
|
+
<li><code>omdBinaryExpressionNode</code> - Operations (e.g., <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code>)</li>
|
|
216
|
+
</ul>
|
|
217
|
+
<h3 id="sequences-solution-steps"><strong>Sequences</strong> - Solution Steps</h3>
|
|
218
|
+
<p>Group related equations for step-by-step solving:</p>
|
|
219
|
+
<pre><code class="language-javascript">const sequence = new omdEquationSequenceNode([
|
|
220
|
+
equation1, equation2, equation3
|
|
221
|
+
]);
|
|
222
|
+
</code></pre>
|
|
223
|
+
<h3 id="display-rendering-engine"><strong>Display</strong> - Rendering Engine</h3>
|
|
224
|
+
<p>Handles layout, centering, and visualization:</p>
|
|
225
|
+
<pre><code class="language-javascript">const display = new omdDisplay(container, {
|
|
226
|
+
fontSize: 36,
|
|
227
|
+
centerContent: true
|
|
228
|
+
});
|
|
229
|
+
</code></pre>
|
|
230
|
+
<h2 id="interactive-examples">Interactive Examples</h2>
|
|
231
|
+
<p>Explore OMD's capabilities with our comprehensive examples:</p>
|
|
232
|
+
<table>
|
|
233
|
+
<thead>
|
|
234
|
+
<tr>
|
|
235
|
+
<th>Category</th>
|
|
236
|
+
<th>Example</th>
|
|
237
|
+
<th>Description</th>
|
|
238
|
+
</tr>
|
|
239
|
+
</thead>
|
|
240
|
+
<tbody><tr>
|
|
241
|
+
<td><strong>Getting Started</strong></td>
|
|
242
|
+
<td><a href="examples/minimal.html">Minimal</a></td>
|
|
243
|
+
<td>Basic equation rendering</td>
|
|
244
|
+
</tr>
|
|
245
|
+
<tr>
|
|
246
|
+
<td></td>
|
|
247
|
+
<td><a href="examples/simple-usage.html">Simple Usage</a></td>
|
|
248
|
+
<td>Interactive features</td>
|
|
249
|
+
</tr>
|
|
250
|
+
<tr>
|
|
251
|
+
<td><strong>Advanced</strong></td>
|
|
252
|
+
<td><a href="examples/expression-playground.html">Expression Playground</a></td>
|
|
253
|
+
<td>Full manipulation interface</td>
|
|
254
|
+
</tr>
|
|
255
|
+
<tr>
|
|
256
|
+
<td></td>
|
|
257
|
+
<td><a href="examples/drag-and-drop-playground.html">Drag & Drop</a></td>
|
|
258
|
+
<td>Intuitive interaction</td>
|
|
259
|
+
</tr>
|
|
260
|
+
<tr>
|
|
261
|
+
<td><strong>Educational</strong></td>
|
|
262
|
+
<td><a href="examples/worked-solution.html">Worked Solutions</a></td>
|
|
263
|
+
<td>Step-by-step solving</td>
|
|
264
|
+
</tr>
|
|
265
|
+
<tr>
|
|
266
|
+
<td></td>
|
|
267
|
+
<td><a href="examples/kids-interactive.html">Kids Interactive</a></td>
|
|
268
|
+
<td>Child-friendly interface</td>
|
|
269
|
+
</tr>
|
|
270
|
+
<tr>
|
|
271
|
+
<td><strong>Components</strong></td>
|
|
272
|
+
<td><a href="examples/equation-stack-test.html">Equation Stack</a></td>
|
|
273
|
+
<td>Stacked equations</td>
|
|
274
|
+
</tr>
|
|
275
|
+
<tr>
|
|
276
|
+
<td></td>
|
|
277
|
+
<td><a href="examples/canvas-multiple-nodes.html">Canvas Demo</a></td>
|
|
278
|
+
<td>Multi-expression layouts</td>
|
|
279
|
+
</tr>
|
|
280
|
+
</tbody></table>
|
|
281
|
+
<p><strong><a href="examples/index.html">Browse All Examples</a></strong></p>
|
|
282
|
+
<h2 id="documentation">Documentation</h2>
|
|
283
|
+
<table>
|
|
284
|
+
<thead>
|
|
285
|
+
<tr>
|
|
286
|
+
<th>Resource</th>
|
|
287
|
+
<th>Description</th>
|
|
288
|
+
</tr>
|
|
289
|
+
</thead>
|
|
290
|
+
<tbody><tr>
|
|
291
|
+
<td><strong><a href="docs/api-reference.html">API Reference</a></strong></td>
|
|
292
|
+
<td>Complete component documentation</td>
|
|
293
|
+
</tr>
|
|
294
|
+
<tr>
|
|
295
|
+
<td><strong><a href="docs/user-guide.html">User Guide</a></strong></td>
|
|
296
|
+
<td>Getting started and tutorials</td>
|
|
297
|
+
</tr>
|
|
298
|
+
</tbody></table>
|
|
299
|
+
<h2 id="architecture">Architecture</h2>
|
|
300
|
+
<pre><code>OMD Library Structure
|
|
301
|
+
├── Display Layer (omdDisplay)
|
|
302
|
+
├── Node System (Expression tree components)
|
|
303
|
+
├── UI Components (Toolbar, Step visualizer)
|
|
304
|
+
├── Core Systems (Simplification, Layout)
|
|
305
|
+
└── Utilities (Configuration, Helpers)
|
|
306
|
+
</code></pre>
|
|
307
|
+
<h2 id="dependencies">Dependencies</h2>
|
|
308
|
+
<ul>
|
|
309
|
+
<li><strong>JSVG</strong> - High-performance SVG rendering</li>
|
|
310
|
+
<li><strong>math.js</strong> - Mathematical expression parsing</li>
|
|
311
|
+
<li><strong>Modern Browser</strong> - ES6 modules, SVG support</li>
|
|
312
|
+
</ul>
|
|
313
|
+
<hr>
|
|
314
|
+
<p><strong>Ready to get started?</strong> Check out our <a href="examples/index.html">examples</a> or dive into the <a href="docs/api-reference.html">documentation</a>!</p>
|
|
315
|
+
|
|
316
|
+
</div>
|
|
317
|
+
|
|
318
|
+
<a href="#" class="back-to-top">↑ Top</a>
|
|
319
|
+
</body>
|
|
320
|
+
</html>
|
package/docs/user-guide.md
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
# OMD User Guide
|
|
2
|
-
|
|
3
|
-
This user guide is under construction. For now, please refer to the following resources:
|
|
4
|
-
|
|
5
|
-
- [API Reference](./api-reference.md)
|
|
6
|
-
- [Documentation](../DOCUMENTATION.md)
|
|
7
|
-
- [Examples](../examples/index.html)
|
|
8
|
-
|
|
9
|
-
If you are looking for something specific, please check the API docs or the main documentation file. More detailed guides and tutorials will be added soon.
|
|
File without changes
|