@@ -126,18 +126,11 @@ class TicketCanvas extends Base {
126126 // 1. Clear
127127 ctx . clearRect ( 0 , 0 , width , height ) ;
128128
129- // 2. Draw Vertical Neural Line (The "Spine")
130- // Positioned relative to the first node.
131- // CSS: Timeline padding-left 60px. Line at 30px. Item content starts at 60px.
132- // So line is 30px to the left of the item content.
133- // We assume nodes[0].x is the item content left edge.
134- let spineX = 38 ,
135- startY = me . startY ;
136-
137- if ( me . nodes . length > 0 ) {
138- spineX = me . nodes [ 0 ] . x - 30 ; // Shift left to center in the gutter
139- }
140-
129+ // 2. Draw Neural Connections (The "Spine")
130+ // We connect each node to the next one.
131+ // For the first segment, we can just draw straight down from the first node?
132+ // Or strictly connect nodes. Let's connect nodes.
133+
141134 // Gradient for the spine
142135 const gradient = ctx . createLinearGradient ( 0 , 0 , 0 , height ) ;
143136 gradient . addColorStop ( 0 , 'rgba(64, 196, 255, 0.1)' ) ;
@@ -147,18 +140,53 @@ class TicketCanvas extends Base {
147140 ctx . strokeStyle = gradient ;
148141 ctx . lineWidth = 2 ;
149142 ctx . beginPath ( ) ;
150- ctx . moveTo ( spineX , startY ) ;
151- ctx . lineTo ( spineX , height ) ;
143+
144+ if ( me . nodes . length > 0 ) {
145+ let first = me . nodes [ 0 ] ;
146+ ctx . moveTo ( first . x , first . y ) ;
147+
148+ for ( let i = 1 ; i < me . nodes . length ; i ++ ) {
149+ let node = me . nodes [ i ] ;
150+ ctx . lineTo ( node . x , node . y ) ;
151+ }
152+ // Extend to bottom from last node
153+ let last = me . nodes [ me . nodes . length - 1 ] ;
154+ ctx . lineTo ( last . x , height ) ;
155+ }
152156 ctx . stroke ( ) ;
153157
154158 // 3. Draw "Pulse" Effect
155- // A glowing segment moving down
159+ // A glowing segment moving down the path
160+ // To do this strictly on the path requires path following logic.
161+ // For now, let's keep the vertical pulse but align it to the node X at that Y.
162+ // Since our nodes are mostly vertical, we can interpolate X based on pulseY.
163+
156164 const pulseSpeed = 0.15 ; // px per ms
157165 const pulseY = ( now * pulseSpeed ) % height ;
158166 const pulseLength = 100 ;
159167
160- // Only draw pulse if it's within the spine range
161- if ( pulseY > startY ) {
168+ // Find which segment the pulse is in
169+ // Simple linear interpolation function
170+ const getXAtY = ( y ) => {
171+ if ( me . nodes . length < 2 ) return me . nodes [ 0 ] ?. x || 38 ;
172+
173+ // Before first node
174+ if ( y < me . nodes [ 0 ] . y ) return me . nodes [ 0 ] . x ;
175+
176+ for ( let i = 0 ; i < me . nodes . length - 1 ; i ++ ) {
177+ let curr = me . nodes [ i ] ;
178+ let next = me . nodes [ i + 1 ] ;
179+ if ( y >= curr . y && y <= next . y ) {
180+ let ratio = ( y - curr . y ) / ( next . y - curr . y ) ;
181+ return curr . x + ( next . x - curr . x ) * ratio ;
182+ }
183+ }
184+
185+ // After last node
186+ return me . nodes [ me . nodes . length - 1 ] . x ;
187+ } ;
188+
189+ if ( me . nodes . length > 0 && pulseY > me . nodes [ 0 ] . y ) {
162190 const pulseGrad = ctx . createLinearGradient ( 0 , pulseY , 0 , pulseY + pulseLength ) ;
163191 pulseGrad . addColorStop ( 0 , 'rgba(64, 196, 255, 0)' ) ;
164192 pulseGrad . addColorStop ( 0.5 , 'rgba(64, 196, 255, 1)' ) ;
@@ -167,18 +195,20 @@ class TicketCanvas extends Base {
167195 ctx . strokeStyle = pulseGrad ;
168196 ctx . lineWidth = 4 ;
169197 ctx . beginPath ( ) ;
170- ctx . moveTo ( spineX , pulseY ) ;
171- ctx . lineTo ( spineX , Math . min ( pulseY + pulseLength , height ) ) ;
198+
199+ // Draw pulse segment by segment to follow the path
200+ // This is complex for a simple effect.
201+ // Simplified: Draw a vertical line at the interpolated X.
202+ // It might look slightly detached on steep angles but fine for vertical flow.
203+ let pulseX = getXAtY ( pulseY ) ;
204+ ctx . moveTo ( pulseX , pulseY ) ;
205+ ctx . lineTo ( getXAtY ( pulseY + pulseLength ) , Math . min ( pulseY + pulseLength , height ) ) ;
172206 ctx . stroke ( ) ;
173207 }
174-
175- // Wrap around pulse (if at bottom)
176- if ( pulseY + pulseLength > height ) {
177- // Draw the remainder at top? Or just let it flow out.
178- }
179208
180209 // 4. Draw Nodes (Event Markers)
181210 me . nodes . forEach ( node => {
211+ const x = node . x ;
182212 const y = node . y ;
183213
184214 // Interaction: If pulse is near node, glow up
@@ -188,7 +218,7 @@ class TicketCanvas extends Base {
188218 const alpha = isActive ? 1 : 0.5 ;
189219
190220 ctx . beginPath ( ) ;
191- ctx . arc ( spineX , y , radius , 0 , 2 * Math . PI ) ;
221+ ctx . arc ( x , y , radius , 0 , 2 * Math . PI ) ;
192222 ctx . fillStyle = `rgba(64, 196, 255, ${ alpha } )` ;
193223 ctx . fill ( ) ;
194224
0 commit comments