diff --git a/frontend/src/component/feature/progress-styles.scss b/frontend/src/component/feature/progress-styles.scss index c036577277..c3a79c7de9 100644 --- a/frontend/src/component/feature/progress-styles.scss +++ b/frontend/src/component/feature/progress-styles.scss @@ -1,7 +1,7 @@ .path { stroke: #3f51b5; stroke-linecap: round; - transition: stroke-dashoffset 5s ease 0s; + transition: stroke-dashoffset 11s ease 0s; } .trail { @@ -14,4 +14,4 @@ line-height: 25px; dominant-baseline: middle; text-anchor: middle; -} \ No newline at end of file +} diff --git a/frontend/src/component/feature/progress.jsx b/frontend/src/component/feature/progress.jsx index 59386daeb3..c5b67fb3fd 100644 --- a/frontend/src/component/feature/progress.jsx +++ b/frontend/src/component/feature/progress.jsx @@ -7,13 +7,14 @@ class Progress extends Component { this.state = { percentage: props.initialAnimation ? 0 : props.percentage, + percentageText: props.initialAnimation ? 0 : props.percentage, }; } componentDidMount () { if (this.props.initialAnimation) { this.initialTimeout = setTimeout(() => { - this.requestAnimationFrame = window.requestAnimationFrame(() => { + this.rafTimerInit = window.requestAnimationFrame(() => { this.setState({ percentage: this.props.percentage, }); @@ -23,16 +24,78 @@ class Progress extends Component { } componentWillReceiveProps ({ percentage }) { - this.setState({ percentage }); + if (this.state.percentage !== percentage) { + const nextState = { percentage }; + if (this.props.animatePercentageText) { + this.animateTo(percentage, this.getTarget(percentage)); + } else { + nextState.percentageText = percentage; + } + this.setState(nextState); + } } + getTarget (target) { + const start = this.state.percentageText; + const TOTAL_ANIMATION_TIME = 10000; + const diff = start > target ? -(start - target) : target - start; + const perCycle = TOTAL_ANIMATION_TIME / diff; + const cyclesCounter = Math.round(Math.abs(TOTAL_ANIMATION_TIME / perCycle)); + const perCycleTime = Math.round(Math.abs(perCycle)); + + let usedTime = 0; + // this initial value could be tweaked more + let lastTime = perCycleTime / 4; + return { + start, + target, + cyclesCounter, + getTimer () { + /* Somewhat tweaked values to get a curve on the counting */ + if (usedTime > (TOTAL_ANIMATION_TIME / 2)) { + // if halfway, lets speed up timeouts + lastTime *= 0.95; + } else { + lastTime *= 1.1; + } + usedTime += lastTime; + return lastTime; + }, + increment: diff / cyclesCounter, + }; + } + + animateTo (percentage, targetState) { + cancelAnimationFrame(this.rafCounterTimer); + clearTimeout(this.nextTimer); + + const current = this.state.percentageText; + + targetState.cyclesCounter --; + if (targetState.cyclesCounter <= 0) { + this.setState({ percentageText: targetState.target }); + return; + } + + const next = Math.round(current + targetState.increment); + this.rafCounterTimer = requestAnimationFrame(() => { + this.setState({ percentageText: next }); + this.nextTimer = setTimeout(() => { + this.animateTo(next, targetState); + }, targetState.getTimer()); + }); + } + + componentWillUnmount () { clearTimeout(this.initialTimeout); - window.cancelAnimationFrame(this.requestAnimationFrame); + clearTimeout(this.nextTimer); + window.cancelAnimationFrame(this.rafTimerInit); + window.cancelAnimationFrame(this.rafCounterTimer); } render () { - const { strokeWidth, percentage } = this.props; + const { strokeWidth } = this.props; const radius = (50 - strokeWidth / 2); const pathDescription = ` M 50,50 m 0,-${radius} @@ -66,7 +129,7 @@ class Progress extends Component { className={styles.text} x={50} y={50} - >{percentage}% + >{this.state.percentageText}% ); } } @@ -75,11 +138,13 @@ Progress.propTypes = { percentage: PropTypes.number.isRequired, strokeWidth: PropTypes.number, initialAnimation: PropTypes.bool, + animatePercentageText: PropTypes.bool, textForPercentage: PropTypes.func, }; Progress.defaultProps = { strokeWidth: 8, + animatePercentageText: false, initialAnimation: false, }; diff --git a/frontend/src/component/feature/view-edit-container.jsx b/frontend/src/component/feature/view-edit-container.jsx index 867aa41662..f3d2644374 100644 --- a/frontend/src/component/feature/view-edit-container.jsx +++ b/frontend/src/component/feature/view-edit-container.jsx @@ -36,7 +36,7 @@ const MetricTab = ({ metrics, featureToggle, toggleFeature }) => { :
- +
}

Last minute
Yes {lastMinute.yes}, No: {lastMinute.no}