Я визуализирую веб-аудио данные с помощью 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 запускается только дважды. Есть идеи, что является причиной проблемы?