Skip to content
Snippets Groups Projects
Unverified Commit 9a4ef280 authored by Paul Kaplan's avatar Paul Kaplan Committed by GitHub
Browse files

Merge pull request #4396 from paulkaplan/improve-sound-editor-perf

Improve sound editor performance with longer sounds
parents b6e1de50 6b6662f5
No related branches found
No related tags found
No related merge requests found
......@@ -12,6 +12,9 @@ $hover-scale: 2;
left: 0;
width: 100%;
height: 100%;
/* Force the browser to paint separately to avoid composite cost with waveform */
transform: translateZ(0);
}
.trim-background {
......@@ -51,7 +54,15 @@ $hover-scale: 2;
}
.playhead {
border: 1px solid $motion-primary;
/*
Even though playhead is just a line, it is 100% width (the width of the waveform)
so that we can use transform: translateX() using percentages.
*/
width: 100%;
border-left: 1px solid $motion-primary;
border-top: none;
border-bottom: none;
border-right: none;
}
.start-trim-line {
......
......@@ -35,7 +35,7 @@ const AudioTrimmer = props => (
<Box
className={classNames(styles.trimLine, styles.playhead)}
style={{
left: `${100 * props.playhead}%`
transform: `translateX(${100 * props.playhead}%)`
}}
/>
) : null}
......
......@@ -2,52 +2,65 @@ import React from 'react';
import PropTypes from 'prop-types';
import styles from './waveform.css';
const Waveform = props => {
const {
width,
height,
data
} = props;
const cappedData = [0, ...data, 0];
const points = [
...cappedData.map((v, i) =>
[width * i / cappedData.length, height * v / 2]
),
...cappedData.reverse().map((v, i) =>
[width * (cappedData.length - i - 1) / cappedData.length, -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 (
<svg
className={styles.container}
viewBox={`-1 0 ${width} ${height}`}
>
<line
className={styles.baseline}
x1={-1}
x2={width}
y1={height / 2}
y2={height / 2}
/>
<g transform={`scale(1, -1) translate(0, -${height / 2})`}>
<path
className={styles.waveformPath}
d={`M0 0${pathComponents.join(' ')}Z`}
strokeLinejoin={'round'}
strokeWidth={1}
// 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 :
data.filter((_, i) => i % takeEveryN === 0);
const cappedData = [0, ...filteredData, 0];
const points = [
...cappedData.map((v, i) =>
[width * i / cappedData.length, height * v / 2]
),
...cappedData.reverse().map((v, i) =>
[width * (cappedData.length - i - 1) / cappedData.length, -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 (
<svg
className={styles.container}
viewBox={`-1 0 ${width} ${height}`}
>
<line
className={styles.baseline}
x1={-1}
x2={width}
y1={height / 2}
y2={height / 2}
/>
</g>
</svg>
);
};
<g transform={`scale(1, -1) translate(0, -${height / 2})`}>
<path
className={styles.waveformPath}
d={`M0 0${pathComponents.join(' ')}Z`}
strokeLinejoin={'round'}
strokeWidth={1}
/>
</g>
</svg>
);
}
}
Waveform.propTypes = {
data: PropTypes.arrayOf(PropTypes.number),
......
......@@ -224,7 +224,7 @@ exports[`Sound Editor Component matches snapshot 1`] = `
"flexWrap": undefined,
"height": undefined,
"justifyContent": undefined,
"left": "50%",
"transform": "translateX(50%)",
"width": undefined,
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment