mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-07 15:43:55 +02:00
Improved y-axis animation again to look much better.
This commit is contained in:
parent
b1ed8cd1b1
commit
c8e95f7297
2 changed files with 74 additions and 64 deletions
|
@ -27,7 +27,7 @@ namespace Statistic {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kHeightLimitsUpdateTimeout = crl::time(320);
|
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) {
|
inline float64 InterpolationRatio(float64 from, float64 to, float64 result) {
|
||||||
return (result - from) / (to - from);
|
return (result - from) / (to - from);
|
||||||
|
@ -516,7 +516,11 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
|
||||||
maxValueFull = std::max(l.maxValue, maxValueFull);
|
maxValueFull = std::max(l.maxValue, maxValueFull);
|
||||||
minValueFull = std::min(l.minValue, minValueFull);
|
minValueFull = std::min(l.minValue, minValueFull);
|
||||||
}
|
}
|
||||||
|
_previousFullHeightLimits = _finalHeightLimits;
|
||||||
_finalHeightLimits = { float64(minValue), float64(maxValue) };
|
_finalHeightLimits = { float64(minValue), float64(maxValue) };
|
||||||
|
if (!_previousFullHeightLimits.max) {
|
||||||
|
_previousFullHeightLimits = _finalHeightLimits;
|
||||||
|
}
|
||||||
if (!chartLinesViewContext.isFinished()) {
|
if (!chartLinesViewContext.isFinished()) {
|
||||||
_animationValueFooterHeightMin = anim::value(
|
_animationValueFooterHeightMin = anim::value(
|
||||||
_animationValueFooterHeightMin.current(),
|
_animationValueFooterHeightMin.current(),
|
||||||
|
@ -539,30 +543,46 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
|
||||||
_finalHeightLimits.max);
|
_finalHeightLimits.max);
|
||||||
|
|
||||||
{
|
{
|
||||||
const auto currentDelta = _animationValueHeightMax.current()
|
const auto previousDelta = _previousFullHeightLimits.max
|
||||||
- _animationValueHeightMin.current();
|
- _previousFullHeightLimits.min;
|
||||||
auto k = currentDelta
|
auto k = previousDelta
|
||||||
/ float64(_finalHeightLimits.max - _finalHeightLimits.min);
|
/ float64(_finalHeightLimits.max - _finalHeightLimits.min);
|
||||||
if (k > 1.) {
|
if (k > 1.) {
|
||||||
k = 1. / k;
|
k = 1. / k;
|
||||||
}
|
}
|
||||||
constexpr auto kDtHeightSpeed1 = 0.03 / 2;
|
constexpr auto kDtHeightSpeed1 = 0.03 * 2;
|
||||||
constexpr auto kDtHeightSpeed2 = 0.03 / 2;
|
constexpr auto kDtHeightSpeed2 = 0.03 * 2;
|
||||||
constexpr auto kDtHeightSpeed3 = 0.045 / 2;
|
constexpr auto kDtHeightSpeed3 = 0.045 * 2;
|
||||||
|
constexpr auto kDtHeightSpeedFilter = kDtHeightSpeed1 / 1.2;
|
||||||
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;
|
||||||
_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
|
? kDtHeightSpeed1
|
||||||
: (k < kDtHeightSpeedThreshold2)
|
: (k < kDtHeightSpeedThreshold2)
|
||||||
? kDtHeightSpeed2
|
? kDtHeightSpeed2
|
||||||
: kDtHeightSpeed3;
|
: kDtHeightSpeed3;
|
||||||
if (k < kDtHeightInstantThreshold) {
|
if (k < kDtHeightInstantThreshold) {
|
||||||
_dtCurrent = { 0., 0. };
|
_dtHeight.current = { 0., 0. };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto ChartWidget::ChartAnimationController::addHorizontalLineRequests() const
|
||||||
|
-> rpl::producer<> {
|
||||||
|
return _addHorizontalLineRequests.events();
|
||||||
|
}
|
||||||
|
|
||||||
void ChartWidget::ChartAnimationController::start() {
|
void ChartWidget::ChartAnimationController::start() {
|
||||||
if (!_animation.animating()) {
|
if (!_animation.animating()) {
|
||||||
_animation.start();
|
_animation.start();
|
||||||
|
@ -577,15 +597,10 @@ void ChartWidget::ChartAnimationController::finish() {
|
||||||
_animationValueHeightMax.finish();
|
_animationValueHeightMax.finish();
|
||||||
_animationValueFooterHeightMin.finish();
|
_animationValueFooterHeightMin.finish();
|
||||||
_animationValueFooterHeightMax.finish();
|
_animationValueFooterHeightMax.finish();
|
||||||
_animValueYAlpha.finish();
|
_animationValueHeightAlpha.finish();
|
||||||
_benchmark = {};
|
_benchmark = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChartWidget::ChartAnimationController::resetAlpha() {
|
|
||||||
_alphaAnimationStartedAt = 0;
|
|
||||||
_animValueYAlpha = anim::value(0., 1.);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChartWidget::ChartAnimationController::restartBottomLineAlpha() {
|
void ChartWidget::ChartAnimationController::restartBottomLineAlpha() {
|
||||||
_bottomLineAlphaAnimationStartedAt = crl::now();
|
_bottomLineAlphaAnimationStartedAt = crl::now();
|
||||||
_animValueBottomLineAlpha = anim::value(0., 1.);
|
_animValueBottomLineAlpha = anim::value(0., 1.);
|
||||||
|
@ -603,15 +618,6 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
constexpr auto kXExpandingDuration = 200.;
|
constexpr auto kXExpandingDuration = 200.;
|
||||||
constexpr auto kAlphaExpandingDuration = 200.;
|
constexpr auto kAlphaExpandingDuration = 200.;
|
||||||
|
|
||||||
if (!_heightAnimationStarted
|
|
||||||
&& ((now - _lastUserInteracted) >= kExpandingDelay)) {
|
|
||||||
_heightAnimationStarts.fire({});
|
|
||||||
_heightAnimationStarted = true;
|
|
||||||
}
|
|
||||||
if (!_alphaAnimationStartedAt) {
|
|
||||||
_alphaAnimationStartedAt = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
constexpr auto kIdealFPS = float64(60);
|
constexpr auto kIdealFPS = float64(60);
|
||||||
const auto currentFPS = _benchmark.lastTickedAt
|
const auto currentFPS = _benchmark.lastTickedAt
|
||||||
|
@ -627,16 +633,15 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
const auto k = (kIdealFPS / currentFPS)
|
const auto k = (kIdealFPS / currentFPS)
|
||||||
// Speed up to reduce ugly frames count.
|
// Speed up to reduce ugly frames count.
|
||||||
* (_benchmark.lastFPSSlow ? 2. : 1.);
|
* (_benchmark.lastFPSSlow ? 2. : 1.);
|
||||||
_dtCurrent.min = std::min(_dtCurrent.min + _dtHeightSpeed * k, 1.);
|
const auto speed = _dtHeight.speed * k;
|
||||||
_dtCurrent.max = std::min(_dtCurrent.max + _dtHeightSpeed * k, 1.);
|
_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(
|
const auto dtX = std::min(
|
||||||
(now - _animation.started()) / kXExpandingDuration,
|
(now - _animation.started()) / kXExpandingDuration,
|
||||||
1.);
|
1.);
|
||||||
const auto dtAlpha = std::min(
|
|
||||||
(now - _alphaAnimationStartedAt) / kAlphaExpandingDuration,
|
|
||||||
1.);
|
|
||||||
const auto dtBottomLineAlpha = std::min(
|
const auto dtBottomLineAlpha = std::min(
|
||||||
(now - _bottomLineAlphaAnimationStartedAt) / kAlphaExpandingDuration,
|
(now - _bottomLineAlphaAnimationStartedAt) / kAlphaExpandingDuration,
|
||||||
1.);
|
1.);
|
||||||
|
@ -649,20 +654,26 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
&& isFinished(_animationValueXMax);
|
&& isFinished(_animationValueXMax);
|
||||||
const auto yFinished = isFinished(_animationValueHeightMin)
|
const auto yFinished = isFinished(_animationValueHeightMin)
|
||||||
&& isFinished(_animationValueHeightMax);
|
&& isFinished(_animationValueHeightMax);
|
||||||
const auto alphaFinished = isFinished(_animValueYAlpha);
|
const auto alphaFinished = isFinished(_animationValueHeightAlpha)
|
||||||
|
&& isFinished(_animationValueHeightMax);
|
||||||
const auto bottomLineAlphaFinished = isFinished(
|
const auto bottomLineAlphaFinished = isFinished(
|
||||||
_animValueBottomLineAlpha);
|
_animValueBottomLineAlpha);
|
||||||
|
|
||||||
|
const auto footerMinFinished = isFinished(_animationValueFooterHeightMin);
|
||||||
|
const auto footerMaxFinished = isFinished(_animationValueFooterHeightMax);
|
||||||
|
|
||||||
chartLinesViewContext.tick(now);
|
chartLinesViewContext.tick(now);
|
||||||
|
|
||||||
if (xFinished
|
if (xFinished
|
||||||
&& yFinished
|
&& yFinished
|
||||||
&& alphaFinished
|
&& alphaFinished
|
||||||
&& bottomLineAlphaFinished
|
&& bottomLineAlphaFinished
|
||||||
|
&& footerMinFinished
|
||||||
|
&& footerMaxFinished
|
||||||
&& chartLinesViewContext.isFinished()) {
|
&& chartLinesViewContext.isFinished()) {
|
||||||
const auto &lines = horizontalLines.back().lines;
|
const auto &lines = horizontalLines.back().lines;
|
||||||
if ((lines.front().absoluteValue == _animationValueHeightMin.to())
|
if ((_finalHeightLimits.min == _animationValueHeightMin.to())
|
||||||
&& lines.back().absoluteValue == _animationValueHeightMax.to()) {
|
&& _finalHeightLimits.max == _animationValueHeightMax.to()) {
|
||||||
_animation.stop();
|
_animation.stop();
|
||||||
_benchmark = {};
|
_benchmark = {};
|
||||||
}
|
}
|
||||||
|
@ -682,15 +693,12 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
dtBottomLineAlpha,
|
dtBottomLineAlpha,
|
||||||
anim::easeInCubic);
|
anim::easeInCubic);
|
||||||
}
|
}
|
||||||
if (_heightAnimationStarted) {
|
if (!yFinished) {
|
||||||
_animationValueHeightMin.update(_dtCurrent.min, anim::easeInCubic);
|
_animationValueHeightMin.update(
|
||||||
_animationValueHeightMax.update(_dtCurrent.max, anim::easeInCubic);
|
_dtHeight.current.min,
|
||||||
_animValueYAlpha.update(dtAlpha, anim::easeInCubic);
|
|
||||||
_animationValueFooterHeightMin.update(
|
|
||||||
_dtCurrent.min,
|
|
||||||
anim::easeInCubic);
|
anim::easeInCubic);
|
||||||
_animationValueFooterHeightMax.update(
|
_animationValueHeightMax.update(
|
||||||
_dtCurrent.max,
|
_dtHeight.current.max,
|
||||||
anim::easeInCubic);
|
anim::easeInCubic);
|
||||||
|
|
||||||
for (auto &horizontalLine : horizontalLines) {
|
for (auto &horizontalLine : horizontalLines) {
|
||||||
|
@ -699,9 +707,22 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
_animationValueHeightMin.current());
|
_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.) {
|
if (!alphaFinished) {
|
||||||
const auto value = _animValueYAlpha.current();
|
_animationValueHeightAlpha.update(
|
||||||
|
_dtHeight.currentAlpha,
|
||||||
|
anim::easeInCubic);
|
||||||
|
const auto value = _animationValueHeightAlpha.current();
|
||||||
|
|
||||||
for (auto &horizontalLine : horizontalLines) {
|
for (auto &horizontalLine : horizontalLines) {
|
||||||
horizontalLine.alpha = horizontalLine.fixedAlpha * (1. - value);
|
horizontalLine.alpha = horizontalLine.fixedAlpha * (1. - value);
|
||||||
|
@ -732,11 +753,6 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
dateLines.push_back(data);
|
dateLines.push_back(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yFinished && alphaFinished) {
|
|
||||||
_alphaAnimationStartedAt = 0;
|
|
||||||
_heightAnimationStarted = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Limits ChartWidget::ChartAnimationController::currentXLimits() const {
|
Limits ChartWidget::ChartAnimationController::currentXLimits() const {
|
||||||
|
@ -799,11 +815,6 @@ bool ChartWidget::ChartAnimationController::isFPSSlow() const {
|
||||||
return _benchmark.lastFPSSlow;
|
return _benchmark.lastFPSSlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ChartWidget::ChartAnimationController::heightAnimationStarts() const
|
|
||||||
-> rpl::producer<> {
|
|
||||||
return _heightAnimationStarts.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
|
ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
|
||||||
: Ui::RpWidget(parent)
|
: Ui::RpWidget(parent)
|
||||||
, _chartArea(base::make_unique_q<RpMouseWidget>(this))
|
, _chartArea(base::make_unique_q<RpMouseWidget>(this))
|
||||||
|
@ -1074,11 +1085,8 @@ void ChartWidget::setupFooter() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
rpl::merge(
|
_animationController.addHorizontalLineRequests(
|
||||||
_animationController.heightAnimationStarts(),
|
|
||||||
_footer->userInteractionFinished()
|
|
||||||
) | rpl::start_with_next([=] {
|
) | rpl::start_with_next([=] {
|
||||||
_animationController.resetAlpha();
|
|
||||||
addHorizontalLine(_animationController.finalHeightLimits(), true);
|
addHorizontalLine(_animationController.finalHeightLimits(), true);
|
||||||
_animationController.start();
|
_animationController.start();
|
||||||
}, _footer->lifetime());
|
}, _footer->lifetime());
|
||||||
|
@ -1097,7 +1105,6 @@ void ChartWidget::setupFooter() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_lastHeightLimitsChanged = now;
|
_lastHeightLimitsChanged = now;
|
||||||
_animationController.resetAlpha();
|
|
||||||
addHorizontalLine(_animationController.finalHeightLimits(), true);
|
addHorizontalLine(_animationController.finalHeightLimits(), true);
|
||||||
}, _footer->lifetime());
|
}, _footer->lifetime());
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,15 +74,13 @@ private:
|
||||||
[[nodiscard]] bool footerAnimating() const;
|
[[nodiscard]] bool footerAnimating() const;
|
||||||
[[nodiscard]] bool isFPSSlow() const;
|
[[nodiscard]] bool isFPSSlow() const;
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> heightAnimationStarts() const;
|
[[nodiscard]] rpl::producer<> addHorizontalLineRequests() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Ui::Animations::Basic _animation;
|
Ui::Animations::Basic _animation;
|
||||||
|
|
||||||
crl::time _lastUserInteracted = 0;
|
crl::time _lastUserInteracted = 0;
|
||||||
crl::time _alphaAnimationStartedAt = 0;
|
|
||||||
crl::time _bottomLineAlphaAnimationStartedAt = 0;
|
crl::time _bottomLineAlphaAnimationStartedAt = 0;
|
||||||
bool _heightAnimationStarted = false;
|
|
||||||
|
|
||||||
anim::value _animationValueXMin;
|
anim::value _animationValueXMin;
|
||||||
anim::value _animationValueXMax;
|
anim::value _animationValueXMax;
|
||||||
|
@ -92,22 +90,27 @@ private:
|
||||||
anim::value _animationValueFooterHeightMin;
|
anim::value _animationValueFooterHeightMin;
|
||||||
anim::value _animationValueFooterHeightMax;
|
anim::value _animationValueFooterHeightMax;
|
||||||
|
|
||||||
anim::value _animValueYAlpha;
|
anim::value _animationValueHeightAlpha;
|
||||||
|
|
||||||
anim::value _animValueBottomLineAlpha;
|
anim::value _animValueBottomLineAlpha;
|
||||||
|
|
||||||
Limits _finalHeightLimits;
|
Limits _finalHeightLimits;
|
||||||
Limits _currentXIndices;
|
Limits _currentXIndices;
|
||||||
|
|
||||||
float _dtHeightSpeed = 0.;
|
struct {
|
||||||
Limits _dtCurrent;
|
float speed = 0.;
|
||||||
|
Limits current;
|
||||||
|
|
||||||
|
float64 currentAlpha = 0.;
|
||||||
|
} _dtHeight;
|
||||||
|
Limits _previousFullHeightLimits;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
crl::time lastTickedAt = 0;
|
crl::time lastTickedAt = 0;
|
||||||
bool lastFPSSlow = false;
|
bool lastFPSSlow = false;
|
||||||
} _benchmark;
|
} _benchmark;
|
||||||
|
|
||||||
rpl::event_stream<> _heightAnimationStarts;
|
rpl::event_stream<> _addHorizontalLineRequests;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue