es1, keyframes2) ? j : -1; }) ); }) .map(keyframes => { return keyframes.map(keyframe => { return { easing: keyframe.easing, offset: keyframe.offset }; }); }); } /** * Return true if given keyframes have same length, offset and easing. * * @param {Array} keyframes1 * @param {Array} keyframes2 * @return {boolean} true: equals */ isOffsetAndEasingKeyframesEqual(keyframes1, keyframes2) { if (keyframes1.length !== keyframes2.length) { return false; } for (let i = 0; i < keyframes1.length; i++) { const keyframe1 = keyframes1[i]; const keyframe2 = keyframes2[i]; if ( keyframe1.offset !== keyframe2.offset || keyframe1.easing !== keyframe2.easing ) { return false; } } return true; } updateState(props) { const { animation, getAnimatedPropertyMap, timeScale } = props; let animatedPropertyMap = null; let thisEl = null; try { animatedPropertyMap = getAnimatedPropertyMap(animation); thisEl = ReactDOM.findDOMNode(this); } catch (e) { // Expected if we've already been destroyed or other node have been selected // in the meantime. console.error(e); return; } const keyframesList = this.getOffsetAndEasingOnlyKeyframes(animatedPropertyMap); const totalDuration = timeScale.getDuration() * Math.abs(animation.state.playbackRate); const durationPerPixel = totalDuration / thisEl.parentNode.clientWidth; this.setState({ durationPerPixel, isStateUpdating: false, keyframesList, }); } render() { const { durationPerPixel, keyframesList } = this.state; const { animation, simulateAnimation, timeScale } = this.props; if (!durationPerPixel || !animation.state.type) { // Undefined animation.state.type means that the animation had been removed already. // Even if the animation was removed, we still need the empty svg since the // component might be re-used. return dom.svg(); } const { playbackRate } = animation.state; const { createdTime } = animation.state.absoluteValues; const absPlaybackRate = Math.abs(playbackRate); // Absorb the playbackRate in viewBox of SVG and offset of child path elements // in order to each graph path components can draw without considering to the // playbackRate. const offset = createdTime * absPlaybackRate; const startTime = timeScale.minStartTime * absPlaybackRate; const totalDuration = timeScale.getDuration() * absPlaybackRate; const opacity = Math.max( 1 / keyframesList.length, MIN_KEYFRAMES_EASING_OPACITY ); return dom.svg( { className: "animation-summary-graph-path", preserveAspectRatio: "none", viewBox: `${startTime} -${DEFAULT_GRAPH_HEIGHT} ` + `${totalDuration} ${DEFAULT_GRAPH_HEIGHT}`, }, keyframesList.map(keyframes => ComputedTimingPath({ animation, durationPerPixel, keyframes, offset, opacity, simulateAnimation, totalDuration, }) ), animation.state.easing !== "linear" ? EffectTimingPath({ animation, durationPerPixel, offset, simulateAnimation, totalDuration, }) : null, animation.state.delay < 0 ? keyframesList.map(keyframes => { return NegativeDelayPath({ animation, durationPerPixel, keyframes, offset, simulateAnimation, totalDuration, }); }) : null, animation.state.iterationCount && animation.state.endDelay < 0 ? keyframesList.map(keyframes => { return NegativeEndDelayPath({ animation, durationPerPixel, keyframes, offset, simulateAnimation, totalDuration, }); }) : null ); } } module.exports = SummaryGraphPath; PK