| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748 |
- import { SpectrumRenderer, SpectrumRenderOptions, buildSpectrumPalette, hslToHex, rgbaFromHex } from './SpectrumRenderer'
- /**
- * 点阵频谱渲染器
- * 使用点阵网格表达频谱能量层级
- */
- export class DotMatrixSpectrumRenderer implements SpectrumRenderer {
- render(ctx: CanvasRenderingContext2D, bands: number[], energy: number,
- width: number, height: number, brandColor: string, options?: SpectrumRenderOptions): void {
- if (bands.length === 0) return
- ctx.clearRect(0, 0, width, height)
- const palette = buildSpectrumPalette(brandColor)
- const complexityScale: number = Math.max(0.45, Math.min(1, options?.complexityScale ?? 1))
- const columns: number = Math.max(12, Math.floor(20 * complexityScale))
- const rows: number = Math.max(8, Math.floor(14 * complexityScale))
- const cellW: number = width / columns
- const cellH: number = height / rows
- const radius: number = Math.max(1.6, Math.min(cellW, cellH) * 0.28)
- for (let c = 0; c < columns; c++) {
- const bandIndex: number = Math.floor((c / columns) * bands.length)
- const value: number = Math.max(0, Math.min(1, bands[bandIndex]))
- const activeRows: number = Math.floor(value * rows)
- const hue: number = (palette.primaryHue + (c / columns) * 135) % 360
- for (let r = 0; r < rows; r++) {
- const lit: boolean = r >= rows - activeRows
- const x: number = c * cellW + cellW * 0.5
- const y: number = r * cellH + cellH * 0.5
- const alpha: number = lit ? (0.30 + value * 0.65) : 0.08
- const lightness: number = lit ? (0.45 + 0.28 * (r / rows)) : 0.22
- ctx.fillStyle = rgbaFromHex(hslToHex(hue, 0.82, lightness), alpha)
- ctx.beginPath()
- ctx.arc(x, y, radius, 0, Math.PI * 2)
- ctx.fill()
- }
- }
- ctx.fillStyle = rgbaFromHex(hslToHex(palette.accentHue, 0.88, 0.60), 0.10 + energy * 0.18)
- ctx.fillRect(0, height * 0.48, width, 2)
- }
- reset(): void {
- // 无状态
- }
- }
|