import React from 'react'; import PropTypes from 'prop-types'; import styles from './waveform.css'; // Waveform is expensive to compute, make sure it only updates when data does // by using PureComponent. In future can be changed back to function with React.memo // eslint-disable-next-line react/prefer-stateless-function class Waveform extends React.PureComponent { render () { const { width, height, data } = this.props; // Never want a density of points higher than the number of pixels // This is very conservative, could be far fewer points because of curve smoothing. // Drawing too many points seems to cause an explosion in browser // composite time when animating the playhead const takeEveryN = Math.ceil(data.length / width); const filteredData = takeEveryN === 1 ? data.slice(0) : data.filter((_, i) => i % takeEveryN === 0); // Need at least two points to render waveform. if (filteredData.length === 1) { filteredData.push(filteredData[0]); } const maxIndex = filteredData.length - 1; const points = [ ...filteredData.map((v, i) => [width * (i / maxIndex), height * v / 2] ), ...filteredData.reverse().map((v, i) => [width * (1 - (i / maxIndex)), -height * v / 2] ) ]; const pathComponents = points.map(([x, y], i) => { const [nx, ny] = points[i < points.length - 1 ? i + 1 : 0]; return `Q${x} ${y} ${(x + nx) / 2} ${(y + ny) / 2}`; }); return ( ); } } Waveform.propTypes = { data: PropTypes.arrayOf(PropTypes.number), height: PropTypes.number, width: PropTypes.number }; export default Waveform;