@teachinglab/omd 0.2.7 → 0.2.8
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/ui/toolbar.js +0 -15
- package/omd/core/omdEquationStack.js +11 -2
- package/omd/display/omdDisplay.js +75 -29
- package/omd/nodes/omdEquationNode.js +46 -6
- package/omd/step-visualizer/omdStepVisualizer.js +312 -29
- package/omd/step-visualizer/omdStepVisualizerLayout.js +122 -110
- package/omd/step-visualizer/omdStepVisualizerTextBoxes.js +46 -8
- package/omd/utils/omdStepVisualizerInteractiveSteps.js +318 -121
- package/package.json +1 -1
- 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
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { omdEquationNode } from '../nodes/omdEquationNode.js';
|
|
2
2
|
import { omdColor } from '../../src/omdColor.js';
|
|
3
3
|
import { jsvgLine, jsvgEllipse } from '@teachinglab/jsvg';
|
|
4
|
+
import { getDotRadius } from '../config/omdConfigManager.js';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Handles visual layout, positioning, and visibility management for step visualizations
|
|
@@ -18,17 +19,25 @@ export class omdStepVisualizerLayout {
|
|
|
18
19
|
* @param {number} position - The x position from the left edge where the visualizer should be positioned
|
|
19
20
|
*/
|
|
20
21
|
setFixedVisualizerPosition(position) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
// Only update if position actually changes
|
|
23
|
+
if (this.fixedVisualizerPosition !== position) {
|
|
24
|
+
this.fixedVisualizerPosition = position;
|
|
25
|
+
// Trigger a layout update if the visualizer is already initialized
|
|
26
|
+
if (this.stepVisualizer && this.stepVisualizer.stepDots.length > 0) {
|
|
27
|
+
this.updateVisualLayout(true); // Allow repositioning for position changes
|
|
28
|
+
}
|
|
25
29
|
}
|
|
26
30
|
}
|
|
27
31
|
|
|
28
32
|
/**
|
|
29
33
|
* Updates the layout of visual elements relative to the sequence
|
|
34
|
+
* @param {boolean} allowRepositioning - Whether to allow equation repositioning (default: false)
|
|
30
35
|
*/
|
|
31
|
-
updateVisualLayout() {
|
|
36
|
+
updateVisualLayout(allowRepositioning = false) {
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
32
41
|
if (this.stepVisualizer.stepDots.length === 0) return;
|
|
33
42
|
|
|
34
43
|
// Calculate the total width needed for equations (including any padding)
|
|
@@ -41,7 +50,8 @@ export class omdStepVisualizerLayout {
|
|
|
41
50
|
this.stepVisualizer.visualContainer.setPosition(visualX, 0);
|
|
42
51
|
|
|
43
52
|
// Only reposition equations if explicitly allowed (not during simple dot clicks)
|
|
44
|
-
if (this.allowEquationRepositioning) {
|
|
53
|
+
if (this.allowEquationRepositioning && allowRepositioning) {
|
|
54
|
+
|
|
45
55
|
// Calculate how much space is available for equations before the visualizer
|
|
46
56
|
const availableEquationSpace = this.fixedVisualizerPosition - this.stepVisualizer.visualSpacing;
|
|
47
57
|
|
|
@@ -49,11 +59,14 @@ export class omdStepVisualizerLayout {
|
|
|
49
59
|
let equationOffsetX = 0;
|
|
50
60
|
if (totalEquationWidth > availableEquationSpace) {
|
|
51
61
|
equationOffsetX = availableEquationSpace - totalEquationWidth;
|
|
52
|
-
|
|
62
|
+
|
|
53
63
|
}
|
|
54
64
|
|
|
55
65
|
// Apply the offset to equation positioning
|
|
56
66
|
this._adjustEquationPositions(equationOffsetX);
|
|
67
|
+
} else {
|
|
68
|
+
|
|
69
|
+
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
// Position dots based on visible equations
|
|
@@ -93,6 +106,11 @@ export class omdStepVisualizerLayout {
|
|
|
93
106
|
let containerWidth = this.stepVisualizer.dotRadius * 3;
|
|
94
107
|
let containerHeight = this.stepVisualizer.height;
|
|
95
108
|
|
|
109
|
+
// Store the original height before expansion for autoscale calculations
|
|
110
|
+
if (!this.stepVisualizer.sequenceHeight) {
|
|
111
|
+
this.stepVisualizer.sequenceHeight = containerHeight;
|
|
112
|
+
}
|
|
113
|
+
|
|
96
114
|
const textBoxes = this.stepVisualizer.textBoxManager.getStepTextBoxes();
|
|
97
115
|
if (textBoxes.length > 0) {
|
|
98
116
|
const textBoxWidth = 280;
|
|
@@ -136,7 +154,7 @@ export class omdStepVisualizerLayout {
|
|
|
136
154
|
|
|
137
155
|
// Adjust position of all steps (equations and operation display nodes)
|
|
138
156
|
sv.steps.forEach(step => {
|
|
139
|
-
if (step && step.setPosition
|
|
157
|
+
if (step && step.setPosition) {
|
|
140
158
|
const currentX = step.xpos || 0;
|
|
141
159
|
const currentY = step.ypos || 0;
|
|
142
160
|
step.setPosition(currentX + offsetX, currentY);
|
|
@@ -150,7 +168,7 @@ export class omdStepVisualizerLayout {
|
|
|
150
168
|
}
|
|
151
169
|
});
|
|
152
170
|
|
|
153
|
-
|
|
171
|
+
|
|
154
172
|
}
|
|
155
173
|
|
|
156
174
|
/**
|
|
@@ -250,12 +268,12 @@ export class omdStepVisualizerLayout {
|
|
|
250
268
|
* Updates visibility of visual elements based on equation visibility
|
|
251
269
|
*/
|
|
252
270
|
updateVisualVisibility() {
|
|
253
|
-
|
|
271
|
+
|
|
254
272
|
const sv = this.stepVisualizer;
|
|
255
273
|
|
|
256
274
|
// Update dot visibility and color first, which is the source of truth
|
|
257
275
|
const dotColor = sv.styling?.dotColor || omdColor.stepColor;
|
|
258
|
-
|
|
276
|
+
|
|
259
277
|
|
|
260
278
|
sv.stepDots.forEach((dot, index) => {
|
|
261
279
|
if (dot.equationRef && dot.equationRef.visible !== false) {
|
|
@@ -263,20 +281,20 @@ export class omdStepVisualizerLayout {
|
|
|
263
281
|
dot.setStrokeColor(dotColor);
|
|
264
282
|
dot.show();
|
|
265
283
|
dot.visible = true; // Use the dot's own visibility property
|
|
266
|
-
|
|
284
|
+
|
|
267
285
|
} else {
|
|
268
286
|
dot.hide();
|
|
269
287
|
dot.visible = false;
|
|
270
|
-
|
|
288
|
+
|
|
271
289
|
}
|
|
272
290
|
});
|
|
273
291
|
|
|
274
292
|
// Clear existing expansion dots
|
|
275
|
-
|
|
293
|
+
|
|
276
294
|
this._clearExpansionDots();
|
|
277
295
|
|
|
278
296
|
// Remove all old lines from the container and the array
|
|
279
|
-
|
|
297
|
+
|
|
280
298
|
sv.stepLines.forEach(line => {
|
|
281
299
|
// Remove the line if it is currently a child of the visualContainer
|
|
282
300
|
if (line.parent === sv.visualContainer) {
|
|
@@ -287,10 +305,10 @@ export class omdStepVisualizerLayout {
|
|
|
287
305
|
|
|
288
306
|
// Get the dots that are currently visible
|
|
289
307
|
const visibleDots = sv.stepDots.filter(dot => dot.visible);
|
|
290
|
-
|
|
308
|
+
|
|
291
309
|
|
|
292
310
|
// Re-create connecting lines only between the visible dots
|
|
293
|
-
|
|
311
|
+
|
|
294
312
|
for (let i = 0; i < visibleDots.length - 1; i++) {
|
|
295
313
|
const fromDot = visibleDots[i];
|
|
296
314
|
const toDot = visibleDots[i + 1];
|
|
@@ -298,26 +316,26 @@ export class omdStepVisualizerLayout {
|
|
|
298
316
|
const line = new jsvgLine();
|
|
299
317
|
const lineColor = sv.styling?.lineColor || omdColor.stepColor;
|
|
300
318
|
line.setStrokeColor(lineColor);
|
|
301
|
-
line.setStrokeWidth(sv.lineWidth);
|
|
319
|
+
line.setStrokeWidth(sv.styling?.lineWidth || sv.lineWidth);
|
|
302
320
|
line.fromDotIndex = sv.stepDots.indexOf(fromDot);
|
|
303
321
|
line.toDotIndex = sv.stepDots.indexOf(toDot);
|
|
304
322
|
|
|
305
323
|
sv.visualContainer.addChild(line);
|
|
306
324
|
sv.stepLines.push(line);
|
|
307
325
|
}
|
|
308
|
-
|
|
326
|
+
|
|
309
327
|
|
|
310
328
|
// After creating the lines, update their positions
|
|
311
329
|
this.updateAllLinePositions();
|
|
312
330
|
|
|
313
331
|
// Create expansion dots for dots that have hidden steps before them
|
|
314
|
-
|
|
332
|
+
|
|
315
333
|
this._createExpansionDots();
|
|
316
334
|
|
|
317
|
-
|
|
335
|
+
|
|
318
336
|
this._positionExpansionDots();
|
|
319
337
|
|
|
320
|
-
|
|
338
|
+
|
|
321
339
|
}
|
|
322
340
|
|
|
323
341
|
/**
|
|
@@ -360,34 +378,34 @@ export class omdStepVisualizerLayout {
|
|
|
360
378
|
* @private
|
|
361
379
|
*/
|
|
362
380
|
_createExpansionDots() {
|
|
363
|
-
|
|
381
|
+
|
|
364
382
|
const sv = this.stepVisualizer;
|
|
365
383
|
const allDots = sv.stepDots;
|
|
366
384
|
const visibleDots = sv.stepDots.filter(dot => dot.visible);
|
|
367
385
|
|
|
368
|
-
|
|
386
|
+
|
|
369
387
|
|
|
370
388
|
// Debug all steps and their properties
|
|
371
|
-
|
|
389
|
+
|
|
372
390
|
sv.steps.forEach((step, i) => {
|
|
373
391
|
if (step && (step instanceof omdEquationNode || step.constructor.name === 'omdEquationNode')) {
|
|
374
|
-
|
|
392
|
+
|
|
375
393
|
} else {
|
|
376
|
-
|
|
394
|
+
|
|
377
395
|
}
|
|
378
396
|
});
|
|
379
397
|
|
|
380
398
|
// Debug all dots and their properties
|
|
381
|
-
|
|
399
|
+
|
|
382
400
|
allDots.forEach((dot, i) => {
|
|
383
401
|
if (dot && dot.equationRef) {
|
|
384
|
-
|
|
402
|
+
|
|
385
403
|
} else {
|
|
386
|
-
|
|
404
|
+
|
|
387
405
|
}
|
|
388
406
|
});
|
|
389
407
|
|
|
390
|
-
|
|
408
|
+
|
|
391
409
|
|
|
392
410
|
// Check for hidden intermediate steps between consecutive visible major steps (stepMark = 0)
|
|
393
411
|
const visibleMajorSteps = [];
|
|
@@ -395,19 +413,19 @@ export class omdStepVisualizerLayout {
|
|
|
395
413
|
if (step && (step instanceof omdEquationNode || step.constructor.name === 'omdEquationNode')) {
|
|
396
414
|
if (step.stepMark === 0 && step.visible === true) {
|
|
397
415
|
visibleMajorSteps.push(stepIndex);
|
|
398
|
-
|
|
416
|
+
|
|
399
417
|
}
|
|
400
418
|
}
|
|
401
419
|
});
|
|
402
420
|
|
|
403
|
-
|
|
421
|
+
|
|
404
422
|
|
|
405
423
|
// Check between consecutive visible major steps for hidden intermediate steps
|
|
406
424
|
for (let i = 1; i < visibleMajorSteps.length; i++) {
|
|
407
425
|
const previousMajorStepIndex = visibleMajorSteps[i - 1];
|
|
408
426
|
const currentMajorStepIndex = visibleMajorSteps[i];
|
|
409
427
|
|
|
410
|
-
|
|
428
|
+
|
|
411
429
|
|
|
412
430
|
// Count hidden intermediate steps between these major steps
|
|
413
431
|
let hiddenIntermediateCount = 0;
|
|
@@ -416,15 +434,15 @@ export class omdStepVisualizerLayout {
|
|
|
416
434
|
if (step && (step instanceof omdEquationNode || step.constructor.name === 'omdEquationNode')) {
|
|
417
435
|
if (step.stepMark > 0 && step.visible === false) {
|
|
418
436
|
hiddenIntermediateCount++;
|
|
419
|
-
|
|
437
|
+
|
|
420
438
|
}
|
|
421
439
|
}
|
|
422
440
|
}
|
|
423
441
|
|
|
424
|
-
|
|
442
|
+
|
|
425
443
|
|
|
426
444
|
if (hiddenIntermediateCount > 0) {
|
|
427
|
-
|
|
445
|
+
|
|
428
446
|
// Find the dot for the current major step to position the expansion dot above it
|
|
429
447
|
const currentMajorStep = sv.steps[currentMajorStepIndex];
|
|
430
448
|
const currentDotIndex = sv.stepDots.findIndex(dot => dot.equationRef === currentMajorStep);
|
|
@@ -432,26 +450,26 @@ export class omdStepVisualizerLayout {
|
|
|
432
450
|
if (currentDotIndex >= 0) {
|
|
433
451
|
// Find the position in the visible dots array
|
|
434
452
|
const visibleDotIndex = i; // i is the position in visibleMajorSteps array
|
|
435
|
-
|
|
453
|
+
|
|
436
454
|
const expansionDot = this._createSingleExpansionDot(visibleDotIndex, previousMajorStepIndex, hiddenIntermediateCount);
|
|
437
455
|
expansionDot.majorStepIndex = currentMajorStepIndex; // Store for reference
|
|
438
456
|
this.expansionDots.push(expansionDot);
|
|
439
457
|
sv.visualContainer.addChild(expansionDot);
|
|
440
|
-
|
|
458
|
+
|
|
441
459
|
} else {
|
|
442
|
-
|
|
460
|
+
|
|
443
461
|
}
|
|
444
462
|
} else {
|
|
445
|
-
|
|
463
|
+
|
|
446
464
|
}
|
|
447
465
|
}
|
|
448
466
|
|
|
449
|
-
|
|
467
|
+
|
|
450
468
|
// Also create collapse dots for expanded sequences
|
|
451
469
|
this._createCollapseDots();
|
|
452
470
|
|
|
453
|
-
|
|
454
|
-
|
|
471
|
+
|
|
472
|
+
|
|
455
473
|
}
|
|
456
474
|
|
|
457
475
|
/**
|
|
@@ -467,7 +485,7 @@ export class omdStepVisualizerLayout {
|
|
|
467
485
|
const toEquation = sv.stepDots[toDotIndex]?.equationRef;
|
|
468
486
|
|
|
469
487
|
if (!fromEquation || !toEquation) {
|
|
470
|
-
|
|
488
|
+
|
|
471
489
|
return 0;
|
|
472
490
|
}
|
|
473
491
|
|
|
@@ -475,7 +493,7 @@ export class omdStepVisualizerLayout {
|
|
|
475
493
|
const fromStepIndex = sv.steps.indexOf(fromEquation);
|
|
476
494
|
const toStepIndex = sv.steps.indexOf(toEquation);
|
|
477
495
|
|
|
478
|
-
|
|
496
|
+
|
|
479
497
|
|
|
480
498
|
// Count intermediate steps between these two major steps
|
|
481
499
|
for (let i = fromStepIndex + 1; i < toStepIndex; i++) {
|
|
@@ -483,13 +501,13 @@ export class omdStepVisualizerLayout {
|
|
|
483
501
|
if (step && (step instanceof omdEquationNode || step.constructor.name === 'omdEquationNode')) {
|
|
484
502
|
// Count intermediate steps (stepMark > 0) that are currently hidden
|
|
485
503
|
if (step.stepMark !== undefined && step.stepMark > 0 && step.visible === false) {
|
|
486
|
-
|
|
504
|
+
|
|
487
505
|
count++;
|
|
488
506
|
}
|
|
489
507
|
}
|
|
490
508
|
}
|
|
491
509
|
|
|
492
|
-
|
|
510
|
+
|
|
493
511
|
return count;
|
|
494
512
|
}
|
|
495
513
|
|
|
@@ -506,21 +524,22 @@ export class omdStepVisualizerLayout {
|
|
|
506
524
|
* @private
|
|
507
525
|
*/
|
|
508
526
|
_createSingleExpansionDot(currentStepIndex, previousStepIndex, hiddenCount) {
|
|
509
|
-
|
|
527
|
+
|
|
510
528
|
const sv = this.stepVisualizer;
|
|
511
|
-
const
|
|
529
|
+
const baseRadius = sv.styling?.dotRadius || getDotRadius(0);
|
|
530
|
+
const expansionRadius = Math.max(3, baseRadius * (sv.styling?.expansionDotScale || 0.4));
|
|
531
|
+
|
|
512
532
|
|
|
513
|
-
console.debug(`Creating expansion dot with radius: ${expansionRadius}`);
|
|
514
533
|
|
|
515
534
|
const expansionDot = new jsvgEllipse();
|
|
516
535
|
expansionDot.setWidthAndHeight(expansionRadius * 2, expansionRadius * 2);
|
|
517
536
|
|
|
518
|
-
// Use same color as regular dots
|
|
537
|
+
// Use same color as regular dots from styling
|
|
519
538
|
const dotColor = sv.styling?.dotColor || omdColor.stepColor;
|
|
520
|
-
|
|
539
|
+
|
|
521
540
|
expansionDot.setFillColor(dotColor);
|
|
522
541
|
expansionDot.setStrokeColor(dotColor);
|
|
523
|
-
expansionDot.setStrokeWidth(1);
|
|
542
|
+
expansionDot.setStrokeWidth(sv.styling?.dotStrokeWidth || 1);
|
|
524
543
|
|
|
525
544
|
// Store metadata
|
|
526
545
|
expansionDot.isExpansionDot = true;
|
|
@@ -529,19 +548,12 @@ export class omdStepVisualizerLayout {
|
|
|
529
548
|
expansionDot.hiddenCount = hiddenCount;
|
|
530
549
|
expansionDot.radius = expansionRadius;
|
|
531
550
|
|
|
532
|
-
console.debug('Expansion dot metadata:', {
|
|
533
|
-
isExpansionDot: expansionDot.isExpansionDot,
|
|
534
|
-
currentStepIndex: expansionDot.currentStepIndex,
|
|
535
|
-
previousStepIndex: expansionDot.previousStepIndex,
|
|
536
|
-
hiddenCount: expansionDot.hiddenCount,
|
|
537
|
-
radius: expansionDot.radius
|
|
538
|
-
});
|
|
539
551
|
|
|
540
552
|
// Make it clickable
|
|
541
553
|
expansionDot.svgObject.style.cursor = "pointer";
|
|
542
554
|
expansionDot.svgObject.onclick = (event) => {
|
|
543
555
|
try {
|
|
544
|
-
|
|
556
|
+
|
|
545
557
|
this._handleExpansionDotClick(expansionDot);
|
|
546
558
|
event.stopPropagation();
|
|
547
559
|
} catch (error) {
|
|
@@ -549,8 +561,8 @@ export class omdStepVisualizerLayout {
|
|
|
549
561
|
}
|
|
550
562
|
};
|
|
551
563
|
|
|
552
|
-
|
|
553
|
-
|
|
564
|
+
|
|
565
|
+
|
|
554
566
|
|
|
555
567
|
return expansionDot;
|
|
556
568
|
}
|
|
@@ -560,23 +572,23 @@ export class omdStepVisualizerLayout {
|
|
|
560
572
|
* @private
|
|
561
573
|
*/
|
|
562
574
|
_positionExpansionDots() {
|
|
563
|
-
|
|
575
|
+
|
|
564
576
|
const sv = this.stepVisualizer;
|
|
565
577
|
|
|
566
|
-
|
|
578
|
+
|
|
567
579
|
|
|
568
580
|
this.expansionDots.forEach((expansionDot, index) => {
|
|
569
|
-
|
|
581
|
+
|
|
570
582
|
let targetDot;
|
|
571
583
|
|
|
572
584
|
if (expansionDot.isCollapseDot) {
|
|
573
|
-
|
|
585
|
+
|
|
574
586
|
// For collapse dots, use the currentStepIndex which points to the dot index
|
|
575
587
|
const dotIndex = expansionDot.currentStepIndex;
|
|
576
588
|
targetDot = sv.stepDots[dotIndex];
|
|
577
|
-
|
|
589
|
+
|
|
578
590
|
} else {
|
|
579
|
-
|
|
591
|
+
|
|
580
592
|
// For expansion dots, we need to find the actual visible dot that corresponds to the major step
|
|
581
593
|
const majorStepIndex = expansionDot.majorStepIndex;
|
|
582
594
|
const majorStep = sv.steps[majorStepIndex];
|
|
@@ -585,9 +597,9 @@ export class omdStepVisualizerLayout {
|
|
|
585
597
|
// Find the dot that corresponds to this major step
|
|
586
598
|
const dotIndex = sv.stepDots.findIndex(dot => dot.equationRef === majorStep);
|
|
587
599
|
targetDot = sv.stepDots[dotIndex];
|
|
588
|
-
|
|
600
|
+
|
|
589
601
|
} else {
|
|
590
|
-
|
|
602
|
+
|
|
591
603
|
}
|
|
592
604
|
}
|
|
593
605
|
|
|
@@ -595,15 +607,15 @@ export class omdStepVisualizerLayout {
|
|
|
595
607
|
const offsetY = -(expansionDot.radius * 2 + 8); // Position above main dot
|
|
596
608
|
const newX = targetDot.xpos;
|
|
597
609
|
const newY = targetDot.ypos + offsetY;
|
|
598
|
-
|
|
610
|
+
|
|
599
611
|
expansionDot.setPosition(newX, newY);
|
|
600
|
-
|
|
612
|
+
|
|
601
613
|
} else {
|
|
602
|
-
|
|
614
|
+
|
|
603
615
|
}
|
|
604
616
|
});
|
|
605
617
|
|
|
606
|
-
|
|
618
|
+
|
|
607
619
|
}
|
|
608
620
|
|
|
609
621
|
/**
|
|
@@ -611,11 +623,11 @@ export class omdStepVisualizerLayout {
|
|
|
611
623
|
* @private
|
|
612
624
|
*/
|
|
613
625
|
_createCollapseDots() {
|
|
614
|
-
|
|
626
|
+
|
|
615
627
|
const sv = this.stepVisualizer;
|
|
616
628
|
const allDots = sv.stepDots;
|
|
617
629
|
|
|
618
|
-
|
|
630
|
+
|
|
619
631
|
|
|
620
632
|
// Group visible intermediate steps by their consecutive sequences
|
|
621
633
|
const intermediateGroups = [];
|
|
@@ -624,21 +636,21 @@ export class omdStepVisualizerLayout {
|
|
|
624
636
|
allDots.forEach((dot, index) => {
|
|
625
637
|
if (dot && dot.visible && dot.equationRef) {
|
|
626
638
|
const stepMark = dot.equationRef.stepMark;
|
|
627
|
-
|
|
639
|
+
|
|
628
640
|
|
|
629
641
|
if (stepMark !== undefined && stepMark > 0) {
|
|
630
642
|
currentGroup.push(index);
|
|
631
|
-
|
|
643
|
+
|
|
632
644
|
} else if (currentGroup.length > 0) {
|
|
633
645
|
// We hit a major step, so end the current group
|
|
634
646
|
intermediateGroups.push([...currentGroup]);
|
|
635
|
-
|
|
647
|
+
|
|
636
648
|
currentGroup = [];
|
|
637
649
|
}
|
|
638
650
|
} else if (currentGroup.length > 0) {
|
|
639
651
|
// We hit a non-visible dot, so end the current group
|
|
640
652
|
intermediateGroups.push([...currentGroup]);
|
|
641
|
-
|
|
653
|
+
|
|
642
654
|
currentGroup = [];
|
|
643
655
|
}
|
|
644
656
|
});
|
|
@@ -646,15 +658,15 @@ export class omdStepVisualizerLayout {
|
|
|
646
658
|
// Don't forget the last group if it exists
|
|
647
659
|
if (currentGroup.length > 0) {
|
|
648
660
|
intermediateGroups.push([...currentGroup]);
|
|
649
|
-
|
|
661
|
+
|
|
650
662
|
}
|
|
651
663
|
|
|
652
|
-
|
|
664
|
+
|
|
653
665
|
|
|
654
666
|
// Create a collapse dot for each group
|
|
655
667
|
intermediateGroups.forEach((group, groupIndex) => {
|
|
656
668
|
if (group.length > 0) {
|
|
657
|
-
|
|
669
|
+
|
|
658
670
|
|
|
659
671
|
// Find the major step that comes after the last intermediate step in this group
|
|
660
672
|
const lastIntermediateIndex = group[group.length - 1];
|
|
@@ -662,7 +674,7 @@ export class omdStepVisualizerLayout {
|
|
|
662
674
|
const lastIntermediateStep = lastIntermediateDot.equationRef;
|
|
663
675
|
const lastIntermediateStepIndex = sv.steps.indexOf(lastIntermediateStep);
|
|
664
676
|
|
|
665
|
-
|
|
677
|
+
|
|
666
678
|
|
|
667
679
|
// Find the next major step (stepMark = 0) after the intermediate steps
|
|
668
680
|
let majorStepAfterIndex = -1;
|
|
@@ -671,7 +683,7 @@ export class omdStepVisualizerLayout {
|
|
|
671
683
|
if (step && (step instanceof omdEquationNode || step.constructor.name === 'omdEquationNode')) {
|
|
672
684
|
if (step.stepMark === 0 && step.visible === true) {
|
|
673
685
|
majorStepAfterIndex = i;
|
|
674
|
-
|
|
686
|
+
|
|
675
687
|
break;
|
|
676
688
|
}
|
|
677
689
|
}
|
|
@@ -683,7 +695,7 @@ export class omdStepVisualizerLayout {
|
|
|
683
695
|
const majorDotIndex = sv.stepDots.findIndex(dot => dot.equationRef === majorStepAfter);
|
|
684
696
|
|
|
685
697
|
if (majorDotIndex >= 0) {
|
|
686
|
-
|
|
698
|
+
|
|
687
699
|
|
|
688
700
|
const collapseDot = this._createSingleExpansionDot(majorDotIndex, -1, group.length);
|
|
689
701
|
collapseDot.isCollapseDot = true;
|
|
@@ -691,17 +703,17 @@ export class omdStepVisualizerLayout {
|
|
|
691
703
|
collapseDot.groupIndex = groupIndex; // Store group reference
|
|
692
704
|
this.expansionDots.push(collapseDot);
|
|
693
705
|
sv.visualContainer.addChild(collapseDot);
|
|
694
|
-
|
|
706
|
+
|
|
695
707
|
} else {
|
|
696
|
-
|
|
708
|
+
|
|
697
709
|
}
|
|
698
710
|
} else {
|
|
699
|
-
|
|
711
|
+
|
|
700
712
|
}
|
|
701
713
|
}
|
|
702
714
|
});
|
|
703
715
|
|
|
704
|
-
|
|
716
|
+
|
|
705
717
|
}
|
|
706
718
|
|
|
707
719
|
/**
|
|
@@ -713,45 +725,45 @@ export class omdStepVisualizerLayout {
|
|
|
713
725
|
|
|
714
726
|
if (expansionDot.isCollapseDot) {
|
|
715
727
|
// Handle collapse dot click - hide only the specific group of intermediate steps
|
|
716
|
-
|
|
728
|
+
|
|
717
729
|
|
|
718
730
|
// Hide only the intermediate steps in this specific group
|
|
719
731
|
const intermediateSteps = expansionDot.intermediateSteps || [];
|
|
720
|
-
|
|
732
|
+
|
|
721
733
|
|
|
722
734
|
intermediateSteps.forEach(dotIndex => {
|
|
723
735
|
const dot = sv.stepDots[dotIndex];
|
|
724
736
|
if (dot && dot.equationRef) {
|
|
725
|
-
|
|
737
|
+
|
|
726
738
|
this._hideStep(dot.equationRef);
|
|
727
739
|
|
|
728
740
|
// Also hide the corresponding dot
|
|
729
741
|
dot.hide();
|
|
730
742
|
dot.visible = false;
|
|
731
|
-
|
|
743
|
+
|
|
732
744
|
}
|
|
733
745
|
});
|
|
734
746
|
|
|
735
747
|
// Remove any lines that connect to the hidden dots
|
|
736
|
-
|
|
748
|
+
|
|
737
749
|
this._removeLinesToHiddenDots();
|
|
738
750
|
|
|
739
|
-
|
|
751
|
+
|
|
740
752
|
} else {
|
|
741
753
|
// Handle expansion dot click - show steps between the major steps
|
|
742
754
|
const { majorStepIndex, previousStepIndex } = expansionDot;
|
|
743
755
|
|
|
744
|
-
|
|
756
|
+
|
|
745
757
|
|
|
746
758
|
// Remove this expansion dot immediately since we're expanding
|
|
747
|
-
|
|
759
|
+
|
|
748
760
|
if (expansionDot.parentNode === sv.visualContainer) {
|
|
749
761
|
sv.visualContainer.removeChild(expansionDot);
|
|
750
762
|
}
|
|
751
763
|
const dotIndex = this.expansionDots.indexOf(expansionDot);
|
|
752
764
|
if (dotIndex >= 0) {
|
|
753
765
|
this.expansionDots.splice(dotIndex, 1);
|
|
754
|
-
|
|
766
|
+
|
|
755
767
|
}
|
|
756
768
|
|
|
757
769
|
// Show all intermediate steps between the previous and current major steps
|
|
@@ -759,7 +771,7 @@ export class omdStepVisualizerLayout {
|
|
|
759
771
|
const step = sv.steps[i];
|
|
760
772
|
if (step && (step instanceof omdEquationNode || step.constructor.name === 'omdEquationNode')) {
|
|
761
773
|
if (step.stepMark > 0) {
|
|
762
|
-
|
|
774
|
+
|
|
763
775
|
this._showStep(step);
|
|
764
776
|
|
|
765
777
|
// Also show the corresponding dot
|
|
@@ -768,13 +780,13 @@ export class omdStepVisualizerLayout {
|
|
|
768
780
|
const stepDot = sv.stepDots[stepDotIndex];
|
|
769
781
|
stepDot.show();
|
|
770
782
|
stepDot.visible = true;
|
|
771
|
-
|
|
783
|
+
|
|
772
784
|
}
|
|
773
785
|
}
|
|
774
786
|
}
|
|
775
787
|
}
|
|
776
788
|
|
|
777
|
-
|
|
789
|
+
|
|
778
790
|
}
|
|
779
791
|
|
|
780
792
|
// Force a complete refresh of the visualizer to clean up artifacts and rebuild lines
|
|
@@ -843,7 +855,7 @@ export class omdStepVisualizerLayout {
|
|
|
843
855
|
*/
|
|
844
856
|
_removeLinesToHiddenDots() {
|
|
845
857
|
const sv = this.stepVisualizer;
|
|
846
|
-
|
|
858
|
+
|
|
847
859
|
|
|
848
860
|
// Get lines that connect to hidden dots
|
|
849
861
|
const linesToRemove = [];
|
|
@@ -852,25 +864,25 @@ export class omdStepVisualizerLayout {
|
|
|
852
864
|
const toDot = sv.stepDots[line.toDotIndex];
|
|
853
865
|
|
|
854
866
|
if ((fromDot && !fromDot.visible) || (toDot && !toDot.visible)) {
|
|
855
|
-
|
|
867
|
+
|
|
856
868
|
linesToRemove.push(line);
|
|
857
869
|
}
|
|
858
870
|
});
|
|
859
871
|
|
|
860
872
|
// Remove the problematic lines
|
|
861
|
-
|
|
873
|
+
|
|
862
874
|
linesToRemove.forEach(line => {
|
|
863
875
|
if (line.parent === sv.visualContainer) {
|
|
864
876
|
sv.visualContainer.removeChild(line);
|
|
865
|
-
|
|
877
|
+
|
|
866
878
|
}
|
|
867
879
|
const lineIndex = sv.stepLines.indexOf(line);
|
|
868
880
|
if (lineIndex >= 0) {
|
|
869
881
|
sv.stepLines.splice(lineIndex, 1);
|
|
870
|
-
|
|
882
|
+
|
|
871
883
|
}
|
|
872
884
|
});
|
|
873
885
|
|
|
874
|
-
|
|
886
|
+
|
|
875
887
|
}
|
|
876
888
|
}
|