= animationItemEl.offsetHeight; this.updateDisplayableRange(); } componentDidUpdate(prevProps) { const { timeScale, sidebarWidth } = this.props; if ( timeScale.getDuration() !== prevProps.timeScale.getDuration() || timeScale.zeroPositionTime !== prevProps.timeScale.zeroPositionTime || sidebarWidth !== prevProps.sidebarWidth ) { this.updateTicks(this.props); } } /** * Since it takes too much time if we render all of animation graphs, * we restrict to render the items that are not in displaying area. * This function calculates the displayable item range. */ updateDisplayableRange() { const count = Math.floor(this._animationListEl.offsetHeight / this._itemHeight) + 1; const index = Math.floor( this._inspectionPanelEl.scrollTop / this._itemHeight ); this.setState({ displayableRange: { startIndex: index, endIndex: index + count }, }); } updateTicks(props) { const { animations, timeScale } = props; const tickLinesEl = this._ref.current.querySelector(".tick-lines"); const width = tickLinesEl.offsetWidth; const animationDuration = timeScale.getDuration(); const minTimeInterval = (TIME_GRADUATION_MIN_SPACING * animationDuration) / width; const intervalLength = findOptimalTimeInterval(minTimeInterval); const intervalWidth = (intervalLength * width) / animationDuration; const tickCount = parseInt(width / intervalWidth, 10); const isAllDurationInfinity = animations.every( animation => animation.state.duration === Infinity ); const zeroBasePosition = width * (timeScale.zeroPositionTime / animationDuration); const shiftWidth = zeroBasePosition % intervalWidth; const needToShift = zeroBasePosition !== 0 && shiftWidth !== 0; const ticks = []; // Need to display first graduation since position will be shifted. if (needToShift) { const label = timeScale.formatTime(timeScale.distanceToRelativeTime(0)); ticks.push({ position: 0, label, width: shiftWidth }); } for (let i = 0; i <= tickCount; i++) { const position = ((i * intervalWidth + shiftWidth) * 100) / width; const distance = timeScale.distanceToRelativeTime(position); const label = isAllDurationInfinity && i === tickCount ? getStr("player.infiniteTimeLabel") : timeScale.formatTime(distance); ticks.push({ position, label, width: intervalWidth }); } this.setState({ ticks }); } render() { const { addAnimationsCurrentTimeListener, animations, direction, dispatch, getAnimatedPropertyMap, getNodeFromActor, removeAnimationsCurrentTimeListener, selectAnimation, setAnimationsCurrentTime, setHighlightedNode, setSelectedNode, simulateAnimation, timeScale, } = this.props; const { displayableRange, ticks } = this.state; return dom.div( { className: "animation-list-container", ref: this._ref, }, ProgressInspectionPanel({ indicator: CurrentTimeScrubber({ addAnimationsCurrentTimeListener, direction, removeAnimationsCurrentTimeListener, setAnimationsCurrentTime, timeScale, }), list: AnimationList({ animations, dispatch, displayableRange, getAnimatedPropertyMap, getNodeFromActor, selectAnimation, setHighlightedNode, setSelectedNode, simulateAnimation, timeScale, }), ticks, }) ); } } const mapStateToProps = state => { return { sidebarWidth: state.animations.sidebarSize ? state.animations.sidebarSize.width : 0, }; }; module.exports = connect(mapStateToProps)(AnimationListContainer); PK