@teachinglab/omd 0.1.9 → 0.2.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/omd/display/omdDisplay.js +69 -37
- package/package.json +1 -1
|
@@ -22,25 +22,25 @@ export class omdDisplay {
|
|
|
22
22
|
edgePadding: 16, // Horizontal padding from edges when scaling
|
|
23
23
|
...options
|
|
24
24
|
};
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
// Create SVG container
|
|
27
27
|
this.svg = new jsvgContainer();
|
|
28
28
|
this.node = null;
|
|
29
|
-
|
|
29
|
+
|
|
30
30
|
// Set up the SVG
|
|
31
31
|
this._setupSVG();
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
_setupSVG() {
|
|
35
35
|
const width = this.container.offsetWidth || 800;
|
|
36
36
|
const height = this.container.offsetHeight || 600;
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
this.svg.setViewbox(width, height);
|
|
39
39
|
this.svg.svgObject.style.verticalAlign = "middle";
|
|
40
40
|
// Enable internal scrolling via native SVG scrolling if content overflows
|
|
41
41
|
this.svg.svgObject.style.overflow = 'hidden';
|
|
42
42
|
this.container.appendChild(this.svg.svgObject);
|
|
43
|
-
|
|
43
|
+
|
|
44
44
|
// Handle resize
|
|
45
45
|
if (window.ResizeObserver) {
|
|
46
46
|
this.resizeObserver = new ResizeObserver(() => {
|
|
@@ -49,12 +49,12 @@ export class omdDisplay {
|
|
|
49
49
|
this.resizeObserver.observe(this.container);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
|
|
53
53
|
_handleResize() {
|
|
54
54
|
const width = this.container.offsetWidth;
|
|
55
55
|
const height = this.container.offsetHeight;
|
|
56
56
|
this.svg.setViewbox(width, height);
|
|
57
|
-
|
|
57
|
+
|
|
58
58
|
if (this.options.centerContent && this.node) {
|
|
59
59
|
this.centerNode();
|
|
60
60
|
}
|
|
@@ -62,7 +62,7 @@ export class omdDisplay {
|
|
|
62
62
|
// Reposition overlay toolbar (if any) on resize
|
|
63
63
|
this._repositionOverlayToolbar();
|
|
64
64
|
}
|
|
65
|
-
|
|
65
|
+
|
|
66
66
|
centerNode() {
|
|
67
67
|
if (!this.node) return;
|
|
68
68
|
const containerWidth = this.container.offsetWidth || 0;
|
|
@@ -140,26 +140,26 @@ export class omdDisplay {
|
|
|
140
140
|
this.container.style.overflow = 'hidden';
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
fitToContent() {
|
|
145
145
|
if (!this.node) {
|
|
146
146
|
return;
|
|
147
147
|
}
|
|
148
|
-
|
|
148
|
+
|
|
149
149
|
// Try to get actual rendered dimensions
|
|
150
150
|
let actualWidth = 0;
|
|
151
151
|
let actualHeight = 0;
|
|
152
|
-
|
|
152
|
+
|
|
153
153
|
// Get both sequence and current step dimensions
|
|
154
154
|
let sequenceWidth = 0, sequenceHeight = 0;
|
|
155
155
|
let stepWidth = 0, stepHeight = 0;
|
|
156
|
-
|
|
156
|
+
|
|
157
157
|
if (this.node.getSequence) {
|
|
158
158
|
const sequence = this.node.getSequence();
|
|
159
159
|
if (sequence && sequence.width && sequence.height) {
|
|
160
160
|
sequenceWidth = sequence.width;
|
|
161
161
|
sequenceHeight = sequence.height;
|
|
162
|
-
|
|
162
|
+
|
|
163
163
|
// Check current step dimensions too
|
|
164
164
|
if (sequence.getCurrentStep) {
|
|
165
165
|
const currentStep = sequence.getCurrentStep();
|
|
@@ -168,39 +168,39 @@ export class omdDisplay {
|
|
|
168
168
|
stepHeight = currentStep.height;
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
|
-
|
|
171
|
+
|
|
172
172
|
// Use the larger of sequence or step dimensions
|
|
173
173
|
actualWidth = Math.max(sequenceWidth, stepWidth);
|
|
174
174
|
actualHeight = Math.max(sequenceHeight, stepHeight);
|
|
175
175
|
}
|
|
176
176
|
}
|
|
177
|
-
|
|
177
|
+
|
|
178
178
|
// Fallback to node dimensions only if sequence/step dimensions aren't available
|
|
179
179
|
if ((actualWidth === 0 || actualHeight === 0) && this.node.width && this.node.height) {
|
|
180
180
|
actualWidth = this.node.width;
|
|
181
181
|
actualHeight = this.node.height;
|
|
182
182
|
}
|
|
183
|
-
|
|
183
|
+
|
|
184
184
|
// Fallback dimensions
|
|
185
185
|
if (actualWidth === 0 || actualHeight === 0) {
|
|
186
186
|
actualWidth = 200;
|
|
187
187
|
actualHeight = 60;
|
|
188
188
|
}
|
|
189
|
-
|
|
189
|
+
|
|
190
190
|
const padding = 10; // More comfortable padding to match user expectation
|
|
191
191
|
const newWidth = actualWidth + (padding * 2);
|
|
192
192
|
const newHeight = actualHeight + (padding * 2);
|
|
193
|
-
|
|
194
|
-
|
|
193
|
+
|
|
194
|
+
|
|
195
195
|
// Position the content at the minimal padding offset FIRST
|
|
196
196
|
if (this.node && this.node.setPosition) {
|
|
197
197
|
this.node.setPosition(padding, padding);
|
|
198
198
|
}
|
|
199
|
-
|
|
199
|
+
|
|
200
200
|
// Update SVG dimensions with viewBox starting from 0,0 since we repositioned content
|
|
201
201
|
this.svg.setViewbox(newWidth, newHeight);
|
|
202
202
|
this.svg.setWidthAndHeight(newWidth, newHeight);
|
|
203
|
-
|
|
203
|
+
|
|
204
204
|
// Update container
|
|
205
205
|
this.container.style.width = `${newWidth}px`;
|
|
206
206
|
this.container.style.height = `${newHeight}px`;
|
|
@@ -216,7 +216,7 @@ export class omdDisplay {
|
|
|
216
216
|
if (this.node) {
|
|
217
217
|
this.svg.removeChild(this.node);
|
|
218
218
|
}
|
|
219
|
-
|
|
219
|
+
|
|
220
220
|
// Create node from expression
|
|
221
221
|
if (typeof expression === 'string') {
|
|
222
222
|
if (expression.includes(';')) {
|
|
@@ -241,7 +241,7 @@ export class omdDisplay {
|
|
|
241
241
|
// Assume it's already a node
|
|
242
242
|
this.node = expression;
|
|
243
243
|
}
|
|
244
|
-
|
|
244
|
+
|
|
245
245
|
// Initialize and render
|
|
246
246
|
const sequence = this.node.getSequence ? this.node.getSequence() : null;
|
|
247
247
|
if (sequence) {
|
|
@@ -250,7 +250,7 @@ export class omdDisplay {
|
|
|
250
250
|
sequence.updateStepsVisibility(step => (step.stepMark ?? 0) === sequence.getFilterLevel());
|
|
251
251
|
}
|
|
252
252
|
this.svg.addChild(this.node);
|
|
253
|
-
|
|
253
|
+
|
|
254
254
|
// Apply any stored font settings
|
|
255
255
|
if (this.options.fontFamily) {
|
|
256
256
|
// Small delay to ensure SVG elements are fully rendered
|
|
@@ -258,7 +258,7 @@ export class omdDisplay {
|
|
|
258
258
|
this.setFont(this.options.fontFamily, this.options.fontWeight || '400');
|
|
259
259
|
}, 10);
|
|
260
260
|
}
|
|
261
|
-
|
|
261
|
+
|
|
262
262
|
// Only use fitToContent for tight sizing when explicitly requested
|
|
263
263
|
if (this.options.fitToContent) {
|
|
264
264
|
this.fitToContent();
|
|
@@ -267,7 +267,7 @@ export class omdDisplay {
|
|
|
267
267
|
}
|
|
268
268
|
// Ensure overlay toolbar is positioned initially
|
|
269
269
|
this._repositionOverlayToolbar();
|
|
270
|
-
|
|
270
|
+
|
|
271
271
|
// Provide a default global refresh function if not present
|
|
272
272
|
if (typeof window !== 'undefined' && !window.refreshDisplayAndFilters) {
|
|
273
273
|
window.refreshDisplayAndFilters = () => {
|
|
@@ -293,10 +293,42 @@ export class omdDisplay {
|
|
|
293
293
|
}
|
|
294
294
|
};
|
|
295
295
|
}
|
|
296
|
-
|
|
296
|
+
|
|
297
297
|
return this.node;
|
|
298
298
|
}
|
|
299
|
-
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Add a jsvg child to the internal SVG container and optionally
|
|
302
|
+
* trigger layout/centering.
|
|
303
|
+
* @param {object} child - A jsvg node to add
|
|
304
|
+
*/
|
|
305
|
+
addChild(child) {
|
|
306
|
+
this.svg.addChild(child);
|
|
307
|
+
|
|
308
|
+
if (this.options.centerContent) this.centerNode();
|
|
309
|
+
|
|
310
|
+
return child;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Remove a child previously added to the internal SVG container.
|
|
315
|
+
* @param {object} child
|
|
316
|
+
*/
|
|
317
|
+
removeChild(child) {
|
|
318
|
+
if (!this.svg) return;
|
|
319
|
+
try {
|
|
320
|
+
if (typeof this.svg.removeChild === 'function') {
|
|
321
|
+
this.svg.removeChild(child);
|
|
322
|
+
} else if (child && child.svgObject && this.svg.svgObject && this.svg.svgObject.contains(child.svgObject)) {
|
|
323
|
+
this.svg.svgObject.removeChild(child.svgObject);
|
|
324
|
+
}
|
|
325
|
+
} catch (e) {
|
|
326
|
+
// no-op
|
|
327
|
+
}
|
|
328
|
+
// If the removed child was the main node, clear reference
|
|
329
|
+
if (this.node === child) this.node = null;
|
|
330
|
+
}
|
|
331
|
+
|
|
300
332
|
/**
|
|
301
333
|
* Updates the display with a new node
|
|
302
334
|
* @param {omdNode} newNode - The new node to display
|
|
@@ -305,19 +337,19 @@ export class omdDisplay {
|
|
|
305
337
|
if (this.node) {
|
|
306
338
|
this.svg.removeChild(this.node);
|
|
307
339
|
}
|
|
308
|
-
|
|
340
|
+
|
|
309
341
|
this.node = newNode;
|
|
310
342
|
this.node.setFontSize(this.options.fontSize);
|
|
311
343
|
this.node.initialize();
|
|
312
344
|
this.svg.addChild(this.node);
|
|
313
|
-
|
|
345
|
+
|
|
314
346
|
if (this.options.centerContent) {
|
|
315
347
|
this.centerNode();
|
|
316
348
|
}
|
|
317
349
|
// Ensure overlay toolbar is positioned on updates
|
|
318
350
|
this._repositionOverlayToolbar();
|
|
319
351
|
}
|
|
320
|
-
|
|
352
|
+
|
|
321
353
|
/**
|
|
322
354
|
* Gets the current node
|
|
323
355
|
* @returns {omdNode|null} The current node
|
|
@@ -345,7 +377,7 @@ export class omdDisplay {
|
|
|
345
377
|
node.positionToolbarOverlay(containerWidth, containerHeight, 16);
|
|
346
378
|
}
|
|
347
379
|
}
|
|
348
|
-
|
|
380
|
+
|
|
349
381
|
/**
|
|
350
382
|
* Sets the font size
|
|
351
383
|
* @param {number} size - The font size
|
|
@@ -367,7 +399,7 @@ export class omdDisplay {
|
|
|
367
399
|
}
|
|
368
400
|
}
|
|
369
401
|
}
|
|
370
|
-
|
|
402
|
+
|
|
371
403
|
/**
|
|
372
404
|
* Sets the font family for all elements in the display
|
|
373
405
|
* @param {string} fontFamily - CSS font-family string (e.g., '"Shantell Sans", cursive')
|
|
@@ -383,16 +415,16 @@ export class omdDisplay {
|
|
|
383
415
|
// Recursively apply to all children
|
|
384
416
|
Array.from(element.children || []).forEach(applyFont);
|
|
385
417
|
};
|
|
386
|
-
|
|
418
|
+
|
|
387
419
|
// Apply font to the entire SVG
|
|
388
420
|
applyFont(this.svg.svgObject);
|
|
389
|
-
|
|
421
|
+
|
|
390
422
|
// Store font settings for future use
|
|
391
423
|
this.options.fontFamily = fontFamily;
|
|
392
424
|
this.options.fontWeight = fontWeight;
|
|
393
425
|
}
|
|
394
426
|
}
|
|
395
|
-
|
|
427
|
+
|
|
396
428
|
/**
|
|
397
429
|
* Clears the display
|
|
398
430
|
*/
|
|
@@ -402,7 +434,7 @@ export class omdDisplay {
|
|
|
402
434
|
this.node = null;
|
|
403
435
|
}
|
|
404
436
|
}
|
|
405
|
-
|
|
437
|
+
|
|
406
438
|
/**
|
|
407
439
|
* Destroys the renderer and cleans up resources
|
|
408
440
|
*/
|