@teachinglab/omd 0.2.7 → 0.2.9
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/canvas/drawing/stroke.js +1 -1
- package/canvas/ui/toolbar.js +0 -15
- package/omd/core/omdEquationStack.js +11 -2
- package/omd/display/omdDisplay.js +149 -31
- package/omd/nodes/omdEquationNode.js +46 -6
- package/omd/step-visualizer/omdStepVisualizer.js +311 -29
- package/omd/step-visualizer/omdStepVisualizerLayout.js +122 -110
- package/omd/step-visualizer/omdStepVisualizerTextBoxes.js +46 -8
- package/omd/utils/omdNodeOverlay.js +1 -1
- package/omd/utils/omdPopup.js +1 -1
- package/omd/utils/omdStepVisualizerInteractiveSteps.js +318 -121
- package/omd/utils/omdTranscriptionService.js +10 -6
- package/package.json +7 -4
- package/src/omdBalanceHanger.js +31 -1
- package/src/omdColor.js +1 -0
- package/src/omdCoordinatePlane.js +53 -3
- package/src/omdMetaExpression.js +8 -4
- package/src/omdTable.js +182 -52
package/canvas/drawing/stroke.js
CHANGED
package/canvas/ui/toolbar.js
CHANGED
|
@@ -60,21 +60,6 @@ export class Toolbar {
|
|
|
60
60
|
|
|
61
61
|
// Add to main SVG so it is rendered
|
|
62
62
|
this.canvas.svg.appendChild(this.toolbarGroup.svgObject);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// Check if the SVG is actually in the DOM
|
|
66
|
-
setTimeout(() => {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// Check the actual SVG content
|
|
70
|
-
console.log('Toolbar SVG innerHTML:', this.toolbarGroup.svgObject.innerHTML);
|
|
71
|
-
console.log('Background SVG object:', this.background.svgObject);
|
|
72
|
-
console.log('Background SVG innerHTML:', this.background.svgObject.outerHTML);
|
|
73
|
-
|
|
74
|
-
// Check if the background is visible
|
|
75
|
-
console.log('Background fill color:', this.background.svgObject.getAttribute('fill'));
|
|
76
|
-
console.log('Background width/height:', this.background.svgObject.getAttribute('width'), this.background.svgObject.getAttribute('height'));
|
|
77
|
-
}, 100);
|
|
78
63
|
}
|
|
79
64
|
|
|
80
65
|
/**
|
|
@@ -34,7 +34,9 @@ export class omdEquationStack extends jsvgGroup {
|
|
|
34
34
|
|
|
35
35
|
// The sequence is the core. If a visualizer is needed, that's our sequence.
|
|
36
36
|
if (options.stepVisualizer) {
|
|
37
|
-
|
|
37
|
+
// Pass through step visualizer styling options
|
|
38
|
+
const stepVisualizerStyling = this.stylingOptions?.stepVisualizer || {};
|
|
39
|
+
this.sequence = new omdStepVisualizer(steps, stepVisualizerStyling);
|
|
38
40
|
} else {
|
|
39
41
|
this.sequence = new omdEquationSequenceNode(steps);
|
|
40
42
|
}
|
|
@@ -44,6 +46,13 @@ export class omdEquationStack extends jsvgGroup {
|
|
|
44
46
|
this.sequence.setDefaultEquationBackground(this.stylingOptions.equationBackground);
|
|
45
47
|
}
|
|
46
48
|
|
|
49
|
+
// Apply step visualizer background styling if provided
|
|
50
|
+
if (options.stepVisualizer && this.stylingOptions?.stepVisualizerBackground) {
|
|
51
|
+
if (typeof this.sequence.setBackgroundStyle === 'function') {
|
|
52
|
+
this.sequence.setBackgroundStyle(this.stylingOptions.stepVisualizerBackground);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
47
56
|
// If a toolbar is needed, create it.
|
|
48
57
|
if (this.toolbarOptions?.enabled) {
|
|
49
58
|
// Default undo: call global hook if provided
|
|
@@ -508,7 +517,7 @@ export class omdEquationStack extends jsvgGroup {
|
|
|
508
517
|
}
|
|
509
518
|
if (seq.layoutManager) {
|
|
510
519
|
try {
|
|
511
|
-
seq.layoutManager.updateVisualLayout();
|
|
520
|
+
seq.layoutManager.updateVisualLayout(true); // Allow repositioning for equation stack changes
|
|
512
521
|
seq.layoutManager.updateVisualVisibility();
|
|
513
522
|
seq.layoutManager.updateAllLinePositions();
|
|
514
523
|
} catch (_) {}
|
|
@@ -20,6 +20,7 @@ export class omdDisplay {
|
|
|
20
20
|
autoScale: true, // Automatically scale content to fit container
|
|
21
21
|
maxScale: 1, // Do not upscale beyond 1 by default
|
|
22
22
|
edgePadding: 16, // Horizontal padding from edges when scaling
|
|
23
|
+
autoCloseStepVisualizer: true, // Close active step visualizer text boxes before autoscale to avoid shrink
|
|
23
24
|
...options
|
|
24
25
|
};
|
|
25
26
|
|
|
@@ -27,6 +28,13 @@ export class omdDisplay {
|
|
|
27
28
|
this.svg = new jsvgContainer();
|
|
28
29
|
this.node = null;
|
|
29
30
|
|
|
31
|
+
// Internal guards to prevent recursive resize induced growth
|
|
32
|
+
this._suppressResizeObserver = false; // When true, _handleResize is a no-op
|
|
33
|
+
this._lastViewbox = null; // Cache last applied viewBox string
|
|
34
|
+
this._lastContentExtents = null; // Cache last measured content extents to detect real growth
|
|
35
|
+
this._viewboxLocked = false; // When true, suppress micro growth adjustments
|
|
36
|
+
this._viewboxLockThreshold = 8; // Require at least 8px growth once locked
|
|
37
|
+
|
|
30
38
|
// Set up the SVG
|
|
31
39
|
this._setupSVG();
|
|
32
40
|
}
|
|
@@ -64,8 +72,13 @@ export class omdDisplay {
|
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
_handleResize() {
|
|
75
|
+
if (this._suppressResizeObserver) return; // Prevent re-entrant resize loops
|
|
67
76
|
const width = this.container.offsetWidth;
|
|
68
77
|
const height = this.container.offsetHeight;
|
|
78
|
+
// Skip if size unchanged; avoids loops where internal changes trigger observer without real container delta
|
|
79
|
+
if (this._lastContainerWidth === width && this._lastContainerHeight === height) return;
|
|
80
|
+
this._lastContainerWidth = width;
|
|
81
|
+
this._lastContainerHeight = height;
|
|
69
82
|
this.svg.setViewbox(width, height);
|
|
70
83
|
|
|
71
84
|
if (this.options.centerContent && this.node) {
|
|
@@ -131,8 +144,50 @@ export class omdDisplay {
|
|
|
131
144
|
const desiredW = Math.max(curW, desiredRight - desiredX);
|
|
132
145
|
const desiredH = Math.max(curH, desiredBottom - desiredY);
|
|
133
146
|
|
|
134
|
-
|
|
135
|
-
|
|
147
|
+
// Guard: If the desired size change is negligible (< 0.5px), skip.
|
|
148
|
+
const widthDelta = Math.abs(desiredW - curW);
|
|
149
|
+
const heightDelta = Math.abs(desiredH - curH);
|
|
150
|
+
|
|
151
|
+
// Safety cap to avoid runaway expansion due to logic errors.
|
|
152
|
+
const MAX_DIM = 10000; // arbitrary large but finite limit
|
|
153
|
+
if (desiredW > MAX_DIM || desiredH > MAX_DIM) {
|
|
154
|
+
console.warn('omdDisplay: viewBox growth capped to prevent runaway expansion', desiredW, desiredH);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (widthDelta < 0.5 && heightDelta < 0.5) return;
|
|
159
|
+
|
|
160
|
+
// Detect repeated growth with identical content extents (suggests feedback loop)
|
|
161
|
+
const curExtSignature = `${minX},${minY},${maxX},${maxY}`;
|
|
162
|
+
if (this._lastContentExtents === curExtSignature && heightDelta > 0 && desiredH > curH) {
|
|
163
|
+
return; // content unchanged, skip
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// If locked, only allow substantial growth
|
|
167
|
+
if (this._viewboxLocked) {
|
|
168
|
+
const growW = desiredW - curW;
|
|
169
|
+
const growH = desiredH - curH;
|
|
170
|
+
if (growW < this._viewboxLockThreshold && growH < this._viewboxLockThreshold) {
|
|
171
|
+
return; // ignore micro growth attempts
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const newViewBox = `${desiredX} ${desiredY} ${desiredW} ${desiredH}`;
|
|
176
|
+
if (this._lastViewbox === newViewBox) return;
|
|
177
|
+
|
|
178
|
+
this._suppressResizeObserver = true;
|
|
179
|
+
try {
|
|
180
|
+
this.svg.svgObject.setAttribute('viewBox', newViewBox);
|
|
181
|
+
} finally {
|
|
182
|
+
// Allow ResizeObserver events after microtask; use timeout to defer
|
|
183
|
+
setTimeout(() => { this._suppressResizeObserver = false; }, 0);
|
|
184
|
+
}
|
|
185
|
+
this._lastViewbox = newViewBox;
|
|
186
|
+
this._lastContentExtents = curExtSignature;
|
|
187
|
+
|
|
188
|
+
// Lock if the growth applied was small; prevents future tiny increments
|
|
189
|
+
if (heightDelta < 2 && widthDelta < 2 && !this._viewboxLocked) {
|
|
190
|
+
this._viewboxLocked = true;
|
|
136
191
|
}
|
|
137
192
|
}
|
|
138
193
|
|
|
@@ -396,9 +451,28 @@ export class omdDisplay {
|
|
|
396
451
|
|
|
397
452
|
centerNode() {
|
|
398
453
|
if (!this.node) return;
|
|
454
|
+
if (!this._centerCallCount) this._centerCallCount = 0;
|
|
455
|
+
this._centerCallCount++;
|
|
456
|
+
if (this._centerCallCount > 500) {
|
|
457
|
+
console.warn('omdDisplay: excessive centerNode calls detected; halting further centering to prevent loop');
|
|
458
|
+
return;
|
|
459
|
+
}
|
|
399
460
|
const containerWidth = this.container.offsetWidth || 0;
|
|
400
461
|
const containerHeight = this.container.offsetHeight || 0;
|
|
401
462
|
|
|
463
|
+
// Early auto-close of step visualizer UI before measuring dimensions to avoid transient height inflation
|
|
464
|
+
if (this.options.autoCloseStepVisualizer && this.node) {
|
|
465
|
+
try {
|
|
466
|
+
if (typeof this.node.forceCloseAll === 'function') {
|
|
467
|
+
this.node.forceCloseAll();
|
|
468
|
+
} else if (typeof this.node.closeAllTextBoxes === 'function') {
|
|
469
|
+
this.node.closeAllTextBoxes();
|
|
470
|
+
} else if (typeof this.node.closeActiveDot === 'function') {
|
|
471
|
+
this.node.closeActiveDot();
|
|
472
|
+
}
|
|
473
|
+
} catch (e) { /* no-op */ }
|
|
474
|
+
}
|
|
475
|
+
|
|
402
476
|
// Determine actual content size (prefer sequence/current step when available)
|
|
403
477
|
let contentWidth = this.node.width || 0;
|
|
404
478
|
let contentHeight = this.node.height || 0;
|
|
@@ -406,14 +480,18 @@ export class omdDisplay {
|
|
|
406
480
|
const seq = this.node.getSequence();
|
|
407
481
|
if (seq) {
|
|
408
482
|
if (seq.width && seq.height) {
|
|
409
|
-
|
|
410
|
-
|
|
483
|
+
// For step visualizers, use sequenceWidth/Height instead of total dimensions to exclude visualizer elements from autoscale
|
|
484
|
+
contentWidth = seq.sequenceWidth || seq.width;
|
|
485
|
+
contentHeight = seq.sequenceHeight || seq.height;
|
|
411
486
|
}
|
|
412
487
|
if (seq.getCurrentStep) {
|
|
413
488
|
const step = seq.getCurrentStep();
|
|
414
489
|
if (step && step.width && step.height) {
|
|
415
|
-
|
|
416
|
-
|
|
490
|
+
// For step visualizers, prioritize sequenceWidth/Height for dimension calculations
|
|
491
|
+
const stepWidth = seq.sequenceWidth || step.width;
|
|
492
|
+
const stepHeight = seq.sequenceHeight || step.height;
|
|
493
|
+
contentWidth = Math.max(contentWidth, stepWidth);
|
|
494
|
+
contentHeight = Math.max(contentHeight, stepHeight);
|
|
417
495
|
}
|
|
418
496
|
}
|
|
419
497
|
}
|
|
@@ -422,22 +500,45 @@ export class omdDisplay {
|
|
|
422
500
|
// Compute scale to keep within bounds
|
|
423
501
|
let scale = 1;
|
|
424
502
|
if (this.options.autoScale && contentWidth > 0 && contentHeight > 0) {
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
503
|
+
// Optionally close any open step visualizer textbox to prevent transient height expansion
|
|
504
|
+
if (this.options.autoCloseStepVisualizer && this.node) {
|
|
505
|
+
try {
|
|
506
|
+
if (typeof this.node.closeActiveDot === 'function') {
|
|
507
|
+
this.node.closeActiveDot();
|
|
508
|
+
} else if (typeof this.node.closeAllTextBoxes === 'function') {
|
|
509
|
+
this.node.closeAllTextBoxes();
|
|
510
|
+
}
|
|
511
|
+
} catch (e) { /* no-op */ }
|
|
512
|
+
}
|
|
513
|
+
// Detect step visualizer directly on node (getSequence returns underlying sequence only)
|
|
514
|
+
let hasStepVisualizer = false;
|
|
515
|
+
if (this.node) {
|
|
516
|
+
const ctorName = this.node.constructor?.name;
|
|
517
|
+
hasStepVisualizer = (ctorName === 'omdStepVisualizer') || this.node.type === 'omdStepVisualizer' || (typeof omdStepVisualizer !== 'undefined' && this.node instanceof omdStepVisualizer);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (hasStepVisualizer) {
|
|
521
|
+
// Preserve existing scale if already set on node; otherwise lock to 1.
|
|
522
|
+
const existingScale = (this.node && typeof this.node.scale === 'number') ? this.node.scale : undefined;
|
|
523
|
+
scale = (existingScale && existingScale > 0) ? existingScale : 1;
|
|
524
|
+
} else {
|
|
525
|
+
const hPad = this.options.edgePadding || 0;
|
|
526
|
+
const vPadTop = this.options.topMargin || 0;
|
|
527
|
+
const vPadBottom = this.options.bottomMargin || 0;
|
|
528
|
+
// Reserve extra space for overlay toolbar if needed
|
|
529
|
+
let reserveBottom = vPadBottom;
|
|
530
|
+
if (this.node && typeof this.node.isToolbarOverlay === 'function' && this.node.isToolbarOverlay()) {
|
|
531
|
+
const tH = (typeof this.node.getToolbarVisualHeight === 'function') ? this.node.getToolbarVisualHeight() : 0;
|
|
532
|
+
reserveBottom += (tH + (this.node.getOverlayPadding ? this.node.getOverlayPadding() : 16));
|
|
533
|
+
}
|
|
534
|
+
const availW = Math.max(0, containerWidth - hPad * 2);
|
|
535
|
+
const availH = Math.max(0, containerHeight - (vPadTop + reserveBottom));
|
|
536
|
+
const sx = availW > 0 ? (availW / contentWidth) : 1;
|
|
537
|
+
const sy = availH > 0 ? (availH / contentHeight) : 1;
|
|
538
|
+
const maxScale = (typeof this.options.maxScale === 'number') ? this.options.maxScale : 1;
|
|
539
|
+
scale = Math.min(sx, sy, maxScale);
|
|
540
|
+
if (!isFinite(scale) || scale <= 0) scale = 1;
|
|
433
541
|
}
|
|
434
|
-
const availW = Math.max(0, containerWidth - hPad * 2);
|
|
435
|
-
const availH = Math.max(0, containerHeight - (vPadTop + reserveBottom));
|
|
436
|
-
const sx = availW > 0 ? (availW / contentWidth) : 1;
|
|
437
|
-
const sy = availH > 0 ? (availH / contentHeight) : 1;
|
|
438
|
-
const maxScale = (typeof this.options.maxScale === 'number') ? this.options.maxScale : 1;
|
|
439
|
-
scale = Math.min(sx, sy, maxScale);
|
|
440
|
-
if (!isFinite(scale) || scale <= 0) scale = 1;
|
|
441
542
|
}
|
|
442
543
|
|
|
443
544
|
// Apply scale
|
|
@@ -451,19 +552,27 @@ export class omdDisplay {
|
|
|
451
552
|
const screenCenterX = containerWidth / 2;
|
|
452
553
|
x = screenCenterX - (this.node.alignPointX * scale);
|
|
453
554
|
} else {
|
|
454
|
-
const scaledWidth =
|
|
555
|
+
const scaledWidth = contentWidth * scale;
|
|
455
556
|
x = (containerWidth - scaledWidth) / 2;
|
|
456
557
|
}
|
|
457
558
|
|
|
458
559
|
// Decide whether positioning would move content outside container. If so,
|
|
459
560
|
// prefer expanding the SVG viewBox instead of moving nodes.
|
|
460
|
-
const scaledWidthFinal =
|
|
461
|
-
const scaledHeightFinal =
|
|
561
|
+
const scaledWidthFinal = contentWidth * scale;
|
|
562
|
+
const scaledHeightFinal = contentHeight * scale;
|
|
462
563
|
const totalNeededH = scaledHeightFinal + (this.options.topMargin || 0) + (this.options.bottomMargin || 0);
|
|
463
564
|
|
|
464
565
|
const willOverflowHoriz = scaledWidthFinal > containerWidth;
|
|
465
566
|
const willOverflowVert = totalNeededH > containerHeight;
|
|
466
567
|
|
|
568
|
+
// Avoid looping if content dimension signature hasn't changed
|
|
569
|
+
const contentSig = `${contentWidth}x${contentHeight}x${scale}`;
|
|
570
|
+
if (this._lastCenterSignature === contentSig && !willOverflowHoriz && !willOverflowVert) {
|
|
571
|
+
// Only update position; skip expensive ensureViewboxFits
|
|
572
|
+
if (this.node.setPosition) this.node.setPosition(x, this.options.topMargin);
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
|
|
467
576
|
if (willOverflowHoriz || willOverflowVert) {
|
|
468
577
|
// Set scale but do NOT reposition node (preserve its absolute positions).
|
|
469
578
|
if (this.node.setScale) this.node.setScale(scale);
|
|
@@ -499,6 +608,8 @@ export class omdDisplay {
|
|
|
499
608
|
}
|
|
500
609
|
if (this.options.debugExtents) this._drawDebugOverlays();
|
|
501
610
|
}
|
|
611
|
+
|
|
612
|
+
this._lastCenterSignature = contentSig;
|
|
502
613
|
}
|
|
503
614
|
|
|
504
615
|
fitToContent() {
|
|
@@ -517,15 +628,17 @@ export class omdDisplay {
|
|
|
517
628
|
if (this.node.getSequence) {
|
|
518
629
|
const sequence = this.node.getSequence();
|
|
519
630
|
if (sequence && sequence.width && sequence.height) {
|
|
520
|
-
sequenceWidth
|
|
521
|
-
|
|
631
|
+
// For step visualizers, use sequenceWidth/Height instead of total dimensions to exclude visualizer elements from autoscale
|
|
632
|
+
sequenceWidth = sequence.sequenceWidth || sequence.width;
|
|
633
|
+
sequenceHeight = sequence.sequenceHeight || sequence.height;
|
|
522
634
|
|
|
523
635
|
// Check current step dimensions too
|
|
524
636
|
if (sequence.getCurrentStep) {
|
|
525
637
|
const currentStep = sequence.getCurrentStep();
|
|
526
638
|
if (currentStep && currentStep.width && currentStep.height) {
|
|
527
|
-
|
|
528
|
-
|
|
639
|
+
// For step visualizers, prioritize sequenceWidth/Height for dimension calculations
|
|
640
|
+
stepWidth = sequence.sequenceWidth || currentStep.width;
|
|
641
|
+
stepHeight = sequence.sequenceHeight || currentStep.height;
|
|
529
642
|
}
|
|
530
643
|
}
|
|
531
644
|
|
|
@@ -624,10 +737,7 @@ export class omdDisplay {
|
|
|
624
737
|
|
|
625
738
|
// Apply any stored font settings
|
|
626
739
|
if (this.options.fontFamily) {
|
|
627
|
-
// Small delay to ensure SVG elements are fully rendered
|
|
628
|
-
setTimeout(() => {
|
|
629
740
|
this.setFont(this.options.fontFamily, this.options.fontWeight || '400');
|
|
630
|
-
}, 10);
|
|
631
741
|
}
|
|
632
742
|
|
|
633
743
|
// Only use fitToContent for tight sizing when explicitly requested
|
|
@@ -834,4 +944,12 @@ export class omdDisplay {
|
|
|
834
944
|
node.positionToolbarOverlay(containerWidth, containerHeight, padding);
|
|
835
945
|
}
|
|
836
946
|
}
|
|
947
|
+
|
|
948
|
+
/**
|
|
949
|
+
* Public API: returns the currently rendered root node (could be a step visualizer, sequence, or plain node)
|
|
950
|
+
* @returns {object|null}
|
|
951
|
+
*/
|
|
952
|
+
getCurrentNode() {
|
|
953
|
+
return this.node;
|
|
954
|
+
}
|
|
837
955
|
}
|
|
@@ -1005,7 +1005,7 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1005
1005
|
case 'table':
|
|
1006
1006
|
return this._renderToTable(mergedOptions);
|
|
1007
1007
|
case 'hanger':
|
|
1008
|
-
return this._renderToHanger();
|
|
1008
|
+
return this._renderToHanger(mergedOptions);
|
|
1009
1009
|
case 'tileequation': {
|
|
1010
1010
|
const leftExpr = this.getLeft().toString();
|
|
1011
1011
|
const rightExpr = this.getRight().toString();
|
|
@@ -1089,6 +1089,11 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1089
1089
|
tickInterval: (options.tickInterval !== undefined) ? options.tickInterval : 1,
|
|
1090
1090
|
forceAllTickLabels: (options.forceAllTickLabels !== undefined) ? options.forceAllTickLabels : true,
|
|
1091
1091
|
showTickLabels: (options.showTickLabels !== undefined) ? options.showTickLabels : true,
|
|
1092
|
+
// Background customization options
|
|
1093
|
+
backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
|
|
1094
|
+
backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
|
|
1095
|
+
backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
|
|
1096
|
+
showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
|
|
1092
1097
|
graphEquations,
|
|
1093
1098
|
lineSegments: [],
|
|
1094
1099
|
dotValues: [],
|
|
@@ -1113,7 +1118,17 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1113
1118
|
equation: `y = ${expr}`,
|
|
1114
1119
|
xMin: options.xMin,
|
|
1115
1120
|
xMax: options.xMax,
|
|
1116
|
-
stepSize: options.stepSize
|
|
1121
|
+
stepSize: options.stepSize,
|
|
1122
|
+
// Background customization options
|
|
1123
|
+
backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
|
|
1124
|
+
backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
|
|
1125
|
+
backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
|
|
1126
|
+
showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
|
|
1127
|
+
// Alternating row color options
|
|
1128
|
+
alternatingRowColors: (options.alternatingRowColors !== undefined) ? options.alternatingRowColors : undefined,
|
|
1129
|
+
evenRowColor: (options.evenRowColor !== undefined) ? options.evenRowColor : undefined,
|
|
1130
|
+
oddRowColor: (options.oddRowColor !== undefined) ? options.oddRowColor : undefined,
|
|
1131
|
+
alternatingRowOpacity: (options.alternatingRowOpacity !== undefined) ? options.alternatingRowOpacity : undefined
|
|
1117
1132
|
};
|
|
1118
1133
|
} else if (options.side === 'right') {
|
|
1119
1134
|
const expr = this._normalizeExpressionString(this.getRight().toString());
|
|
@@ -1124,7 +1139,17 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1124
1139
|
equation: `y = ${expr}`,
|
|
1125
1140
|
xMin: options.xMin,
|
|
1126
1141
|
xMax: options.xMax,
|
|
1127
|
-
stepSize: options.stepSize
|
|
1142
|
+
stepSize: options.stepSize,
|
|
1143
|
+
// Background customization options
|
|
1144
|
+
backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
|
|
1145
|
+
backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
|
|
1146
|
+
backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
|
|
1147
|
+
showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
|
|
1148
|
+
// Alternating row color options
|
|
1149
|
+
alternatingRowColors: (options.alternatingRowColors !== undefined) ? options.alternatingRowColors : undefined,
|
|
1150
|
+
evenRowColor: (options.evenRowColor !== undefined) ? options.evenRowColor : undefined,
|
|
1151
|
+
oddRowColor: (options.oddRowColor !== undefined) ? options.oddRowColor : undefined,
|
|
1152
|
+
alternatingRowOpacity: (options.alternatingRowOpacity !== undefined) ? options.alternatingRowOpacity : undefined
|
|
1128
1153
|
};
|
|
1129
1154
|
}
|
|
1130
1155
|
|
|
@@ -1155,7 +1180,17 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1155
1180
|
omdType: "table",
|
|
1156
1181
|
title: `Equation Table: ${this.toString()}`,
|
|
1157
1182
|
headers,
|
|
1158
|
-
data
|
|
1183
|
+
data,
|
|
1184
|
+
// Background customization options
|
|
1185
|
+
backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
|
|
1186
|
+
backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
|
|
1187
|
+
backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
|
|
1188
|
+
showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined,
|
|
1189
|
+
// Alternating row color options
|
|
1190
|
+
alternatingRowColors: (options.alternatingRowColors !== undefined) ? options.alternatingRowColors : undefined,
|
|
1191
|
+
evenRowColor: (options.evenRowColor !== undefined) ? options.evenRowColor : undefined,
|
|
1192
|
+
oddRowColor: (options.oddRowColor !== undefined) ? options.oddRowColor : undefined,
|
|
1193
|
+
alternatingRowOpacity: (options.alternatingRowOpacity !== undefined) ? options.alternatingRowOpacity : undefined
|
|
1159
1194
|
};
|
|
1160
1195
|
}
|
|
1161
1196
|
|
|
@@ -1184,7 +1219,7 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1184
1219
|
* @returns {Object} JSON configuration for omdBalanceHanger
|
|
1185
1220
|
* @private
|
|
1186
1221
|
*/
|
|
1187
|
-
_renderToHanger() {
|
|
1222
|
+
_renderToHanger(options = {}) {
|
|
1188
1223
|
// Convert equation sides to hanger representation
|
|
1189
1224
|
const leftValues = this._convertToHangerValues(this.getLeft());
|
|
1190
1225
|
const rightValues = this._convertToHangerValues(this.getRight());
|
|
@@ -1193,7 +1228,12 @@ _propagateBackgroundStyle(style, visited = new Set()) {
|
|
|
1193
1228
|
omdType: "balanceHanger",
|
|
1194
1229
|
leftValues: leftValues,
|
|
1195
1230
|
rightValues: rightValues,
|
|
1196
|
-
tilt: "none" // Equations should be balanced by definition
|
|
1231
|
+
tilt: "none", // Equations should be balanced by definition
|
|
1232
|
+
// Background customization options
|
|
1233
|
+
backgroundColor: (options.backgroundColor !== undefined) ? options.backgroundColor : undefined,
|
|
1234
|
+
backgroundCornerRadius: (options.backgroundCornerRadius !== undefined) ? options.backgroundCornerRadius : undefined,
|
|
1235
|
+
backgroundOpacity: (options.backgroundOpacity !== undefined) ? options.backgroundOpacity : undefined,
|
|
1236
|
+
showBackground: (options.showBackground !== undefined) ? options.showBackground : undefined
|
|
1197
1237
|
};
|
|
1198
1238
|
}
|
|
1199
1239
|
|