@teachinglab/omd 0.7.33 → 0.7.34
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/omd/display/omdDisplay.js +34 -12
- package/package.json +1 -1
- package/src/omdCoordinatePlane.js +30 -4
|
@@ -24,6 +24,8 @@ export class omdDisplay {
|
|
|
24
24
|
centerContent: true,
|
|
25
25
|
topMargin: 40,
|
|
26
26
|
bottomMargin: 16,
|
|
27
|
+
observeResize: true,
|
|
28
|
+
expandViewboxToFitContent: true,
|
|
27
29
|
fitToContent: true, // Fit to content size by default
|
|
28
30
|
autoScale: false, // Don't auto-scale by default
|
|
29
31
|
maxScale: 1, // Do not upscale beyond 1 by default
|
|
@@ -76,7 +78,7 @@ export class omdDisplay {
|
|
|
76
78
|
}
|
|
77
79
|
|
|
78
80
|
// Handle resize
|
|
79
|
-
if (window.ResizeObserver) {
|
|
81
|
+
if (this.options.observeResize && window.ResizeObserver) {
|
|
80
82
|
this.resizeObserver = new ResizeObserver(() => {
|
|
81
83
|
this._handleResize();
|
|
82
84
|
});
|
|
@@ -103,6 +105,13 @@ export class omdDisplay {
|
|
|
103
105
|
if (this.options.debugExtents) this._drawDebugOverlays();
|
|
104
106
|
}
|
|
105
107
|
|
|
108
|
+
_syncViewboxToContainer(width = this.container.offsetWidth || 0, height = this.container.offsetHeight || 0) {
|
|
109
|
+
if (!width || !height) return;
|
|
110
|
+
this.svg.setViewbox(width, height);
|
|
111
|
+
this.svg.setWidthAndHeight(width, height);
|
|
112
|
+
this._lastViewbox = `0 0 ${width} ${height}`;
|
|
113
|
+
}
|
|
114
|
+
|
|
106
115
|
/**
|
|
107
116
|
* Ensure the internal SVG viewBox is at least as large as the provided content dimensions.
|
|
108
117
|
* This prevents clipping when content is larger than the current viewBox.
|
|
@@ -573,6 +582,11 @@ export class omdDisplay {
|
|
|
573
582
|
// prefer expanding the SVG viewBox instead of moving nodes.
|
|
574
583
|
const scaledWidthFinal = contentWidth * scale;
|
|
575
584
|
const scaledHeightFinal = contentHeight * scale;
|
|
585
|
+
const availableHeight = Math.max(
|
|
586
|
+
0,
|
|
587
|
+
containerHeight - (this.options.topMargin || 0) - (this.options.bottomMargin || 0)
|
|
588
|
+
);
|
|
589
|
+
const y = (this.options.topMargin || 0) + Math.max(0, (availableHeight - scaledHeightFinal) / 2);
|
|
576
590
|
const totalNeededH = scaledHeightFinal + (this.options.topMargin || 0) + (this.options.bottomMargin || 0);
|
|
577
591
|
|
|
578
592
|
const willOverflowHoriz = scaledWidthFinal > containerWidth;
|
|
@@ -582,15 +596,18 @@ export class omdDisplay {
|
|
|
582
596
|
const contentSig = `${contentWidth}x${contentHeight}x${scale}`;
|
|
583
597
|
if (this._lastCenterSignature === contentSig && !willOverflowHoriz && !willOverflowVert) {
|
|
584
598
|
// Only update position; skip expensive ensureViewboxFits
|
|
585
|
-
if (this.node.setPosition) this.node.setPosition(x,
|
|
599
|
+
if (this.node.setPosition) this.node.setPosition(x, y);
|
|
586
600
|
return;
|
|
587
601
|
}
|
|
588
602
|
|
|
589
603
|
if (willOverflowHoriz || willOverflowVert) {
|
|
590
604
|
// Set scale but do NOT reposition node (preserve its absolute positions).
|
|
591
605
|
if (this.node.setScale) this.node.setScale(scale);
|
|
592
|
-
|
|
593
|
-
|
|
606
|
+
if (this.options.expandViewboxToFitContent !== false) {
|
|
607
|
+
this._ensureViewboxFits(contentWidth, contentHeight);
|
|
608
|
+
} else {
|
|
609
|
+
this._syncViewboxToContainer(containerWidth, containerHeight);
|
|
610
|
+
}
|
|
594
611
|
// Reposition overlay toolbar in case viewBox/container changed
|
|
595
612
|
this._repositionOverlayToolbar();
|
|
596
613
|
|
|
@@ -603,14 +620,16 @@ export class omdDisplay {
|
|
|
603
620
|
}
|
|
604
621
|
if (this.options.debugExtents) this._drawDebugOverlays();
|
|
605
622
|
} else {
|
|
606
|
-
|
|
607
|
-
this.node.setPosition(x, this.options.topMargin);
|
|
623
|
+
this.node.setPosition(x, y);
|
|
608
624
|
|
|
609
625
|
// Reposition overlay toolbar (if any)
|
|
610
626
|
this._repositionOverlayToolbar();
|
|
611
627
|
|
|
612
|
-
|
|
613
|
-
|
|
628
|
+
if (this.options.expandViewboxToFitContent !== false) {
|
|
629
|
+
this._ensureViewboxFits(contentWidth, contentHeight);
|
|
630
|
+
} else {
|
|
631
|
+
this._syncViewboxToContainer(containerWidth, containerHeight);
|
|
632
|
+
}
|
|
614
633
|
|
|
615
634
|
if (totalNeededH > containerHeight) {
|
|
616
635
|
// Let the host scroll vertically; keep horizontal overflow hidden to avoid layout shift
|
|
@@ -822,10 +841,13 @@ export class omdDisplay {
|
|
|
822
841
|
// Ensure overlay toolbar is positioned initially
|
|
823
842
|
this._repositionOverlayToolbar();
|
|
824
843
|
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
844
|
+
if (this.options.expandViewboxToFitContent !== false) {
|
|
845
|
+
const cw = (this.node && this.node.width) ? this.node.width : 0;
|
|
846
|
+
const ch = (this.node && this.node.height) ? this.node.height : 0;
|
|
847
|
+
this._ensureViewboxFits(cw, ch);
|
|
848
|
+
} else {
|
|
849
|
+
this._syncViewboxToContainer();
|
|
850
|
+
}
|
|
829
851
|
|
|
830
852
|
if (this.options.debugExtents) this._drawDebugOverlays();
|
|
831
853
|
else this._clearDebugOverlays();
|
package/package.json
CHANGED
|
@@ -55,6 +55,10 @@ export class omdCoordinatePlane extends jsvgGroup {
|
|
|
55
55
|
this.variables = [];
|
|
56
56
|
this.basePaddingBottom = 30;
|
|
57
57
|
this.interactivePaddingBottom = 0;
|
|
58
|
+
this.customPaddingTop = null;
|
|
59
|
+
this.customPaddingRight = null;
|
|
60
|
+
this.customPaddingBottom = null;
|
|
61
|
+
this.customPaddingLeft = null;
|
|
58
62
|
this.renderedFunctionEntries = [];
|
|
59
63
|
this.sliderControlRows = [];
|
|
60
64
|
|
|
@@ -87,6 +91,23 @@ export class omdCoordinatePlane extends jsvgGroup {
|
|
|
87
91
|
this.forceAllTickLabels = (data.forceAllTickLabels !== undefined) ? data.forceAllTickLabels : this.forceAllTickLabels;
|
|
88
92
|
this.showTickLabels = (data.showTickLabels !== undefined) ? data.showTickLabels : this.showTickLabels;
|
|
89
93
|
|
|
94
|
+
if (typeof data.graphPadding === "number") {
|
|
95
|
+
this.customPaddingTop = data.graphPadding;
|
|
96
|
+
this.customPaddingRight = data.graphPadding;
|
|
97
|
+
this.customPaddingBottom = data.graphPadding;
|
|
98
|
+
this.customPaddingLeft = data.graphPadding;
|
|
99
|
+
} else if (data.graphPadding && typeof data.graphPadding === "object") {
|
|
100
|
+
if (typeof data.graphPadding.top === "number") this.customPaddingTop = data.graphPadding.top;
|
|
101
|
+
if (typeof data.graphPadding.right === "number") this.customPaddingRight = data.graphPadding.right;
|
|
102
|
+
if (typeof data.graphPadding.bottom === "number") this.customPaddingBottom = data.graphPadding.bottom;
|
|
103
|
+
if (typeof data.graphPadding.left === "number") this.customPaddingLeft = data.graphPadding.left;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (typeof data.paddingTop === "number") this.customPaddingTop = data.paddingTop;
|
|
107
|
+
if (typeof data.paddingRight === "number") this.customPaddingRight = data.paddingRight;
|
|
108
|
+
if (typeof data.paddingBottom === "number") this.customPaddingBottom = data.paddingBottom;
|
|
109
|
+
if (typeof data.paddingLeft === "number") this.customPaddingLeft = data.paddingLeft;
|
|
110
|
+
|
|
90
111
|
// Load background customization properties
|
|
91
112
|
this.backgroundColor = data.backgroundColor || this.backgroundColor;
|
|
92
113
|
this.backgroundCornerRadius = (data.backgroundCornerRadius !== undefined) ? data.backgroundCornerRadius : this.backgroundCornerRadius;
|
|
@@ -295,14 +316,19 @@ export class omdCoordinatePlane extends jsvgGroup {
|
|
|
295
316
|
// ===== Helper functions =====
|
|
296
317
|
|
|
297
318
|
calculatePadding() {
|
|
298
|
-
|
|
299
|
-
|
|
319
|
+
const defaultPaddingLeft = this.yLabel ? 50 : 30;
|
|
320
|
+
const defaultPaddingBottom = this.xLabel ? 50 : 30;
|
|
321
|
+
const defaultPaddingTop = 25;
|
|
322
|
+
const defaultPaddingRight = 25;
|
|
323
|
+
|
|
324
|
+
this.paddingLeft = typeof this.customPaddingLeft === "number" ? this.customPaddingLeft : defaultPaddingLeft;
|
|
325
|
+
this.basePaddingBottom = typeof this.customPaddingBottom === "number" ? this.customPaddingBottom : defaultPaddingBottom;
|
|
300
326
|
this.interactivePaddingBottom = this.shouldShowInteractiveControls()
|
|
301
327
|
? this.getInteractiveControlHeight()
|
|
302
328
|
: 0;
|
|
303
329
|
this.paddingBottom = this.basePaddingBottom + this.interactivePaddingBottom;
|
|
304
|
-
this.paddingTop =
|
|
305
|
-
this.paddingRight =
|
|
330
|
+
this.paddingTop = typeof this.customPaddingTop === "number" ? this.customPaddingTop : defaultPaddingTop;
|
|
331
|
+
this.paddingRight = typeof this.customPaddingRight === "number" ? this.customPaddingRight : defaultPaddingRight;
|
|
306
332
|
}
|
|
307
333
|
|
|
308
334
|
computeAxisPos(isXAxis, value) {
|