Reduced redundant calculations of animation in chart widget.

This commit is contained in:
23rd 2023-07-01 12:18:33 +03:00 committed by John Preston
parent 77695091b3
commit d603f4de51
2 changed files with 79 additions and 87 deletions

View file

@ -44,6 +44,19 @@ constexpr auto kHeightLimitsUpdateTimeout = crl::time(320);
return minValue; return minValue;
} }
[[nodiscard]] Limits FindHeightLimitsBetweenXLimits(
Data::StatisticalChart &chartData,
const Limits &xPercentageLimits) {
const auto startXIndex = chartData.findStartIndex(xPercentageLimits.min);
const auto endXIndex = chartData.findEndIndex(
startXIndex,
xPercentageLimits.max);
return Limits{
float64(FindMinValue(chartData, startXIndex, endXIndex)),
float64(FindMaxValue(chartData, startXIndex, endXIndex)),
};
}
void PaintHorizontalLines( void PaintHorizontalLines(
QPainter &p, QPainter &p,
const ChartHorizontalLinesData &horizontalLine, const ChartHorizontalLinesData &horizontalLine,
@ -84,6 +97,9 @@ public:
[[nodiscard]] rpl::producer<Limits> xPercentageLimitsChange() const; [[nodiscard]] rpl::producer<Limits> xPercentageLimitsChange() const;
[[nodiscard]] rpl::producer<> userInteractionFinished() const; [[nodiscard]] rpl::producer<> userInteractionFinished() const;
void setFullHeightLimits(Limits limits);
[[nodiscard]] const Limits &fullHeightLimits() const;
private: private:
not_null<Ui::AbstractButton*> _left; not_null<Ui::AbstractButton*> _left;
not_null<Ui::AbstractButton*> _right; not_null<Ui::AbstractButton*> _right;
@ -91,6 +107,8 @@ private:
rpl::event_stream<Limits> _xPercentageLimitsChange; rpl::event_stream<Limits> _xPercentageLimitsChange;
rpl::event_stream<> _userInteractionFinished; rpl::event_stream<> _userInteractionFinished;
Limits _fullHeightLimits;
struct { struct {
int x = 0; int x = 0;
int leftLimit = 0; int leftLimit = 0;
@ -192,6 +210,14 @@ rpl::producer<> ChartWidget::Footer::userInteractionFinished() const {
return _userInteractionFinished.events(); return _userInteractionFinished.events();
} }
void ChartWidget::Footer::setFullHeightLimits(Limits limits) {
_fullHeightLimits = std::move(limits);
}
const Limits &ChartWidget::Footer::fullHeightLimits() const {
return _fullHeightLimits;
}
ChartWidget::ChartAnimationController::ChartAnimationController( ChartWidget::ChartAnimationController::ChartAnimationController(
Fn<void()> &&updateCallback) Fn<void()> &&updateCallback)
: _animation(std::move(updateCallback)) { : _animation(std::move(updateCallback)) {
@ -201,35 +227,29 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
Data::StatisticalChart &chartData, Data::StatisticalChart &chartData,
Limits xPercentageLimits, Limits xPercentageLimits,
crl::time now) { crl::time now) {
if ((_animValueXMin.to() == xPercentageLimits.min) if ((_animationValueXMin.to() == xPercentageLimits.min)
&& (_animValueXMax.to() == xPercentageLimits.max)) { && (_animationValueXMax.to() == xPercentageLimits.max)) {
return; return;
} }
start(); start();
_animValueXMin.start(xPercentageLimits.min); _animationValueXMin.start(xPercentageLimits.min);
_animValueXMax.start(xPercentageLimits.max); _animationValueXMax.start(xPercentageLimits.max);
_lastUserInteracted = now; _lastUserInteracted = now;
{ _finalHeightLimits = FindHeightLimitsBetweenXLimits(
const auto startXIndex = chartData.findStartIndex( chartData,
_animValueXMin.to()); { _animationValueXMin.to(), _animationValueXMax.to() });
const auto endXIndex = chartData.findEndIndex( _animationValueHeightMin = anim::value(
startXIndex, _animationValueHeightMin.current(),
_animValueXMax.to());
_finalHeightLimits = {
float64(FindMinValue(chartData, startXIndex, endXIndex)),
float64(FindMaxValue(chartData, startXIndex, endXIndex)),
};
}
_animValueYMin = anim::value(
_animValueYMin.current(),
_finalHeightLimits.min); _finalHeightLimits.min);
_animValueYMax = anim::value( _animationValueHeightMax = anim::value(
_animValueYMax.current(), _animationValueHeightMax.current(),
_finalHeightLimits.max); _finalHeightLimits.max);
{ {
auto k = (_animValueYMax.current() - _animValueYMin.current()) const auto currentDelta = _animationValueHeightMax.current()
- _animationValueHeightMin.current();
auto k = currentDelta
/ float64(_finalHeightLimits.max - _finalHeightLimits.min); / float64(_finalHeightLimits.max - _finalHeightLimits.min);
if (k > 1.) { if (k > 1.) {
k = 1. / k; k = 1. / k;
@ -240,7 +260,7 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
constexpr auto kDtHeightSpeedThreshold1 = 0.7; constexpr auto kDtHeightSpeedThreshold1 = 0.7;
constexpr auto kDtHeightSpeedThreshold2 = 0.1; constexpr auto kDtHeightSpeedThreshold2 = 0.1;
constexpr auto kDtHeightInstantThreshold = 0.97; constexpr auto kDtHeightInstantThreshold = 0.97;
_dtYSpeed = (k > kDtHeightSpeedThreshold1) _dtHeightSpeed = (k > kDtHeightSpeedThreshold1)
? kDtHeightSpeed1 ? kDtHeightSpeed1
: (k < kDtHeightSpeedThreshold2) : (k < kDtHeightSpeedThreshold2)
? kDtHeightSpeed2 ? kDtHeightSpeed2
@ -259,10 +279,10 @@ void ChartWidget::ChartAnimationController::start() {
void ChartWidget::ChartAnimationController::finish() { void ChartWidget::ChartAnimationController::finish() {
_animation.stop(); _animation.stop();
_animValueXMin.finish(); _animationValueXMin.finish();
_animValueXMax.finish(); _animationValueXMax.finish();
_animValueYMin.finish(); _animationValueHeightMin.finish();
_animValueYMax.finish(); _animationValueHeightMax.finish();
_animValueYAlpha.finish(); _animValueYAlpha.finish();
} }
@ -290,8 +310,8 @@ void ChartWidget::ChartAnimationController::tick(
_alphaAnimationStartedAt = now; _alphaAnimationStartedAt = now;
} }
_dtCurrent.min = std::min(_dtCurrent.min + _dtYSpeed, 1.); _dtCurrent.min = std::min(_dtCurrent.min + _dtHeightSpeed, 1.);
_dtCurrent.max = std::min(_dtCurrent.max + _dtYSpeed, 1.); _dtCurrent.max = std::min(_dtCurrent.max + _dtHeightSpeed, 1.);
const auto dtX = std::min( const auto dtX = std::min(
(now - _animation.started()) / kXExpandingDuration, (now - _animation.started()) / kXExpandingDuration,
@ -304,35 +324,35 @@ void ChartWidget::ChartAnimationController::tick(
return anim.current() == anim.to(); return anim.current() == anim.to();
}; };
const auto xFinished = isFinished(_animValueXMin) const auto xFinished = isFinished(_animationValueXMin)
&& isFinished(_animValueXMax); && isFinished(_animationValueXMax);
const auto yFinished = isFinished(_animValueYMin) const auto yFinished = isFinished(_animationValueHeightMin)
&& isFinished(_animValueYMax); && isFinished(_animationValueHeightMax);
const auto alphaFinished = isFinished(_animValueYAlpha); const auto alphaFinished = isFinished(_animValueYAlpha);
if (xFinished && yFinished && alphaFinished) { if (xFinished && yFinished && alphaFinished) {
const auto &lines = horizontalLines.back().lines; const auto &lines = horizontalLines.back().lines;
if ((lines.front().absoluteValue == _animValueYMin.to()) if ((lines.front().absoluteValue == _animationValueHeightMin.to())
&& (lines.back().absoluteValue == _animValueYMax.to())) { && lines.back().absoluteValue == _animationValueHeightMax.to()) {
_animation.stop(); _animation.stop();
} }
} }
if (xFinished) { if (xFinished) {
_animValueXMin.finish(); _animationValueXMin.finish();
_animValueXMax.finish(); _animationValueXMax.finish();
} else { } else {
_animValueXMin.update(dtX, anim::linear); _animationValueXMin.update(dtX, anim::linear);
_animValueXMax.update(dtX, anim::linear); _animationValueXMax.update(dtX, anim::linear);
} }
if (_heightAnimationStarted) { if (_heightAnimationStarted) {
_animValueYMin.update(_dtCurrent.min, anim::easeInCubic); _animationValueHeightMin.update(_dtCurrent.min, anim::easeInCubic);
_animValueYMax.update(_dtCurrent.max, anim::easeInCubic); _animationValueHeightMax.update(_dtCurrent.max, anim::easeInCubic);
_animValueYAlpha.update(dtAlpha, anim::easeInCubic); _animValueYAlpha.update(dtAlpha, anim::easeInCubic);
for (auto &horizontalLine : horizontalLines) { for (auto &horizontalLine : horizontalLines) {
horizontalLine.computeRelative( horizontalLine.computeRelative(
_animValueYMax.current(), _animationValueHeightMax.current(),
_animValueYMin.current()); _animationValueHeightMin.current());
} }
} }
@ -362,11 +382,14 @@ void ChartWidget::ChartAnimationController::tick(
} }
Limits ChartWidget::ChartAnimationController::currentXLimits() const { Limits ChartWidget::ChartAnimationController::currentXLimits() const {
return { _animValueXMin.current(), _animValueXMax.current() }; return { _animationValueXMin.current(), _animationValueXMax.current() };
} }
Limits ChartWidget::ChartAnimationController::currentHeightLimits() const { Limits ChartWidget::ChartAnimationController::currentHeightLimits() const {
return { _animValueYMin.current(), _animValueYMax.current() }; return {
_animationValueHeightMin.current(),
_animationValueHeightMax.current(),
};
} }
Limits ChartWidget::ChartAnimationController::finalHeightLimits() const { Limits ChartWidget::ChartAnimationController::finalHeightLimits() const {
@ -391,22 +414,16 @@ ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
st::countryRowHeight); st::countryRowHeight);
}, _footer->lifetime()); }, _footer->lifetime());
_footer->paintRequest( _footer->paintRequest(
) | rpl::start_with_next([=, limits = Limits{ 0., 1. }] { ) | rpl::start_with_next([=, fullXLimits = Limits{ 0., 1. }] {
auto p = QPainter(_footer.get()); auto p = QPainter(_footer.get());
if (_chartData) { if (_chartData) {
const auto startXIndex2 = 0;
const auto endXIndex2 = int(_chartData.xPercentage.size() - 1);
const auto limitsY = Limits{
float64(FindMinValue(_chartData, startXIndex2, endXIndex2)),
float64(FindMaxValue(_chartData, startXIndex2, endXIndex2)),
};
p.fillRect(_footer->rect(), st::boxBg); p.fillRect(_footer->rect(), st::boxBg);
Statistic::PaintLinearChartView( Statistic::PaintLinearChartView(
p, p,
_chartData, _chartData,
limits, fullXLimits,
limitsY, _footer->fullHeightLimits(),
_footer->rect()); _footer->rect());
} }
}, _footer->lifetime()); }, _footer->lifetime());
@ -438,7 +455,11 @@ ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
} }
void ChartWidget::setChartData(Data::StatisticalChart chartData) { void ChartWidget::setChartData(Data::StatisticalChart chartData) {
_chartData = chartData; _chartData = std::move(chartData);
_footer->setFullHeightLimits(FindHeightLimitsBetweenXLimits(
_chartData,
{ _chartData.xPercentage.front(), _chartData.xPercentage.back() }));
_animationController.setXPercentageLimits( _animationController.setXPercentageLimits(
_chartData, _chartData,

View file

@ -57,16 +57,16 @@ private:
crl::time _alphaAnimationStartedAt = 0; crl::time _alphaAnimationStartedAt = 0;
bool _heightAnimationStarted = false; bool _heightAnimationStarted = false;
anim::value _animValueXMin; anim::value _animationValueXMin;
anim::value _animValueXMax; anim::value _animationValueXMax;
anim::value _animValueYMin; anim::value _animationValueHeightMin;
anim::value _animValueYMax; anim::value _animationValueHeightMax;
anim::value _animValueYAlpha; anim::value _animValueYAlpha;
Limits _finalHeightLimits; Limits _finalHeightLimits;
float _dtYSpeed = 0.; float _dtHeightSpeed = 0.;
Limits _dtCurrent; Limits _dtCurrent;
rpl::event_stream<> _heightAnimationStarts; rpl::event_stream<> _heightAnimationStarts;
@ -78,40 +78,11 @@ private:
bool _useMinHeight = false; bool _useMinHeight = false;
Limits _currentHeight;
Limits _animateToHeight;
Limits _thresholdHeight = { -1, 0 };
Limits _startFrom;
Limits _startFromH;
Limits _xPercentageLimits;
// struct {
// Ui::Animations::Basic animation;
// crl::time lastUserInteracted = 0;
// crl::time yAnimationStartedAt = 0;
// crl::time alphaAnimationStartedAt = 0;
// anim::value animValueXMin;
// anim::value animValueXMax;
// anim::value animValueYMin;
// anim::value animValueYMax;
// anim::value animValueYAlpha;
// float dtYSpeed = 0.;
// Limits dtCurrent;
// } _xPercentage;
ChartAnimationController _animationController; ChartAnimationController _animationController;
float64 _minMaxUpdateStep = 0.;
crl::time _lastHeightLimitsChanged = 0; crl::time _lastHeightLimitsChanged = 0;
std::vector<ChartHorizontalLinesData> _horizontalLines; std::vector<ChartHorizontalLinesData> _horizontalLines;
Ui::Animations::Simple _heightLimitsAnimation;
}; };
} // namespace Statistic } // namespace Statistic