Как анализировать данные веб-аудио частоты с помощью d3 js

1

Я визуализирую веб-аудио данные с помощью d3. Я постоянно запускаю функцию, которая добавляет данные в d3 с помощью requestanimationframe. Когда я консоль регистрирую данные частоты в рекурсивном вызове функции, я получаю результат, как и ожидалось. Однако, когда я связываю данные с svg и пытаюсь создать элементы с помощью d3, цикл запускается только дважды.

Я пытался передать разные наборы данных в привязку данных, но каждый результат вызывает функцию только дважды. Например:

import createBoomBox from './boombox';

const frequencyData = new Uint8Array(200);

const createFrequency = (analyser) => {
  requestAnimationFrame(() => createFrequency(analyser));
  analyser.getByteFrequencyData(frequencyData);
  createBoomBox(frequencyData);
  };

const createAudio = (audioId) => {
  console.log('in audio');
  const audioCtx = new (window.AudioContext || 
  window.webkitAudioContext)();

  const audioElement = document.getElementById(audioId);

   const audioSrc = audioCtx.createMediaElementSource(audioElement) 
    || window.audiosrc;
   window.audioSrc = audioSrc;
   const analyser = audioCtx.createAnalyser();

   audioSrc.connect(analyser);

   audioSrc.connect(audioCtx.destination);

   createFrequency(analyser);
   };

   export default createAudio;

Здесь я создаю аудио-контекст и передаю данные частоты в createBoomBox. createBoomBox выглядит следующим образом:

const svgHeight = 200;
const svgWidth = 200;

const boomBox = d3.selectAll('.boom-box');

const svg = boomBox.append('svg')
  .attr('height', svgHeight)
  .attr('width', svgWidth);

const createBoomBox = (frequencyData) => {
  const rangeScale = d3.scaleLinear()
    .domain([0, d3.max(frequencyData)])
    .range([0, svgHeight]);

  const hslScale = d3.scaleLinear()
    .domain([0, d3.max(frequencyData)])
    .range([0, 360]);

  console.log(frequencyData);
  svg.selectAll('circle')
    .data(frequencyData)
    .enter()
    .append('circle')
    .attr('r', d => rangeScale(d))
    .attr('cx', svgWidth / 2)
    .attr('cy', svgHeight / 2)
    .attr('fill', 'none')
    .attr('stroke-width', 4)
    .attr('stroke-opacity', 1)
    .attr('stroke', d => d3.hsl(hslScale(d), 1, 0.5))
    .exit()
    .remove();
};

export default createBoomBox;

Проблема возникает в функции createBoomBox, в

 svg.selectAll

createBoomBox повторно вызывается с requestAnimationFrame. Когда консоль регистрирует данные частоты прямо над строкой svg.selectAll, я получаю результат, как и ожидалось. А именно, массив в виде Uint8Array с частотными данными.

Тем не менее, когда я консоль журнала данных внутри

svg.selectAll('circle')
        .data(frequencyData)
        .enter()
        .append('circle')
        .attr('r', d => rangeScale(d))
        .attr('cx', svgWidth / 2)
        .attr('cy', svgHeight / 2)
        .attr('fill', 'none')
        .attr('stroke-width', 4)
        .attr('stroke-opacity', 1)
        .attr('stroke', d => d3.hsl(hslScale(d), 1, 0.5))
        .exit()
        .remove();

Итерация в приведенном выше блоке кода происходит только дважды. Таким образом, хотя вся функция неоднократно вызывается через requestAnimationFrame, блок svg.selectAll запускается только дважды. Любая идея относительно того, что вызывает проблему?

  • 0
    Здравствуйте, вы можете добавить фрагмент кода, пожалуйста
Теги:
audio
d3.js

1 ответ

1
Лучший ответ

Ваш выбор выхода всегда пуст.

Вам необходимо применить шаблон Enter-Update-Exit.

var circles = svg.selectAll('circle')
    .data(frequencyData);
circles.exit().remove();
circles.enter()
  .append('circle')
    .attr('cx', svgWidth / 2)
    .attr('cy', svgHeight / 2)
    .attr('fill', 'none')
    .attr('stroke-width', 4)
    .attr('stroke-opacity', 1)
  .merge(circles)
    .attr('r', d => rangeScale(d))
    .attr('stroke', d => d3.hsl(hslScale(d), 1, 0.5));
  • 0
    Спасибо! Это сработало! Вы также знаете, как удалить созданные источники медиа-элементов? Например, каждый аудиофайл запускается нажатием клавиши. Когда я повторяю нажатие клавиши, я получаю следующую ошибку: Не удалось выполнить «createMediaElementSource» для «AudioContext»: HTMLMediaElement ранее уже подключен к другому MediaElementSourceNode

Ещё вопросы

Сообщество Overcoder
Наверх
Меню