Skip to content

Commit 088a4f6

Browse files
committed
feat(LFO): implement square wave
1 parent 877c9fb commit 088a4f6

2 files changed

Lines changed: 50 additions & 8 deletions

File tree

  • example/src/components/visualizaion
  • packages/components/visualization/LFO

example/src/components/visualizaion/EchoLFO.tsx

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,27 @@
11
import React from 'react'
2-
import { LFO, Knob } from '@echo-ui'
2+
import { LFO, Knob, Button, LFOProps } from '@echo-ui'
33

44
export const EchoLFO = () => {
5+
const [type, setType] = React.useState<LFOProps['type']>('sine')
56
const [frequency, setFrequency] = React.useState(0)
67
const [speed, setSpeed] = React.useState(0)
78
const [delay, setDelay] = React.useState(0)
89

910
return (
10-
<section className="h-32 w-2/3 mb-20">
11-
<LFO speed={speed} frequency={frequency} delay={delay} />
11+
<section className="h-32 w-2/3 mb-32">
12+
<Button.Group size="sm" className="mb-2">
13+
<Button toggled={type === 'sine'} onClick={() => setType('sine')}>
14+
Sine
15+
</Button>
16+
<Button toggled={type === 'square'} onClick={() => setType('square')}>
17+
Square
18+
</Button>
19+
<Button toggled={type === 'triangle'} onClick={() => setType('triangle')}>
20+
Triangle
21+
</Button>
22+
</Button.Group>
23+
24+
<LFO speed={speed} frequency={frequency} delay={delay} type={type} />
1225

1326
<Knob.Group size={50} trackWidth={3} min={0} max={1} step={0.1}>
1427
<Knob

packages/components/visualization/LFO/LFO.tsx

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ export const LFO = forwardRef<LFORef, LFOProps>((props, ref) => {
4343
useEffect(() => {
4444
generateScales()
4545
generateWave()
46-
}, [speed, frequency, delay])
46+
}, [speed, frequency, delay, type, lineWidth, lineColor])
4747

4848
const dimensions = useResizeObserver(
4949
LFORef,
@@ -72,6 +72,8 @@ export const LFO = forwardRef<LFORef, LFOProps>((props, ref) => {
7272
}
7373

7474
const generateWave = () => {
75+
if (type !== 'sine' && type !== 'square' && type !== 'triangle') return
76+
7577
const { width, height } = dimensions.current
7678
const svg = d3.select(LFORef.current).select('svg').attr('width', width).attr('height', height)
7779

@@ -96,16 +98,15 @@ export const LFO = forwardRef<LFORef, LFOProps>((props, ref) => {
9698
}
9799

98100
generateSineWave(svg)
101+
generateSquareWave(svg)
99102
}
100103

101104
const generateSineWave = (svg: d3.Selection<d3.BaseType, unknown, null, undefined>) => {
102105
if (type !== 'sine' || !svg) return
103106

104107
const data = d3.range(0, 4 * Math.PI * (speed * 10), 0.01).map((x) => {
105-
return {
106-
x,
107-
y: Math.sin(x) * frequency * (max - min) * 0.5 + (max + min) / 2,
108-
}
108+
const y = Math.sin(x) * frequency * (max - min) * 0.5 + (max + min) / 2
109+
return { x, y }
109110
})
110111

111112
const line = d3
@@ -123,6 +124,34 @@ export const LFO = forwardRef<LFORef, LFOProps>((props, ref) => {
123124
.attr('transform', `translate(${delay}, 0)`)
124125
}
125126

127+
const generateSquareWave = (svg: d3.Selection<d3.BaseType, unknown, null, undefined>) => {
128+
if (type !== 'square' || !svg) return
129+
130+
const center = (max + min) / 2
131+
const halfHeight = ((max - min) * frequency) / 2
132+
const data = [{ x: 0, y: center }].concat(
133+
d3.range(0, 4 * Math.PI * (speed * 10), 0.01).map((x) => {
134+
const y =
135+
Math.floor(x / (Math.PI / 2)) % 2 === 0 ? center + halfHeight : center - halfHeight
136+
return { x, y }
137+
}),
138+
)
139+
140+
const line = d3
141+
.line<{ x: number; y: number }>()
142+
.x((d) => xScale.current!(d.x))
143+
.y((d) => yScale.current!(d.y))
144+
145+
svg
146+
.append('path')
147+
.datum(data)
148+
.attr('fill', 'none')
149+
.attr('stroke', lineColor)
150+
.attr('stroke-width', lineWidth)
151+
.attr('d', line)
152+
.attr('transform', `translate(${delay}, 0)`)
153+
}
154+
126155
const { base, svg } = useStyle()
127156

128157
return (

0 commit comments

Comments
 (0)