@@ -106,6 +106,7 @@ export const LFO = forwardRef<LFORef, LFOProps>((props, ref) => {
106106
107107 generateSineWave ( svg )
108108 generateSquareWave ( svg )
109+ generateTriangleWave ( svg )
109110 }
110111
111112 const generateSineWave = ( svg : d3 . Selection < d3 . BaseType , unknown , null , undefined > ) => {
@@ -134,10 +135,11 @@ export const LFO = forwardRef<LFORef, LFOProps>((props, ref) => {
134135 const generateSquareWave = ( svg : d3 . Selection < d3 . BaseType , unknown , null , undefined > ) => {
135136 if ( type !== 'square' || ! svg ) return
136137
137- const halfHeight = 0.5 * amplitude
138- const data = [ { x : 0 , y : 0.5 } ] . concat (
138+ const centerY = 0.5
139+ const halfHeight = centerY * amplitude
140+ const data = [ { x : 0 , y : centerY } ] . concat (
139141 d3 . range ( 0 , 4 * Math . PI * ( frequency * 10 ) , 0.01 ) . map ( ( x ) => {
140- const y = Math . floor ( x / Math . PI ) % 2 === 0 ? 0.5 + halfHeight : 0.5 - halfHeight
142+ const y = Math . floor ( x / Math . PI ) % 2 === 0 ? centerY + halfHeight : centerY - halfHeight
141143 return { x, y }
142144 } ) ,
143145 )
@@ -157,6 +159,39 @@ export const LFO = forwardRef<LFORef, LFOProps>((props, ref) => {
157159 . attr ( 'transform' , `translate(${ delay } , 0)` )
158160 }
159161
162+ const generateTriangleWave = ( svg : d3 . Selection < d3 . BaseType , unknown , null , undefined > ) => {
163+ if ( type !== 'triangle' || ! svg ) return
164+
165+ const centerY = 0.5
166+ const data = d3 . range ( 0 , 4 * Math . PI * ( frequency * 10 ) , 0.01 ) . map ( ( x ) => {
167+ // Adjust the phase so that the waveform starts in the middle of the rising segment
168+ // and ensure that the starting point is at the center of the Y-axis
169+ // By mapping the x value to the corresponding position in a cycle,
170+ // the waveform is in the middle of the rising segment when it starts
171+ const phase = ( ( x + Math . PI / 2 ) % ( 2 * Math . PI ) ) / Math . PI
172+
173+ let y
174+ if ( phase < 1 ) y = phase * amplitude
175+ else y = ( 2 - phase ) * amplitude
176+ y = y - amplitude / 2 + centerY
177+ return { x, y }
178+ } )
179+
180+ const line = d3
181+ . line < { x : number ; y : number } > ( )
182+ . x ( ( d ) => xScale . current ! ( d . x ) )
183+ . y ( ( d ) => yScale . current ! ( d . y ) )
184+
185+ svg
186+ . append ( 'path' )
187+ . datum ( data )
188+ . attr ( 'fill' , 'none' )
189+ . attr ( 'stroke' , lineColor )
190+ . attr ( 'stroke-width' , lineWidth )
191+ . attr ( 'd' , line )
192+ . attr ( 'transform' , `translate(${ delay } , 0)` )
193+ }
194+
160195 const { base, svg } = useStyle ( )
161196
162197 return (
0 commit comments