From c8e95f72972eb8e0c4089cbf4c7b437527db7416 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 15 Jul 2023 01:56:47 +0300 Subject: [PATCH] Improved y-axis animation again to look much better. --- .../SourceFiles/statistics/chart_widget.cpp | 121 +++++++++--------- .../SourceFiles/statistics/chart_widget.h | 17 ++- 2 files changed, 74 insertions(+), 64 deletions(-) diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 010df238c3..bcff2b920d 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -27,7 +27,7 @@ namespace Statistic { namespace { constexpr auto kHeightLimitsUpdateTimeout = crl::time(320); -constexpr auto kExpandingDelay = crl::time(100); +constexpr auto kExpandingDelay = crl::time(1); inline float64 InterpolationRatio(float64 from, float64 to, float64 result) { return (result - from) / (to - from); @@ -516,7 +516,11 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits( maxValueFull = std::max(l.maxValue, maxValueFull); minValueFull = std::min(l.minValue, minValueFull); } + _previousFullHeightLimits = _finalHeightLimits; _finalHeightLimits = { float64(minValue), float64(maxValue) }; + if (!_previousFullHeightLimits.max) { + _previousFullHeightLimits = _finalHeightLimits; + } if (!chartLinesViewContext.isFinished()) { _animationValueFooterHeightMin = anim::value( _animationValueFooterHeightMin.current(), @@ -539,30 +543,46 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits( _finalHeightLimits.max); { - const auto currentDelta = _animationValueHeightMax.current() - - _animationValueHeightMin.current(); - auto k = currentDelta + const auto previousDelta = _previousFullHeightLimits.max + - _previousFullHeightLimits.min; + auto k = previousDelta / float64(_finalHeightLimits.max - _finalHeightLimits.min); if (k > 1.) { k = 1. / k; } - constexpr auto kDtHeightSpeed1 = 0.03 / 2; - constexpr auto kDtHeightSpeed2 = 0.03 / 2; - constexpr auto kDtHeightSpeed3 = 0.045 / 2; + constexpr auto kDtHeightSpeed1 = 0.03 * 2; + constexpr auto kDtHeightSpeed2 = 0.03 * 2; + constexpr auto kDtHeightSpeed3 = 0.045 * 2; + constexpr auto kDtHeightSpeedFilter = kDtHeightSpeed1 / 1.2; constexpr auto kDtHeightSpeedThreshold1 = 0.7; constexpr auto kDtHeightSpeedThreshold2 = 0.1; constexpr auto kDtHeightInstantThreshold = 0.97; - _dtHeightSpeed = (k > kDtHeightSpeedThreshold1) + if (k < 1.) { + auto &alpha = _animationValueHeightAlpha; + alpha = anim::value( + (alpha.current() == alpha.to()) ? 0. : alpha.current(), + 1.); + _dtHeight.currentAlpha = 0.; + _addHorizontalLineRequests.fire({}); + } + _dtHeight.speed = (!chartLinesViewContext.isFinished()) + ? kDtHeightSpeedFilter + : (k > kDtHeightSpeedThreshold1) ? kDtHeightSpeed1 : (k < kDtHeightSpeedThreshold2) ? kDtHeightSpeed2 : kDtHeightSpeed3; if (k < kDtHeightInstantThreshold) { - _dtCurrent = { 0., 0. }; + _dtHeight.current = { 0., 0. }; } } } +auto ChartWidget::ChartAnimationController::addHorizontalLineRequests() const +-> rpl::producer<> { + return _addHorizontalLineRequests.events(); +} + void ChartWidget::ChartAnimationController::start() { if (!_animation.animating()) { _animation.start(); @@ -577,15 +597,10 @@ void ChartWidget::ChartAnimationController::finish() { _animationValueHeightMax.finish(); _animationValueFooterHeightMin.finish(); _animationValueFooterHeightMax.finish(); - _animValueYAlpha.finish(); + _animationValueHeightAlpha.finish(); _benchmark = {}; } -void ChartWidget::ChartAnimationController::resetAlpha() { - _alphaAnimationStartedAt = 0; - _animValueYAlpha = anim::value(0., 1.); -} - void ChartWidget::ChartAnimationController::restartBottomLineAlpha() { _bottomLineAlphaAnimationStartedAt = crl::now(); _animValueBottomLineAlpha = anim::value(0., 1.); @@ -603,15 +618,6 @@ void ChartWidget::ChartAnimationController::tick( constexpr auto kXExpandingDuration = 200.; constexpr auto kAlphaExpandingDuration = 200.; - if (!_heightAnimationStarted - && ((now - _lastUserInteracted) >= kExpandingDelay)) { - _heightAnimationStarts.fire({}); - _heightAnimationStarted = true; - } - if (!_alphaAnimationStartedAt) { - _alphaAnimationStartedAt = now; - } - { constexpr auto kIdealFPS = float64(60); const auto currentFPS = _benchmark.lastTickedAt @@ -627,16 +633,15 @@ void ChartWidget::ChartAnimationController::tick( const auto k = (kIdealFPS / currentFPS) // Speed up to reduce ugly frames count. * (_benchmark.lastFPSSlow ? 2. : 1.); - _dtCurrent.min = std::min(_dtCurrent.min + _dtHeightSpeed * k, 1.); - _dtCurrent.max = std::min(_dtCurrent.max + _dtHeightSpeed * k, 1.); + const auto speed = _dtHeight.speed * k; + _dtHeight.current.min = std::min(_dtHeight.current.min + speed, 1.); + _dtHeight.current.max = std::min(_dtHeight.current.max + speed, 1.); + _dtHeight.currentAlpha = std::min(_dtHeight.currentAlpha + speed, 1.); } const auto dtX = std::min( (now - _animation.started()) / kXExpandingDuration, 1.); - const auto dtAlpha = std::min( - (now - _alphaAnimationStartedAt) / kAlphaExpandingDuration, - 1.); const auto dtBottomLineAlpha = std::min( (now - _bottomLineAlphaAnimationStartedAt) / kAlphaExpandingDuration, 1.); @@ -649,20 +654,26 @@ void ChartWidget::ChartAnimationController::tick( && isFinished(_animationValueXMax); const auto yFinished = isFinished(_animationValueHeightMin) && isFinished(_animationValueHeightMax); - const auto alphaFinished = isFinished(_animValueYAlpha); + const auto alphaFinished = isFinished(_animationValueHeightAlpha) + && isFinished(_animationValueHeightMax); const auto bottomLineAlphaFinished = isFinished( _animValueBottomLineAlpha); + const auto footerMinFinished = isFinished(_animationValueFooterHeightMin); + const auto footerMaxFinished = isFinished(_animationValueFooterHeightMax); + chartLinesViewContext.tick(now); if (xFinished && yFinished && alphaFinished && bottomLineAlphaFinished + && footerMinFinished + && footerMaxFinished && chartLinesViewContext.isFinished()) { const auto &lines = horizontalLines.back().lines; - if ((lines.front().absoluteValue == _animationValueHeightMin.to()) - && lines.back().absoluteValue == _animationValueHeightMax.to()) { + if ((_finalHeightLimits.min == _animationValueHeightMin.to()) + && _finalHeightLimits.max == _animationValueHeightMax.to()) { _animation.stop(); _benchmark = {}; } @@ -682,15 +693,12 @@ void ChartWidget::ChartAnimationController::tick( dtBottomLineAlpha, anim::easeInCubic); } - if (_heightAnimationStarted) { - _animationValueHeightMin.update(_dtCurrent.min, anim::easeInCubic); - _animationValueHeightMax.update(_dtCurrent.max, anim::easeInCubic); - _animValueYAlpha.update(dtAlpha, anim::easeInCubic); - _animationValueFooterHeightMin.update( - _dtCurrent.min, + if (!yFinished) { + _animationValueHeightMin.update( + _dtHeight.current.min, anim::easeInCubic); - _animationValueFooterHeightMax.update( - _dtCurrent.max, + _animationValueHeightMax.update( + _dtHeight.current.max, anim::easeInCubic); for (auto &horizontalLine : horizontalLines) { @@ -699,9 +707,22 @@ void ChartWidget::ChartAnimationController::tick( _animationValueHeightMin.current()); } } + if (!footerMinFinished) { + _animationValueFooterHeightMin.update( + _dtHeight.current.min, + anim::sineInOut); + } + if (!footerMaxFinished) { + _animationValueFooterHeightMax.update( + _dtHeight.current.max, + anim::sineInOut); + } - if (dtAlpha >= 0. && dtAlpha <= 1.) { - const auto value = _animValueYAlpha.current(); + if (!alphaFinished) { + _animationValueHeightAlpha.update( + _dtHeight.currentAlpha, + anim::easeInCubic); + const auto value = _animationValueHeightAlpha.current(); for (auto &horizontalLine : horizontalLines) { horizontalLine.alpha = horizontalLine.fixedAlpha * (1. - value); @@ -732,11 +753,6 @@ void ChartWidget::ChartAnimationController::tick( dateLines.push_back(data); } } - - if (yFinished && alphaFinished) { - _alphaAnimationStartedAt = 0; - _heightAnimationStarted = false; - } } Limits ChartWidget::ChartAnimationController::currentXLimits() const { @@ -799,11 +815,6 @@ bool ChartWidget::ChartAnimationController::isFPSSlow() const { return _benchmark.lastFPSSlow; } -auto ChartWidget::ChartAnimationController::heightAnimationStarts() const --> rpl::producer<> { - return _heightAnimationStarts.events(); -} - ChartWidget::ChartWidget(not_null parent) : Ui::RpWidget(parent) , _chartArea(base::make_unique_q(this)) @@ -1074,11 +1085,8 @@ void ChartWidget::setupFooter() { } }); - rpl::merge( - _animationController.heightAnimationStarts(), - _footer->userInteractionFinished() + _animationController.addHorizontalLineRequests( ) | rpl::start_with_next([=] { - _animationController.resetAlpha(); addHorizontalLine(_animationController.finalHeightLimits(), true); _animationController.start(); }, _footer->lifetime()); @@ -1097,7 +1105,6 @@ void ChartWidget::setupFooter() { return; } _lastHeightLimitsChanged = now; - _animationController.resetAlpha(); addHorizontalLine(_animationController.finalHeightLimits(), true); }, _footer->lifetime()); } diff --git a/Telegram/SourceFiles/statistics/chart_widget.h b/Telegram/SourceFiles/statistics/chart_widget.h index 96610443cf..981ea5496a 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.h +++ b/Telegram/SourceFiles/statistics/chart_widget.h @@ -74,15 +74,13 @@ private: [[nodiscard]] bool footerAnimating() const; [[nodiscard]] bool isFPSSlow() const; - [[nodiscard]] rpl::producer<> heightAnimationStarts() const; + [[nodiscard]] rpl::producer<> addHorizontalLineRequests() const; private: Ui::Animations::Basic _animation; crl::time _lastUserInteracted = 0; - crl::time _alphaAnimationStartedAt = 0; crl::time _bottomLineAlphaAnimationStartedAt = 0; - bool _heightAnimationStarted = false; anim::value _animationValueXMin; anim::value _animationValueXMax; @@ -92,22 +90,27 @@ private: anim::value _animationValueFooterHeightMin; anim::value _animationValueFooterHeightMax; - anim::value _animValueYAlpha; + anim::value _animationValueHeightAlpha; anim::value _animValueBottomLineAlpha; Limits _finalHeightLimits; Limits _currentXIndices; - float _dtHeightSpeed = 0.; - Limits _dtCurrent; + struct { + float speed = 0.; + Limits current; + + float64 currentAlpha = 0.; + } _dtHeight; + Limits _previousFullHeightLimits; struct { crl::time lastTickedAt = 0; bool lastFPSSlow = false; } _benchmark; - rpl::event_stream<> _heightAnimationStarts; + rpl::event_stream<> _addHorizontalLineRequests; };