const dataMap = new WeakMap(); const normalizeArray = (data, m, downsamplePeaks = false, memoize = false) => { let cache, mKey, dKey; if (memoize) { mKey = m.toString(); dKey = downsamplePeaks.toString(); cache = dataMap.has(data)? dataMap.get(data) : {}; dataMap.set(data, cache); cache[mKey] = cache[mKey] || {}; if (cache[mKey][dKey]) { return cache[mKey][dKey]; } } const n = data.length; const result = new Array(m); if (m <= n) { // Downsampling result.fill(0); const count = new Array(m).fill(0); for (let i = 0; i < n; i++) { const index = Math.floor(i * (m / n)); if (downsamplePeaks) { // take highest result in the set result[index] = Math.max(result[index], Math.abs(data[i])); } else { result[index] += Math.abs(data[i]); } count[index]++; } if (!downsamplePeaks) { for (let i = 0; i < result.length; i++) { result[i] = result[i] / count[i]; } } } else { for (let i = 0; i < m; i++) { const index = (i * (n - 1)) / (m - 1); const low = Math.floor(index); const high = Math.ceil(index); const t = index - low; if (high >= n) { result[i] = data[n - 1]; } else { result[i] = data[low] * (1 - t) + data[high] * t; } } } if (memoize) { cache[mKey][dKey] = result; } return result; }; export const WavRenderer = { drawBars: (canvas, ctx, data, color, pointCount = 0, barWidth = 0, barSpacing = 0, center = false) => { pointCount = Math.floor( Math.min( pointCount, (canvas.width - barSpacing) / (Math.max(barWidth, 1) + barSpacing) ) ); if (!pointCount) { pointCount = Math.floor( (canvas.width - barSpacing) / (Math.max(barWidth, 1) + barSpacing) ); } if (!barWidth) { barWidth = (canvas.width - barSpacing) / pointCount - barSpacing; } const points = normalizeArray(data, pointCount, true); for (let i = 0; i < pointCount; i++) { const amplitude = Math.abs(points[i]); const height = Math.max(1, amplitude * canvas.height); const x = barSpacing + i * (barWidth + barSpacing); const y = center? (canvas.height - height) / 2 : canvas.height - height; ctx.fillStyle = color; ctx.fillRect(x, y, barWidth, height); } }, };