From 29bfa40657409ea09aeb4030d52ba765185dfa9b Mon Sep 17 00:00:00 2001 From: Shan He Date: Fri, 5 Feb 2021 00:17:30 +0800 Subject: [PATCH] [Bug] Interval animation doesn't stop when speed is set to 0 (#1397) * Fix: If time series speed is set to 0, the timeline should stop animation (Step by interval mode) * Added tests for clamp Co-authored-by: Ilya Boyandin --- .../animation-control/animation-controller.js | 43 +++++++++++-------- test/node/utils/data-utils-test.js | 10 +++++ 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/components/common/animation-control/animation-controller.js b/src/components/common/animation-control/animation-controller.js index 10c485c3dc..bce3cbadac 100644 --- a/src/components/common/animation-control/animation-controller.js +++ b/src/components/common/animation-control/animation-controller.js @@ -77,9 +77,10 @@ function AnimationControllerFactory() { _timer = null; _startOrPauseAnimation() { - if (!this._timer && this.props.isAnimating) { + const {isAnimating, speed} = this.props; + if (!this._timer && isAnimating && speed > 0) { this._startAnimation(); - } else if (this._timer && !this.props.isAnimating) { + } else if (this._timer && !isAnimating) { this._pauseAnimation(); } } @@ -130,31 +131,37 @@ function AnimationControllerFactory() { }; _startAnimation = () => { - this._pauseAnimation(); - if (this.props.animationWindow === ANIMATION_WINDOW.interval) { - // animate by interval - // 30*600 - const {steps, speed} = this.props; - if (!Array.isArray(steps) || !steps.length) { - Console.warn('animation steps should be an array'); - return; + const {speed} = this.props; + this._clearTimer(); + if (speed > 0) { + if (this.props.animationWindow === ANIMATION_WINDOW.interval) { + // animate by interval + // 30*600 + const {steps} = this.props; + if (!Array.isArray(steps) || !steps.length) { + Console.warn('animation steps should be an array'); + return; + } + // when speed = 1, animation should loop through 600 frames at 60 FPS + // calculate delay based on # steps + const delay = (BASE_SPEED * (1000 / FPS)) / steps.length / (speed || 1); + this._animate(delay); + } else { + this._timer = requestAnimationFrame(this._nextFrame); } - // when speed = 1, animation should loop through 600 frames at 60 FPS - // calculate delay based on # steps - const delay = (BASE_SPEED * (1000 / FPS)) / steps.length / (speed || 1); - this._animate(delay); - } else { - this._timer = requestAnimationFrame(this._nextFrame); } - this.setState({isAnimating: true}); }; - _pauseAnimation = () => { + _clearTimer = () => { if (this._timer) { cancelAnimationFrame(this._timer); this._timer = null; } + }; + + _pauseAnimation = () => { + this._clearTimer(); this.setState({isAnimating: false}); }; diff --git a/test/node/utils/data-utils-test.js b/test/node/utils/data-utils-test.js index d7d36a51ee..8d02ca84ba 100644 --- a/test/node/utils/data-utils-test.js +++ b/test/node/utils/data-utils-test.js @@ -21,6 +21,7 @@ import test from 'tape'; import { + clamp, getRoundingDecimalFromStep, preciseRound, normalizeSliderValue, @@ -32,6 +33,15 @@ import { } from 'utils/data-utils'; import {ALL_FIELD_TYPES} from 'constants'; +test('dataUtils -> clamp', t => { + t.equal(clamp([0,1], 2), 1, 'should clamp 2 to 1 for [0,1]'); + t.equal(clamp([0,1], 0.5), 0.5, 'should not clamp 0.5 for [0,1]'); + t.equal(clamp([-1,1], -2), -1, 'should clamp -2 to -1 for [-1,1]'); + t.equal(clamp([0,10], 11), 10, 'should clamp 11 to 10 for [0,10]'); + t.equal(clamp([0,0], 1), 0, 'should clamp 1 to 0 for [0,0]'); + t.end(); +}); + test('dataUtils -> preciseRound', t => { t.equal(preciseRound(1.234, 2), '1.23', 'should round 1.234 correctly'); t.equal(preciseRound(13.234, 0), '13', 'should round 13.234 correctly');