ngx-audio-wave
Version: 
A modern, accessible audio wave visualization component for Angular 20+ with comprehensive keyboard navigation and screen reader support.
1 lines • 28.9 kB
Source Map (JSON)
{"version":3,"file":"ngx-audio-wave.mjs","sources":["../../../projects/ngx-audio-wave/src/lib/service/ngx-audio-wave.service.ts","../../../projects/ngx-audio-wave/src/lib/ngx-audio-wave.ts","../../../projects/ngx-audio-wave/src/lib/ngx-audio-wave.html","../../../projects/ngx-audio-wave/src/public-api.ts","../../../projects/ngx-audio-wave/src/ngx-audio-wave.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\n\n@Injectable()\nexport class NgxAudioWaveService {\n  samples = 50;\n\n  /**\n   * Filters the AudioBuffer retrieved from an external source\n   * @param {AudioBuffer} audioBuffer the AudioBuffer from drawAudio()\n   * @returns {Array} an array of floating point numbers\n   */\n  filterData(audioBuffer: AudioBuffer): number[] {\n    const rawData = audioBuffer.getChannelData(0); // We only need to work with one channel of data\n    const blockSize = Math.floor(rawData.length / this.samples); // the number of samples in each subdivision\n    const filteredData = [];\n    for (let i = 0; i < this.samples; i++) {\n      let blockStart = blockSize * i; // the location of the first sample in the block\n      let sum = 0;\n      for (let j = 0; j < blockSize; j++) {\n        sum = sum + Math.abs(rawData[blockStart + j]); // find the sum of all the samples in the block\n      }\n      filteredData.push(sum / blockSize); // divide the sum by the block size to get the average\n    }\n    return filteredData;\n  }\n\n  /**\n   * Normalizes the audio data to make a cleaner illustration\n   * @param {Array} filteredData the data from filterData()\n   * @returns {Array} an normalized array of floating point numbers\n   */\n  normalizeData(filteredData: number[]): number[] {\n    const multiplier = Math.pow(Math.max(...filteredData), -1);\n    return filteredData.map(n => n * multiplier);\n  }\n}\n","import {\n  AfterViewInit,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  DestroyRef,\n  ElementRef,\n  inject,\n  input,\n  numberAttribute,\n  OnDestroy,\n  PLATFORM_ID,\n  SecurityContext,\n  signal,\n  viewChild,\n} from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { isPlatformBrowser } from '@angular/common';\nimport { finalize, interval } from 'rxjs';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { DomSanitizer, SafeUrl } from '@angular/platform-browser';\nimport { NgxAudioWaveService } from './service/ngx-audio-wave.service';\n\n@Component({\n  selector: 'ngx-audio-wave',\n  templateUrl: './ngx-audio-wave.html',\n  styleUrls: ['./ngx-audio-wave.scss'],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  providers: [NgxAudioWaveService],\n})\nexport class NgxAudioWave implements AfterViewInit, OnDestroy {\n  // required inputs\n  readonly audioSrc = input.required<string | SafeUrl>();\n\n  // optional inputs\n  readonly color = input('#1e90ff');\n  readonly height = input(25, { transform: numberAttribute });\n  readonly gap = input(5, { transform: numberAttribute });\n  readonly rounded = input(true, { transform: booleanAttribute });\n  readonly hideBtn = input(false, { transform: booleanAttribute });\n  readonly skip = input(5, { transform: numberAttribute });\n  readonly volume = input(1, { transform: numberAttribute });\n  readonly playbackRate = input(1, { transform: numberAttribute });\n  readonly loop = input(false, { transform: booleanAttribute });\n\n  // accessibility inputs\n  readonly ariaLabel = input<string>('');\n  readonly playButtonLabel = input('Play audio');\n  readonly pauseButtonLabel = input('Pause audio');\n  readonly progressBarLabel = input('Audio progress bar');\n\n  // public state signals\n  readonly isPaused = signal(true);\n  readonly isLoading = signal(true);\n  readonly hasError = signal(false);\n  readonly currentVolume = signal(1);\n  readonly currentPlaybackRate = signal(1);\n  readonly isLooping = signal(false);\n  readonly progressText = computed(() => {\n    const current = this.exactCurrentTime();\n    const duration = this.exactDuration();\n    const percent = this.exactPlayedPercent();\n\n    if (duration === 0) {\n      return 'Audio not loaded';\n    }\n\n    const currentMinutes = Math.floor(current / 60);\n    const currentSeconds = Math.floor(current % 60);\n    const durationMinutes = Math.floor(duration / 60);\n    const durationSeconds = Math.floor(duration % 60);\n\n    return `${currentMinutes}:${currentSeconds.toString().padStart(2, '0')} of ${durationMinutes}:${durationSeconds.toString().padStart(2, '0')} (${Math.round(percent)}% played)`;\n  });\n  readonly statusText = computed(() => {\n    if (this.isLoading()) {\n      return 'Loading audio';\n    }\n\n    if (this.hasError()) {\n      return 'Error loading audio';\n    }\n\n    if (this.isPaused()) {\n      return 'Audio paused';\n    }\n\n    return 'Audio playing';\n  });\n\n  // public-exact\n  readonly exactPlayedPercent = computed(() => {\n    const percent = this.calculatePercent(\n      this.exactDuration(),\n      this.exactCurrentTime()\n    );\n    return percent < 100 ? percent : 100;\n  });\n  readonly exactCurrentTime = signal(0);\n  readonly exactDuration = signal(0);\n\n  // deprecated signals\n  /** @deprecated This property will be removed in version 21.0.0. Use exactPlayedPercent instead. */\n  readonly playedPercent = computed(() =>\n    Math.round(this.exactPlayedPercent())\n  );\n  /** @deprecated This property will be removed in version 21.0.0. Use exactCurrentTime instead. */\n  readonly currentTime = computed(() => Math.round(this.exactCurrentTime()));\n  /** @deprecated This property will be removed in version 21.0.0. Use exactDuration instead. */\n  readonly duration = computed(() => Math.round(this.exactDuration()));\n\n  // component internal signals\n  protected readonly normalizedData = signal<number[]>([]);\n  protected readonly clipPath = computed(\n    () => `inset(0px ${100 - this.exactPlayedPercent()}% 0px 0px)`\n  );\n  protected readonly width = computed(\n    () => this.audioWaveService.samples * this.gap()\n  );\n\n  // injecting\n  private readonly platformId = inject(PLATFORM_ID);\n  private readonly isPlatformBrowser = isPlatformBrowser(this.platformId);\n  private readonly domSanitizer = inject(DomSanitizer);\n  private readonly httpClient = inject(HttpClient);\n  private readonly audioWaveService = inject(NgxAudioWaveService);\n  private readonly destroyRef = inject(DestroyRef);\n\n  // view\n  private audioRef =\n    viewChild.required<ElementRef<HTMLAudioElement>>('audioRef');\n\n  // lifecycle hooks\n  ngAfterViewInit() {\n    if (this.isPlatformBrowser) {\n      this.fetchAudio(this.audioSrc());\n      this.setVolume(this.volume());\n      this.setPlaybackRate(this.playbackRate());\n      this.setLoop(this.loop());\n\n      this.startInterval();\n    }\n  }\n\n  ngOnDestroy() {\n    this.stop();\n  }\n\n  // playback control\n  play(time = 0) {\n    if (!this.isPlatformBrowser) return;\n\n    const audio = this.audioRef().nativeElement;\n    void audio.play();\n\n    if (time) {\n      audio.currentTime = time;\n    }\n  }\n\n  pause() {\n    if (!this.isPlatformBrowser) return;\n\n    const audio = this.audioRef().nativeElement;\n    audio.pause();\n  }\n\n  stop() {\n    if (!this.isPlatformBrowser) return;\n\n    const audio = this.audioRef().nativeElement;\n    audio.currentTime = 0;\n    this.pause();\n  }\n\n  // volume\n  setVolume(volume: number) {\n    if (!this.isPlatformBrowser) return;\n\n    const audio = this.audioRef().nativeElement;\n    const clampedVolume = Math.max(0, Math.min(1, volume));\n    audio.volume = clampedVolume;\n    this.currentVolume.set(clampedVolume);\n  }\n\n  mute() {\n    this.setVolume(0);\n  }\n\n  unmute() {\n    this.setVolume(this.volume());\n  }\n\n  toggleMute() {\n    if (this.currentVolume() === 0) {\n      this.unmute();\n    } else {\n      this.mute();\n    }\n  }\n\n  // playback speed\n  setPlaybackRate(rate: number) {\n    if (!this.isPlatformBrowser) return;\n\n    const audio = this.audioRef().nativeElement;\n    const clampedRate = Math.max(0.25, Math.min(4, rate)); // Ограничиваем от 0.25x до 4x\n    audio.playbackRate = clampedRate;\n    this.currentPlaybackRate.set(clampedRate);\n  }\n\n  resetPlaybackRate() {\n    this.setPlaybackRate(1);\n  }\n\n  increasePlaybackRate() {\n    const currentRate = this.currentPlaybackRate();\n    const newRate = Math.min(4, currentRate + 0.25);\n    this.setPlaybackRate(newRate);\n  }\n\n  decreasePlaybackRate() {\n    const currentRate = this.currentPlaybackRate();\n    const newRate = Math.max(0.25, currentRate - 0.25);\n    this.setPlaybackRate(newRate);\n  }\n\n  // loop\n  setLoop(loop: boolean) {\n    if (!this.isPlatformBrowser) return;\n\n    const audio = this.audioRef().nativeElement;\n    audio.loop = loop;\n    this.isLooping.set(loop);\n  }\n\n  enableLoop() {\n    this.setLoop(true);\n  }\n\n  disableLoop() {\n    this.setLoop(false);\n  }\n\n  toggleLoop() {\n    this.setLoop(!this.isLooping());\n  }\n\n  // user interaction\n  setTime(mouseEvent: MouseEvent) {\n    const offsetX = mouseEvent.offsetX;\n    const width = this.width;\n\n    const clickPercent = this.calculatePercent(width(), offsetX);\n\n    const time = (clickPercent * this.exactDuration()) / 100;\n\n    void this.play(time);\n  }\n\n  // private helpers\n  private calculatePercent(total: number, value: number) {\n    return (value / total) * 100 || 0;\n  }\n\n  private startInterval() {\n    interval(100)\n      .pipe(takeUntilDestroyed(this.destroyRef))\n      .subscribe({\n        next: () => {\n          const audio = this.audioRef().nativeElement;\n          this.exactCurrentTime.set(audio.currentTime);\n        },\n      });\n  }\n\n  private fetchAudio(audioSrc: string | SafeUrl) {\n    this.isLoading.set(true);\n\n    const src =\n      typeof audioSrc === 'object'\n        ? this.domSanitizer.sanitize(SecurityContext.URL, audioSrc)\n        : audioSrc;\n    if (!src) {\n      console.error('Invalid SafeUrl: could not sanitize');\n      this.hasError.set(true);\n      return;\n    }\n\n    this.httpClient\n      .get(src, { responseType: 'arraybuffer' })\n      .pipe(\n        finalize(() => {\n          this.isLoading.set(false);\n        }),\n        takeUntilDestroyed(this.destroyRef)\n      )\n      .subscribe({\n        next: async arrayBuffer => {\n          try {\n            const audioContext = new AudioContext();\n            const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);\n\n            this.exactDuration.set(audioBuffer.duration);\n\n            const filteredData = this.audioWaveService.filterData(audioBuffer);\n            this.normalizedData.set(\n              this.audioWaveService.normalizeData(filteredData)\n            );\n          } catch (e) {\n            this.hasError.set(true);\n          }\n        },\n        error: error => {\n          console.error(error);\n\n          this.hasError.set(true);\n        },\n      });\n  }\n\n  protected pauseChange(event: Event) {\n    if (!(event.target instanceof HTMLAudioElement)) return;\n    this.isPaused.set(event.target.paused);\n  }\n\n  // event handlers\n  protected onKeyDown(event: KeyboardEvent) {\n    if (!this.isPlatformBrowser) return;\n\n    const audio = this.audioRef().nativeElement;\n    const duration = this.exactDuration();\n\n    switch (event.key) {\n      case ' ':\n      case 'Enter':\n        event.preventDefault();\n        if (this.isPaused()) {\n          this.play();\n        } else {\n          this.pause();\n        }\n        break;\n\n      case 'ArrowLeft':\n        event.preventDefault();\n        const leftTime = Math.max(0, audio.currentTime - this.skip());\n        this.play(leftTime);\n        break;\n\n      case 'ArrowRight':\n        event.preventDefault();\n        const rightTime = Math.min(duration, audio.currentTime + this.skip());\n        this.play(rightTime);\n        break;\n\n      case 'Home':\n        event.preventDefault();\n        this.play(0);\n        break;\n\n      case 'End':\n        event.preventDefault();\n        this.play(duration);\n        break;\n    }\n  }\n}\n","<audio\n  #audioRef\n  [src]=\"audioSrc()\"\n  (pause)=\"pauseChange($event)\"\n  (play)=\"pauseChange($event)\"\n  hidden=\"hidden\"\n></audio>\n\n<div\n  class=\"ngx-audio-wave-wrapper\"\n  [attr.aria-label]=\"ariaLabel() || 'Audio player'\"\n  [style.--ngx-audio-wave-color]=\"color()\"\n  role=\"region\"\n>\n  @if (!hasError()) {\n    @if (!hideBtn()) {\n      @if (isPaused()) {\n        <button\n          class=\"ngx-audio-wave-btn\"\n          [attr.aria-label]=\"playButtonLabel()\"\n          [attr.aria-pressed]=\"false\"\n          (click)=\"play()\"\n          type=\"button\"\n        >\n          <svg\n            aria-hidden=\"true\"\n            height=\"16\"\n            viewBox=\"0 0 16 16\"\n            width=\"16\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n          >\n            <path\n              d=\"m11.596 8.697-6.363 3.692c-.54.313-1.233-.066-1.233-.697V4.308c0-.63.692-1.01 1.233-.696l6.363 3.692a.802.802 0 0 1 0 1.393z\"\n            />\n          </svg>\n        </button>\n      } @else {\n        <button\n          class=\"ngx-audio-wave-btn\"\n          [attr.aria-label]=\"pauseButtonLabel()\"\n          [attr.aria-pressed]=\"true\"\n          (click)=\"pause()\"\n          type=\"button\"\n        >\n          <svg\n            aria-hidden=\"true\"\n            height=\"16\"\n            viewBox=\"0 0 16 16\"\n            width=\"16\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n          >\n            <path\n              d=\"M5.5 3.5A1.5 1.5 0 0 1 7 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5zm5 0A1.5 1.5 0 0 1 12 5v6a1.5 1.5 0 0 1-3 0V5a1.5 1.5 0 0 1 1.5-1.5z\"\n            />\n          </svg>\n        </button>\n      }\n    }\n\n    <div\n      class=\"ngx-audio-wave\"\n      [attr.aria-label]=\"progressBarLabel()\"\n      [attr.aria-valuemax]=\"100\"\n      [attr.aria-valuemin]=\"0\"\n      [attr.aria-valuenow]=\"exactPlayedPercent()\"\n      [attr.aria-valuetext]=\"progressText()\"\n      [style.height.px]=\"height()\"\n      [style.width.px]=\"width()\"\n      (click)=\"setTime($event)\"\n      (keydown)=\"onKeyDown($event)\"\n      role=\"progressbar\"\n      tabindex=\"0\"\n    >\n      @if (!isLoading()) {\n        <svg\n          class=\"real\"\n          [attr.viewBox]=\"`0 0 ${width()} ${height()}`\"\n          aria-hidden=\"true\"\n        >\n          @for (rect of normalizedData(); track rect; let index = $index) {\n            <rect\n              [attr.height]=\"rect * height()\"\n              [attr.rx]=\"rounded() ? 1 : 0\"\n              [attr.ry]=\"rounded() ? 1 : 0\"\n              [attr.width]=\"2\"\n              [attr.x]=\"index * gap()\"\n              [attr.y]=\"height() - rect * height()\"\n            ></rect>\n          }\n        </svg>\n\n        <div class=\"fake\" [style.clip-path]=\"clipPath()\">\n          <svg [attr.viewBox]=\"`0 0 ${width()} ${height()}`\" aria-hidden=\"true\">\n            @for (rect of normalizedData(); track rect; let index = $index) {\n              <rect\n                [attr.height]=\"rect * height()\"\n                [attr.rx]=\"rounded() ? 1 : 0\"\n                [attr.ry]=\"rounded() ? 1 : 0\"\n                [attr.width]=\"2\"\n                [attr.x]=\"index * gap()\"\n                [attr.y]=\"height() - rect * height()\"\n              ></rect>\n            }\n          </svg>\n        </div>\n      } @else {\n        <div\n          class=\"ngx-audio-wave-loading\"\n          aria-label=\"Loading audio\"\n          role=\"status\"\n        >\n          <span></span>\n          <span></span>\n          <span></span>\n        </div>\n      }\n    </div>\n\n    <!-- Live region for screen readers -->\n    <div class=\"ngx-audio-wave-sr-only\" aria-atomic=\"true\" aria-live=\"polite\">\n      {{ statusText() }}\n    </div>\n  } @else {\n    <div aria-label=\"Audio loading error\" role=\"alert\">\n      Some errors occurred\n    </div>\n  }\n</div>\n","/*\n * Public API Surface of ngx-audio-wave\n */\n\nexport * from './lib/ngx-audio-wave';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}