From f4fc8ec2c4ef9455a132dc87f08c01c98e91baf1 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Fri, 26 May 2023 16:04:49 +0300 Subject: [PATCH] Added initial chart y-axis animation without x-axis. --- .../SourceFiles/statistics/chart_widget.cpp | 73 +++++++++++++++---- .../SourceFiles/statistics/chart_widget.h | 7 ++ .../statistics/linear_chart_view.cpp | 42 ++++++++++- .../statistics/linear_chart_view.h | 4 +- 4 files changed, 108 insertions(+), 18 deletions(-) diff --git a/Telegram/SourceFiles/statistics/chart_widget.cpp b/Telegram/SourceFiles/statistics/chart_widget.cpp index 17be748d04..440a334c90 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.cpp +++ b/Telegram/SourceFiles/statistics/chart_widget.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "statistics/linear_chart_view.h" #include "ui/abstract_button.h" +#include "ui/effects/animation_value_f.h" #include "ui/rect.h" #include "styles/style_boxes.h" @@ -132,6 +133,10 @@ ChartWidget::Footer::Footer(not_null parent) _start.leftLimit, _start.rightLimit); side->move(nextX, side->y()); + _xPercentageLimitsChange.fire({ + .min = _left->x() / float64(width()), + .max = rect::right(_right) / float64(width()), + }); } break; case QEvent::MouseButtonPress: { _start.x = pos.x(); @@ -181,25 +186,26 @@ ChartWidget::ChartWidget(not_null parent) Statistic::PaintLinearChartView( p, _chartData, + {}, limits, + 1., _footer->rect()); } }, _footer->lifetime()); - _footer->xPercentageLimitsChange( - ) | rpl::start_with_next([=](Limits xPercentageLimits) { - _xPercentageLimits = { - .min = *ranges::lower_bound( - _chartData.xPercentage, - xPercentageLimits.min), - .max = *ranges::lower_bound( - _chartData.xPercentage, - xPercentageLimits.max), - }; + + _xPercentage.animation.init([=] { + const auto progress = (crl::now() - _xPercentage.lastUserInteracted) + / float64(400.); + _xPercentage.progress = progress; + if (progress > 1.) { + _xPercentage.animation.stop(); + _xPercentage.was = _xPercentage.now; + } const auto startXIndex = _chartData.findStartIndex( - _xPercentageLimits.min); + _xPercentage.now.min); const auto endXIndex = _chartData.findEndIndex( startXIndex, - _xPercentageLimits.max); + _xPercentage.now.max); setHeightLimits( { float64(FindMinValue(_chartData, startXIndex, endXIndex)), @@ -207,6 +213,41 @@ ChartWidget::ChartWidget(not_null parent) }, false); update(); + }); + + _footer->xPercentageLimitsChange( + ) | rpl::start_with_next([=](Limits xPercentageLimits) { + if (!_xPercentage.animation.animating()) { + _xPercentage.animation.start(); + // _xPercentage.was = base::take(_xPercentage.now); + } + _xPercentage.now = xPercentageLimits; + _xPercentage.lastUserInteracted = crl::now(); + // _xPercentage.animation.stop(); + // const auto was = _xPercentageLimits; + // const auto now = xPercentageLimits; + // _xPercentage.animation.start([=](float64 value) { + // _xPercentageLimits = { + // .min = *ranges::lower_bound( + // _chartData.xPercentage, + // anim::interpolateF(was.min, now.min, value)), + // .max = *ranges::lower_bound( + // _chartData.xPercentage, + // anim::interpolateF(was.max, now.max, value)), + // }; + // const auto startXIndex = _chartData.findStartIndex( + // _xPercentageLimits.min); + // const auto endXIndex = _chartData.findEndIndex( + // startXIndex, + // _xPercentageLimits.max); + // setHeightLimits( + // { + // float64(FindMinValue(_chartData, startXIndex, endXIndex)), + // float64(FindMaxValue(_chartData, startXIndex, endXIndex)), + // }, + // false); + // update(); + // }, 0., 1., 400); }, _footer->lifetime()); resize(width(), st::confirmMaxHeight + st::countryRowHeight * 2); } @@ -219,6 +260,10 @@ void ChartWidget::setChartData(Data::StatisticalChart chartData) { .min = _chartData.xPercentage.front(), .max = _chartData.xPercentage.back(), }; + _xPercentage.now = { + .min = _chartData.xPercentage.front(), + .max = _chartData.xPercentage.back(), + }; const auto startXIndex = _chartData.findStartIndex( _xPercentageLimits.min); const auto endXIndex = _chartData.findEndIndex( @@ -255,7 +300,9 @@ void ChartWidget::paintEvent(QPaintEvent *e) { Statistic::PaintLinearChartView( p, _chartData, - _xPercentageLimits, + _xPercentage.was, + _xPercentage.now, + _xPercentage.progress, chartRect); } diff --git a/Telegram/SourceFiles/statistics/chart_widget.h b/Telegram/SourceFiles/statistics/chart_widget.h index b53c598b3c..7c1cc261a3 100644 --- a/Telegram/SourceFiles/statistics/chart_widget.h +++ b/Telegram/SourceFiles/statistics/chart_widget.h @@ -41,6 +41,13 @@ private: Limits _startFromH; Limits _xPercentageLimits; + struct { + Limits was; + Limits now; + Ui::Animations::Basic animation; + crl::time lastUserInteracted = 0; + float64 progress = 0.; + } _xPercentage; float64 _minMaxUpdateStep = 0.; diff --git a/Telegram/SourceFiles/statistics/linear_chart_view.cpp b/Telegram/SourceFiles/statistics/linear_chart_view.cpp index 5fb760c56c..2aa9e008ac 100644 --- a/Telegram/SourceFiles/statistics/linear_chart_view.cpp +++ b/Telegram/SourceFiles/statistics/linear_chart_view.cpp @@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL #include "data/data_statistics.h" #include "statistics/statistics_common.h" +#include "ui/effects/animation_value_f.h" #include "styles/style_boxes.h" namespace Statistic { @@ -16,12 +17,16 @@ namespace Statistic { void PaintLinearChartView( QPainter &p, const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, + const Limits &xPercentageLimitsWas, + const Limits &xPercentageLimitsNow, + float64 progress, const QRect &rect) { const auto offset = 0; const auto currentMinHeight = rect.y(); // const auto currentMaxHeight = rect.height() + rect.y(); // + const auto xPercentageLimits = xPercentageLimitsNow; + for (const auto &line : chartData.lines) { const auto additionalP = (chartData.xPercentage.size() < 2) ? 0. @@ -42,14 +47,43 @@ void PaintLinearChartView( int(chartData.xPercentage.size() - 1), endXIndex + additionalPoints); + auto minY = std::numeric_limits::max(); + auto maxY = 0.; + auto minYIndex = 0; + auto maxYIndex = 0; + const auto tempXPercentage = Limits{ + .min = *ranges::lower_bound( + chartData.xPercentage, + anim::interpolateF(xPercentageLimitsWas.min, xPercentageLimitsNow.min, progress)), + .max = *ranges::lower_bound( + chartData.xPercentage, + anim::interpolateF(xPercentageLimitsWas.max, xPercentageLimitsNow.max, progress)), + }; + for (auto i = 0; i < chartData.xPercentage.size(); i++) { + if (chartData.xPercentage[i] == tempXPercentage.min) { + minYIndex = i; + } + if (chartData.xPercentage[i] == tempXPercentage.max) { + maxYIndex = i; + } + } + for (auto i = minYIndex; i < maxYIndex; i++) { + if (line.y[i] > maxY) { + maxY = line.y[i]; + } + if (line.y[i] < minY) { + minY = line.y[i]; + } + } + for (auto i = localStart; i <= localEnd; i++) { if (line.y[i] < 0) { continue; } - const auto xPoint = chartData.xPercentage[i] * rect.width() + const auto xPoint = ((chartData.xPercentage[i] - xPercentageLimits.min) / (xPercentageLimits.max - xPercentageLimits.min)) * rect.width() - offset; - const auto yPercentage = (line.y[i] - line.minValue) - / float64(line.maxValue - line.minValue); + const auto yPercentage = (line.y[i] - minY) + / float64(maxY - minY); const auto yPoint = rect.y() + (1. - yPercentage) * rect.height(); if (first) { first = false; diff --git a/Telegram/SourceFiles/statistics/linear_chart_view.h b/Telegram/SourceFiles/statistics/linear_chart_view.h index f9414dbb58..0b943d4f00 100644 --- a/Telegram/SourceFiles/statistics/linear_chart_view.h +++ b/Telegram/SourceFiles/statistics/linear_chart_view.h @@ -18,7 +18,9 @@ struct Limits; void PaintLinearChartView( QPainter &p, const Data::StatisticalChart &chartData, - const Limits &xPercentageLimits, + const Limits &xPercentageLimitsWas, + const Limits &xPercentageLimitsNow, + float64 progress, const QRect &rect); } // namespace Statistic