zeroed-some/bashamole / eb535ed

Browse files

animation shows the mole

Authored by espadonne
SHA
eb535ed03822286620ef41c57c9beb7178778a53
Parents
da833f2
Tree
b794e8a

1 changed file

StatusFile+-
M frontend/src/components/TreeVisualizer.tsx 71 16
frontend/src/components/TreeVisualizer.tsxmodified
@@ -57,9 +57,12 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
5757
     navigation: { duration: 750, easing: d3.easeCubicInOut },
5858
     intro: {
5959
       phases: [
60
-        { duration: 1000 }, // Initial zoom
61
-        { duration: 2000, easing: d3.easeCubicInOut }, // Zoom out
62
-        { duration: 1000 }, // Pause
60
+        { duration: 1000 }, // Initial pause on root
61
+        { duration: 2000, easing: d3.easeCubicInOut }, // Zoom out to full tree
62
+        { duration: 1000 }, // Pause on full tree
63
+        { duration: 1500, easing: d3.easeCubicInOut }, // Zoom to mole
64
+        { duration: 800 }, // Brief pause on mole
65
+        { duration: 1200, easing: d3.easeCubicInOut }, // Zoom out partially
6366
         { duration: 1500, easing: d3.easeCubicInOut } // Zoom to player
6467
       ]
6568
     },
@@ -85,6 +88,7 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
8588
     scaleExtent: [0.1, 3] as [number, number],
8689
     defaultScale: 3,
8790
     fullTreeScale: 0.8,
91
+    partialTreeScale: 1.5, // For the partial zoom out after showing mole
8892
     treePadding: 200,
8993
     nudgeOffset: { x: 0.15, y: 0.2 }
9094
   };
@@ -129,6 +133,8 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
129133
     }
130134
   };
131135
 
136
+  const isAnimatingRef = useRef(false);
137
+
132138
   useEffect(() => {
133139
     if (!treeData || !svgRef.current || !containerRef.current) return;
134140
 
@@ -531,28 +537,77 @@ const TreeVisualizer: React.FC<TreeVisualizerProps> = ({
531537
       const treeCenter = { x: treeCenterX, y: treeCenterY } as d3.HierarchyPointNode<TreeNode>;
532538
       const fullTreeTransform = getZoomTransform(treeCenter, fullTreeScale);
533539
       
540
+      // Find mole location
541
+      const moleNode = treeNodes.descendants().find(d => d.data.has_mole);
542
+      const moleTransform = moleNode ? getZoomTransform(moleNode, ZOOM_CONFIG.defaultScale) : null;
543
+      
544
+      // Partial tree view (for after showing mole)
545
+      const partialTreeTransform = getZoomTransform(treeCenter, ZOOM_CONFIG.partialTreeScale);
546
+      
534547
       // Final player position with nudge offset
535548
       const playerTransform = getZoomTransform(playerNode, ZOOM_CONFIG.defaultScale, 
536549
                                               ZOOM_CONFIG.nudgeOffset.x, 
537550
                                               ZOOM_CONFIG.nudgeOffset.y);
538551
       
539
-      // Animate using zoom transitions
552
+      // Animate using zoom transitions with new sequence
540553
       const phases = ANIMATION_CONFIG.intro.phases;
541
-      svg.transition()
542
-        .duration(phases[0].duration)
543
-        .call(zoom.transform, rootTransform)
554
+      
555
+      // Build the transition chain
556
+      if (moleTransform) {
557
+        isAnimatingRef.current = true;
558
+        
559
+        // Create a single transition and chain all the calls
560
+        svg.transition()
561
+          .duration(phases[0].duration)
562
+          .call(zoom.transform, rootTransform)
563
+        .transition()
564
+          .duration(phases[1].duration)
565
+          .ease(phases[1].easing!)
566
+          .call(zoom.transform, fullTreeTransform)
567
+        .transition()
568
+          .duration(phases[2].duration)
569
+          .call(zoom.transform, fullTreeTransform)
544570
         .transition()
545
-        .duration(phases[1].duration)
546
-        .ease(phases[1].easing!)
547
-        .call(zoom.transform, fullTreeTransform)
571
+          .duration(phases[3].duration)
572
+          .ease(phases[3].easing!)
573
+          .call(zoom.transform, moleTransform)
548574
         .transition()
549
-        .duration(phases[2].duration)
550
-        .call(zoom.transform, fullTreeTransform)
575
+          .duration(phases[4].duration)
576
+          .call(zoom.transform, moleTransform)
551577
         .transition()
552
-        .duration(phases[3].duration)
553
-        .ease(phases[3].easing!)
554
-        .call(zoom.transform, playerTransform);
555
-    } else if (playerNode) {
578
+          .duration(phases[5].duration)
579
+          .ease(phases[5].easing!)
580
+          .call(zoom.transform, partialTreeTransform)
581
+        .transition()
582
+          .duration(phases[6].duration)
583
+          .ease(phases[6].easing!)
584
+          .call(zoom.transform, playerTransform)
585
+          .on('end', () => {
586
+            isAnimatingRef.current = false;
587
+          });
588
+      } else {
589
+        isAnimatingRef.current = true;
590
+        
591
+        // Shorter sequence without mole
592
+        svg.transition()
593
+          .duration(phases[0].duration)
594
+          .call(zoom.transform, rootTransform)
595
+        .transition()
596
+          .duration(phases[1].duration)
597
+          .ease(phases[1].easing!)
598
+          .call(zoom.transform, fullTreeTransform)
599
+        .transition()
600
+          .duration(phases[2].duration)
601
+          .call(zoom.transform, fullTreeTransform)
602
+        .transition()
603
+          .duration(phases[6].duration)
604
+          .ease(phases[6].easing!)
605
+          .call(zoom.transform, playerTransform)
606
+          .on('end', () => {
607
+            isAnimatingRef.current = false;
608
+          });
609
+      }
610
+    } else if (playerNode && !isAnimatingRef.current) {
556611
       // No intro: position on player with nudge offset
557612
       const playerTransform = getZoomTransform(playerNode, ZOOM_CONFIG.defaultScale,
558613
                                               ZOOM_CONFIG.nudgeOffset.x,