StarburstSpectrumRenderer.ets 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
  1. import { SpectrumRenderer, SpectrumRenderOptions, buildSpectrumPalette, hslToHex, rgbaFromHex } from './SpectrumRenderer'
  2. /**
  3. * 星爆频谱渲染器
  4. * 从中心向外爆发的星芒线条
  5. */
  6. export class StarburstSpectrumRenderer implements SpectrumRenderer {
  7. private drift: number = 0
  8. render(ctx: CanvasRenderingContext2D, bands: number[], energy: number,
  9. width: number, height: number, brandColor: string, options?: SpectrumRenderOptions): void {
  10. if (bands.length === 0) return
  11. ctx.clearRect(0, 0, width, height)
  12. const palette = buildSpectrumPalette(brandColor)
  13. const centerX: number = width / 2
  14. const centerY: number = height / 2
  15. const complexityScale: number = Math.max(0.45, Math.min(1, options?.complexityScale ?? 1))
  16. const rays: number = Math.max(18, Math.floor(44 * complexityScale))
  17. const outerMax: number = Math.min(width, height) * 0.46
  18. const innerRadius: number = Math.min(width, height) * 0.08
  19. this.drift += 0.015 + energy * 0.01
  20. for (let i = 0; i < rays; i++) {
  21. const bandIndex: number = Math.floor((i / rays) * bands.length)
  22. const value: number = Math.pow(bands[bandIndex], 0.8)
  23. const angle: number = (Math.PI * 2 * i) / rays + this.drift
  24. const len: number = innerRadius + value * (outerMax - innerRadius)
  25. const x1: number = centerX + Math.cos(angle) * innerRadius
  26. const y1: number = centerY + Math.sin(angle) * innerRadius
  27. const x2: number = centerX + Math.cos(angle) * len
  28. const y2: number = centerY + Math.sin(angle) * len
  29. const hue: number = (palette.warmHue + i * 5) % 360
  30. ctx.beginPath()
  31. ctx.moveTo(x1, y1)
  32. ctx.lineTo(x2, y2)
  33. ctx.strokeStyle = rgbaFromHex(hslToHex(hue, 0.88, 0.58), 0.20 + value * 0.70)
  34. ctx.lineWidth = 1 + value * 2.2
  35. ctx.stroke()
  36. }
  37. const coreRadius: number = innerRadius * (0.85 + energy * 0.65)
  38. ctx.beginPath()
  39. ctx.arc(centerX, centerY, coreRadius, 0, Math.PI * 2)
  40. ctx.fillStyle = rgbaFromHex(hslToHex(palette.complementaryHue, 0.82, 0.62), 0.14 + energy * 0.18)
  41. ctx.fill()
  42. }
  43. reset(): void {
  44. this.drift = 0
  45. }
  46. }