Moved out control of animations for line filtering to separated class.
This commit is contained in:
parent
bdd35a6e2b
commit
8ded88baf5
|
@ -1286,6 +1286,8 @@ PRIVATE
|
||||||
statistics/chart_header_widget.h
|
statistics/chart_header_widget.h
|
||||||
statistics/chart_horizontal_lines_data.cpp
|
statistics/chart_horizontal_lines_data.cpp
|
||||||
statistics/chart_horizontal_lines_data.h
|
statistics/chart_horizontal_lines_data.h
|
||||||
|
statistics/chart_lines_filter_controller.cpp
|
||||||
|
statistics/chart_lines_filter_controller.h
|
||||||
statistics/chart_widget.cpp
|
statistics/chart_widget.cpp
|
||||||
statistics/chart_widget.h
|
statistics/chart_widget.h
|
||||||
statistics/point_details_widget.cpp
|
statistics/point_details_widget.cpp
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#include "statistics/chart_lines_filter_controller.h"
|
||||||
|
|
||||||
|
namespace Statistic {
|
||||||
|
|
||||||
|
LinesFilterController::LinesFilterController() = default;
|
||||||
|
|
||||||
|
void LinesFilterController::setEnabled(int id, bool enabled, crl::time now) {
|
||||||
|
const auto it = _entries.find(id);
|
||||||
|
if (it == end(_entries)) {
|
||||||
|
_entries[id] = Entry{
|
||||||
|
.enabled = enabled,
|
||||||
|
.startedAt = now,
|
||||||
|
.anim = anim::value(enabled ? 0. : 1., enabled ? 1. : 0.),
|
||||||
|
};
|
||||||
|
} else if (it->second.enabled != enabled) {
|
||||||
|
auto &entry = it->second;
|
||||||
|
entry.enabled = enabled;
|
||||||
|
entry.startedAt = now;
|
||||||
|
entry.dtCurrent = 0.;
|
||||||
|
entry.anim.start(enabled ? 1. : 0.);
|
||||||
|
}
|
||||||
|
_isFinished = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LinesFilterController::isFinished() const {
|
||||||
|
return _isFinished;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LinesFilterController::isEnabled(int id) const {
|
||||||
|
const auto it = _entries.find(id);
|
||||||
|
return (it == end(_entries)) ? true : it->second.enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
float64 LinesFilterController::alpha(int id) const {
|
||||||
|
const auto it = _entries.find(id);
|
||||||
|
return (it == end(_entries)) ? 1. : it->second.alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinesFilterController::tick(float64 dtSpeed) {
|
||||||
|
auto finishedCount = 0;
|
||||||
|
auto idsToRemove = std::vector<int>();
|
||||||
|
for (auto &[id, entry] : _entries) {
|
||||||
|
if (!entry.startedAt) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
entry.dtCurrent = std::min(entry.dtCurrent + dtSpeed, 1.);
|
||||||
|
entry.anim.update(entry.dtCurrent, anim::easeInCubic);
|
||||||
|
const auto progress = entry.anim.current();
|
||||||
|
entry.alpha = std::clamp(progress, 0., 1.);
|
||||||
|
if ((entry.alpha == 1.) && entry.enabled) {
|
||||||
|
idsToRemove.push_back(id);
|
||||||
|
}
|
||||||
|
if (entry.anim.current() == entry.anim.to()) {
|
||||||
|
finishedCount++;
|
||||||
|
entry.anim.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_isFinished = (finishedCount == _entries.size());
|
||||||
|
for (const auto &id : idsToRemove) {
|
||||||
|
_entries.remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Statistic
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
This file is part of Telegram Desktop,
|
||||||
|
the official desktop application for the Telegram messaging service.
|
||||||
|
|
||||||
|
For license and copyright information please follow this link:
|
||||||
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ui/effects/animation_value.h"
|
||||||
|
|
||||||
|
namespace Statistic {
|
||||||
|
|
||||||
|
class LinesFilterController final {
|
||||||
|
public:
|
||||||
|
LinesFilterController();
|
||||||
|
|
||||||
|
void setEnabled(int id, bool enabled, crl::time now);
|
||||||
|
[[nodiscard]] bool isEnabled(int id) const;
|
||||||
|
[[nodiscard]] bool isFinished() const;
|
||||||
|
[[nodiscard]] float64 alpha(int id) const;
|
||||||
|
|
||||||
|
void tick(float64 dtSpeed);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Entry final {
|
||||||
|
bool enabled = false;
|
||||||
|
crl::time startedAt = 0;
|
||||||
|
float64 alpha = 1.;
|
||||||
|
anim::value anim;
|
||||||
|
float64 dtCurrent = 0.;
|
||||||
|
};
|
||||||
|
|
||||||
|
base::flat_map<int, Entry> _entries;
|
||||||
|
bool _isFinished = true;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Statistic
|
|
@ -11,6 +11,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "base/qt/qt_key_modifiers.h"
|
#include "base/qt/qt_key_modifiers.h"
|
||||||
#include "lang/lang_keys.h"
|
#include "lang/lang_keys.h"
|
||||||
#include "statistics/chart_header_widget.h"
|
#include "statistics/chart_header_widget.h"
|
||||||
|
#include "statistics/chart_lines_filter_controller.h"
|
||||||
#include "statistics/chart_lines_filter_widget.h"
|
#include "statistics/chart_lines_filter_widget.h"
|
||||||
#include "statistics/point_details_widget.h"
|
#include "statistics/point_details_widget.h"
|
||||||
#include "statistics/view/abstract_chart_view.h"
|
#include "statistics/view/abstract_chart_view.h"
|
||||||
|
@ -505,10 +506,11 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xPercentageLimits,
|
Limits xPercentageLimits,
|
||||||
const std::unique_ptr<AbstractChartView> &chartView,
|
const std::unique_ptr<AbstractChartView> &chartView,
|
||||||
|
const std::shared_ptr<LinesFilterController> &linesFilter,
|
||||||
crl::time now) {
|
crl::time now) {
|
||||||
if ((_animationValueXMin.to() == xPercentageLimits.min)
|
if ((_animationValueXMin.to() == xPercentageLimits.min)
|
||||||
&& (_animationValueXMax.to() == xPercentageLimits.max)
|
&& (_animationValueXMax.to() == xPercentageLimits.max)
|
||||||
&& chartView->isFinished()) {
|
&& linesFilter->isFinished()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
start();
|
start();
|
||||||
|
@ -535,7 +537,7 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
|
||||||
if (!_previousFullHeightLimits.max) {
|
if (!_previousFullHeightLimits.max) {
|
||||||
_previousFullHeightLimits = _finalHeightLimits;
|
_previousFullHeightLimits = _finalHeightLimits;
|
||||||
}
|
}
|
||||||
if (!chartView->isFinished()) {
|
if (!linesFilter->isFinished()) {
|
||||||
_animationValueFooterHeightMin = anim::value(
|
_animationValueFooterHeightMin = anim::value(
|
||||||
_animationValueFooterHeightMin.current(),
|
_animationValueFooterHeightMin.current(),
|
||||||
heightLimits.full.min);
|
heightLimits.full.min);
|
||||||
|
@ -583,7 +585,7 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
|
||||||
_dtHeight.currentAlpha = 0.;
|
_dtHeight.currentAlpha = 0.;
|
||||||
_addHorizontalLineRequests.fire({});
|
_addHorizontalLineRequests.fire({});
|
||||||
}
|
}
|
||||||
_dtHeight.speed = (!chartView->isFinished())
|
_dtHeight.speed = (!linesFilter->isFinished())
|
||||||
? kDtHeightSpeedFilter
|
? kDtHeightSpeedFilter
|
||||||
: (k > kDtHeightSpeedThreshold1)
|
: (k > kDtHeightSpeedThreshold1)
|
||||||
? kDtHeightSpeed1
|
? kDtHeightSpeed1
|
||||||
|
@ -629,7 +631,8 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
crl::time now,
|
crl::time now,
|
||||||
ChartHorizontalLinesView &horizontalLinesView,
|
ChartHorizontalLinesView &horizontalLinesView,
|
||||||
std::vector<BottomCaptionLineData> &dateLines,
|
std::vector<BottomCaptionLineData> &dateLines,
|
||||||
const std::unique_ptr<AbstractChartView> &chartView) {
|
const std::unique_ptr<AbstractChartView> &chartView,
|
||||||
|
const std::shared_ptr<LinesFilterController> &linesFilter) {
|
||||||
if (!_animation.animating()) {
|
if (!_animation.animating()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -652,6 +655,7 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
// Speed up to reduce ugly frames count.
|
// Speed up to reduce ugly frames count.
|
||||||
* (_benchmark.lastFPSSlow ? 2. : 1.);
|
* (_benchmark.lastFPSSlow ? 2. : 1.);
|
||||||
const auto speed = _dtHeight.speed * k;
|
const auto speed = _dtHeight.speed * k;
|
||||||
|
linesFilter->tick(speed);
|
||||||
_dtHeight.current.min = std::min(_dtHeight.current.min + speed, 1.);
|
_dtHeight.current.min = std::min(_dtHeight.current.min + speed, 1.);
|
||||||
_dtHeight.current.max = std::min(_dtHeight.current.max + speed, 1.);
|
_dtHeight.current.max = std::min(_dtHeight.current.max + speed, 1.);
|
||||||
_dtHeight.currentAlpha = std::min(_dtHeight.currentAlpha + speed, 1.);
|
_dtHeight.currentAlpha = std::min(_dtHeight.currentAlpha + speed, 1.);
|
||||||
|
@ -680,25 +684,13 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
const auto footerMinFinished = isFinished(_animationValueFooterHeightMin);
|
const auto footerMinFinished = isFinished(_animationValueFooterHeightMin);
|
||||||
const auto footerMaxFinished = isFinished(_animationValueFooterHeightMax);
|
const auto footerMaxFinished = isFinished(_animationValueFooterHeightMax);
|
||||||
|
|
||||||
// chartView->tick(now);
|
|
||||||
{
|
|
||||||
constexpr auto kDtHeightSpeed1 = 0.03 * 2;
|
|
||||||
constexpr auto kDtHeightSpeed2 = 0.03 * 2;
|
|
||||||
constexpr auto kDtHeightSpeed3 = 0.045 * 2;
|
|
||||||
if (_dtHeight.current.max > 0 && _dtHeight.current.max < 1) {
|
|
||||||
chartView->update(_dtHeight.current.max);
|
|
||||||
} else {
|
|
||||||
chartView->tick(now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xFinished
|
if (xFinished
|
||||||
&& yFinished
|
&& yFinished
|
||||||
&& alphaFinished
|
&& alphaFinished
|
||||||
&& bottomLineAlphaFinished
|
&& bottomLineAlphaFinished
|
||||||
&& footerMinFinished
|
&& footerMinFinished
|
||||||
&& footerMaxFinished
|
&& footerMaxFinished
|
||||||
&& chartView->isFinished()) {
|
&& linesFilter->isFinished()) {
|
||||||
if ((_finalHeightLimits.min == _animationValueHeightMin.to())
|
if ((_finalHeightLimits.min == _animationValueHeightMin.to())
|
||||||
&& _finalHeightLimits.max == _animationValueHeightMax.to()) {
|
&& _finalHeightLimits.max == _animationValueHeightMax.to()) {
|
||||||
_animation.stop();
|
_animation.stop();
|
||||||
|
@ -735,12 +727,12 @@ void ChartWidget::ChartAnimationController::tick(
|
||||||
if (!footerMinFinished) {
|
if (!footerMinFinished) {
|
||||||
_animationValueFooterHeightMin.update(
|
_animationValueFooterHeightMin.update(
|
||||||
_dtHeight.current.min,
|
_dtHeight.current.min,
|
||||||
anim::sineInOut);
|
anim::easeInCubic);
|
||||||
}
|
}
|
||||||
if (!footerMaxFinished) {
|
if (!footerMaxFinished) {
|
||||||
_animationValueFooterHeightMax.update(
|
_animationValueFooterHeightMax.update(
|
||||||
_dtHeight.current.max,
|
_dtHeight.current.max,
|
||||||
anim::sineInOut);
|
anim::easeInCubic);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!alphaFinished) {
|
if (!alphaFinished) {
|
||||||
|
@ -816,9 +808,11 @@ ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
|
||||||
, _chartArea(base::make_unique_q<RpMouseWidget>(this))
|
, _chartArea(base::make_unique_q<RpMouseWidget>(this))
|
||||||
, _header(std::make_unique<Header>(this))
|
, _header(std::make_unique<Header>(this))
|
||||||
, _footer(std::make_unique<Footer>(this))
|
, _footer(std::make_unique<Footer>(this))
|
||||||
|
, _linesFilterController(std::make_shared<LinesFilterController>())
|
||||||
, _animationController([=] {
|
, _animationController([=] {
|
||||||
_chartArea->update();
|
_chartArea->update();
|
||||||
if (_animationController.footerAnimating() || !_chartView->isFinished()) {
|
if (_animationController.footerAnimating()
|
||||||
|
|| !_linesFilterController->isFinished()) {
|
||||||
_footer->update();
|
_footer->update();
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
|
@ -906,7 +900,8 @@ void ChartWidget::setupChartArea() {
|
||||||
now,
|
now,
|
||||||
_horizontalLinesView,
|
_horizontalLinesView,
|
||||||
_bottomLine.dates,
|
_bottomLine.dates,
|
||||||
_chartView);
|
_chartView,
|
||||||
|
_linesFilterController);
|
||||||
|
|
||||||
const auto chartRect = chartAreaRect();
|
const auto chartRect = chartAreaRect();
|
||||||
|
|
||||||
|
@ -947,7 +942,7 @@ void ChartWidget::setupChartArea() {
|
||||||
for (const auto &line : _chartData.lines) {
|
for (const auto &line : _chartData.lines) {
|
||||||
_details.widget->setLineAlpha(
|
_details.widget->setLineAlpha(
|
||||||
line.id,
|
line.id,
|
||||||
_chartView->alpha(line.id));
|
_linesFilterController->alpha(line.id));
|
||||||
}
|
}
|
||||||
_chartView->paintSelectedXIndex(
|
_chartView->paintSelectedXIndex(
|
||||||
p,
|
p,
|
||||||
|
@ -1089,6 +1084,7 @@ void ChartWidget::setupFooter() {
|
||||||
_chartData,
|
_chartData,
|
||||||
xPercentageLimits,
|
xPercentageLimits,
|
||||||
_chartView,
|
_chartView,
|
||||||
|
_linesFilterController,
|
||||||
now);
|
now);
|
||||||
updateChartFullWidth(_chartArea->width());
|
updateChartFullWidth(_chartArea->width());
|
||||||
updateBottomDates();
|
updateBottomDates();
|
||||||
|
@ -1349,12 +1345,13 @@ void ChartWidget::setupFilterButtons() {
|
||||||
_filterButtons->buttonEnabledChanges(
|
_filterButtons->buttonEnabledChanges(
|
||||||
) | rpl::start_with_next([=](const ChartLinesFilterWidget::Entry &e) {
|
) | rpl::start_with_next([=](const ChartLinesFilterWidget::Entry &e) {
|
||||||
const auto now = crl::now();
|
const auto now = crl::now();
|
||||||
_chartView->setEnabled(e.id, e.enabled, now);
|
_linesFilterController->setEnabled(e.id, e.enabled, now);
|
||||||
|
|
||||||
_animationController.setXPercentageLimits(
|
_animationController.setXPercentageLimits(
|
||||||
_chartData,
|
_chartData,
|
||||||
_animationController.currentXLimits(),
|
_animationController.currentXLimits(),
|
||||||
_chartView,
|
_chartView,
|
||||||
|
_linesFilterController,
|
||||||
now);
|
now);
|
||||||
}, _filterButtons->lifetime());
|
}, _filterButtons->lifetime());
|
||||||
}
|
}
|
||||||
|
@ -1365,6 +1362,7 @@ void ChartWidget::setChartData(
|
||||||
_chartData = std::move(chartData);
|
_chartData = std::move(chartData);
|
||||||
|
|
||||||
_chartView = CreateChartView(type);
|
_chartView = CreateChartView(type);
|
||||||
|
_chartView->setLinesFilterController(_linesFilterController);
|
||||||
_horizontalLinesView.setChartData(_chartData, type);
|
_horizontalLinesView.setChartData(_chartData, type);
|
||||||
|
|
||||||
setupDetails();
|
setupDetails();
|
||||||
|
@ -1374,6 +1372,7 @@ void ChartWidget::setChartData(
|
||||||
_chartData,
|
_chartData,
|
||||||
{ _chartData.xPercentage.front(), _chartData.xPercentage.back() },
|
{ _chartData.xPercentage.front(), _chartData.xPercentage.back() },
|
||||||
_chartView,
|
_chartView,
|
||||||
|
_linesFilterController,
|
||||||
0);
|
0);
|
||||||
updateChartFullWidth(_chartArea->width());
|
updateChartFullWidth(_chartArea->width());
|
||||||
updateHeader();
|
updateHeader();
|
||||||
|
|
|
@ -21,6 +21,7 @@ class PointDetailsWidget;
|
||||||
class ChartLinesFilterWidget;
|
class ChartLinesFilterWidget;
|
||||||
class AbstractChartView;
|
class AbstractChartView;
|
||||||
class Header;
|
class Header;
|
||||||
|
class LinesFilterController;
|
||||||
|
|
||||||
class ChartWidget : public Ui::RpWidget {
|
class ChartWidget : public Ui::RpWidget {
|
||||||
public:
|
public:
|
||||||
|
@ -60,7 +61,8 @@ private:
|
||||||
void setXPercentageLimits(
|
void setXPercentageLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xPercentageLimits,
|
Limits xPercentageLimits,
|
||||||
const std::unique_ptr<AbstractChartView> &AbstractChartView,
|
const std::unique_ptr<AbstractChartView> &chartView,
|
||||||
|
const std::shared_ptr<LinesFilterController> &linesFilter,
|
||||||
crl::time now);
|
crl::time now);
|
||||||
void start();
|
void start();
|
||||||
void finish();
|
void finish();
|
||||||
|
@ -70,7 +72,8 @@ private:
|
||||||
crl::time now,
|
crl::time now,
|
||||||
ChartHorizontalLinesView &horizontalLinesView,
|
ChartHorizontalLinesView &horizontalLinesView,
|
||||||
std::vector<BottomCaptionLineData> &dateLines,
|
std::vector<BottomCaptionLineData> &dateLines,
|
||||||
const std::unique_ptr<AbstractChartView> &AbstractChartView);
|
const std::unique_ptr<AbstractChartView> &chartView,
|
||||||
|
const std::shared_ptr<LinesFilterController> &linesFilter);
|
||||||
|
|
||||||
[[nodiscard]] Limits currentXLimits() const;
|
[[nodiscard]] Limits currentXLimits() const;
|
||||||
[[nodiscard]] Limits currentXIndices() const;
|
[[nodiscard]] Limits currentXIndices() const;
|
||||||
|
@ -162,6 +165,8 @@ private:
|
||||||
|
|
||||||
bool _useMinHeight = false;
|
bool _useMinHeight = false;
|
||||||
|
|
||||||
|
std::shared_ptr<LinesFilterController> _linesFilterController;
|
||||||
|
|
||||||
ChartAnimationController _animationController;
|
ChartAnimationController _animationController;
|
||||||
crl::time _lastHeightLimitsChanged = 0;
|
crl::time _lastHeightLimitsChanged = 0;
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ struct StatisticalChart;
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
|
|
||||||
struct Limits;
|
struct Limits;
|
||||||
|
class LinesFilterController;
|
||||||
|
|
||||||
struct PaintContext final {
|
struct PaintContext final {
|
||||||
const Data::StatisticalChart &chartData;
|
const Data::StatisticalChart &chartData;
|
||||||
|
@ -42,11 +43,6 @@ public:
|
||||||
const QRect &rect,
|
const QRect &rect,
|
||||||
float64 x) = 0;
|
float64 x) = 0;
|
||||||
|
|
||||||
virtual void setEnabled(int id, bool enabled, crl::time now) = 0;
|
|
||||||
[[nodiscard]] virtual bool isEnabled(int id) const = 0;
|
|
||||||
[[nodiscard]] virtual bool isFinished() const = 0;
|
|
||||||
[[nodiscard]] virtual float64 alpha(int id) const = 0;
|
|
||||||
|
|
||||||
struct HeightLimits final {
|
struct HeightLimits final {
|
||||||
Limits full;
|
Limits full;
|
||||||
Limits ranged;
|
Limits ranged;
|
||||||
|
@ -56,10 +52,6 @@ public:
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) = 0;
|
Limits xIndices) = 0;
|
||||||
|
|
||||||
virtual void tick(crl::time now) = 0;
|
|
||||||
virtual void update(float64 dt) {
|
|
||||||
};
|
|
||||||
|
|
||||||
struct LocalZoomResult final {
|
struct LocalZoomResult final {
|
||||||
bool hasZoom = false;
|
bool hasZoom = false;
|
||||||
Limits limitIndices;
|
Limits limitIndices;
|
||||||
|
@ -99,7 +91,18 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setLinesFilterController(std::shared_ptr<LinesFilterController> c) {
|
||||||
|
_linesFilterController = std::move(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
using LinesFilterControllerPtr = std::shared_ptr<LinesFilterController>;
|
||||||
|
[[nodiscard]] LinesFilterControllerPtr linesFilterController() {
|
||||||
|
return _linesFilterController;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
LinesFilterControllerPtr _linesFilterController;
|
||||||
Fn<void()> _updateCallback;
|
Fn<void()> _updateCallback;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "statistics/view/linear_chart_view.h"
|
#include "statistics/view/linear_chart_view.h"
|
||||||
|
|
||||||
#include "data/data_statistics.h"
|
#include "data/data_statistics.h"
|
||||||
|
#include "statistics/chart_lines_filter_controller.h"
|
||||||
#include "statistics/statistics_common.h"
|
#include "statistics/statistics_common.h"
|
||||||
#include "ui/effects/animation_value_f.h"
|
#include "ui/effects/animation_value_f.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
@ -17,8 +18,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kAlphaDuration = float64(350);
|
|
||||||
|
|
||||||
float64 Ratio(const LinearChartView::CachedLineRatios &ratios, int id) {
|
float64 Ratio(const LinearChartView::CachedLineRatios &ratios, int id) {
|
||||||
return (id == 1) ? ratios.first : ratios.second;
|
return (id == 1) ? ratios.first : ratios.second;
|
||||||
}
|
}
|
||||||
|
@ -72,13 +71,14 @@ void LinearChartView::paint(QPainter &p, const PaintContext &c) {
|
||||||
c.rect.size());
|
c.rect.size());
|
||||||
|
|
||||||
const auto opacity = p.opacity();
|
const auto opacity = p.opacity();
|
||||||
|
const auto linesFilter = linesFilterController();
|
||||||
const auto imageSize = c.rect.size() * style::DevicePixelRatio();
|
const auto imageSize = c.rect.size() * style::DevicePixelRatio();
|
||||||
const auto cacheScale = 1. / style::DevicePixelRatio();
|
const auto cacheScale = 1. / style::DevicePixelRatio();
|
||||||
auto &caches = (c.footer ? _footerCaches : _mainCaches);
|
auto &caches = (c.footer ? _footerCaches : _mainCaches);
|
||||||
|
|
||||||
for (auto i = 0; i < c.chartData.lines.size(); i++) {
|
for (auto i = 0; i < c.chartData.lines.size(); i++) {
|
||||||
const auto &line = c.chartData.lines[i];
|
const auto &line = c.chartData.lines[i];
|
||||||
p.setOpacity(alpha(line.id));
|
p.setOpacity(linesFilter->alpha(line.id));
|
||||||
if (!p.opacity()) {
|
if (!p.opacity()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ void LinearChartView::paint(QPainter &p, const PaintContext &c) {
|
||||||
|
|
||||||
const auto isSameToken = (cache.lastToken == cacheToken);
|
const auto isSameToken = (cache.lastToken == cacheToken);
|
||||||
if ((isSameToken && cache.hq)
|
if ((isSameToken && cache.hq)
|
||||||
|| (p.opacity() < 1. && !isEnabled(line.id))) {
|
|| (p.opacity() < 1. && !linesFilter->isEnabled(line.id))) {
|
||||||
p.drawImage(c.rect.topLeft(), cache.image);
|
p.drawImage(c.rect.topLeft(), cache.image);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@ void LinearChartView::paintSelectedXIndex(
|
||||||
if (selectedXIndex < 0) {
|
if (selectedXIndex < 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const auto linesFilter = linesFilterController();
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
auto o = ScopedPainterOpacity(p, progress);
|
auto o = ScopedPainterOpacity(p, progress);
|
||||||
p.setBrush(st::boxBg);
|
p.setBrush(st::boxBg);
|
||||||
|
@ -141,9 +142,9 @@ void LinearChartView::paintSelectedXIndex(
|
||||||
&& (_selectedPoints.lastXLimits.max == c.xPercentageLimits.max);
|
&& (_selectedPoints.lastXLimits.max == c.xPercentageLimits.max);
|
||||||
auto linePainted = false;
|
auto linePainted = false;
|
||||||
for (const auto &line : c.chartData.lines) {
|
for (const auto &line : c.chartData.lines) {
|
||||||
const auto lineAlpha = alpha(line.id);
|
const auto lineAlpha = linesFilter->alpha(line.id);
|
||||||
const auto useCache = isSameToken
|
const auto useCache = isSameToken
|
||||||
|| (lineAlpha < 1. && !isEnabled(line.id));
|
|| (lineAlpha < 1. && !linesFilter->isEnabled(line.id));
|
||||||
if (!useCache) {
|
if (!useCache) {
|
||||||
// Calculate.
|
// Calculate.
|
||||||
const auto r = Ratio(_cachedLineRatios, line.id);
|
const auto r = Ratio(_cachedLineRatios, line.id);
|
||||||
|
@ -208,33 +209,6 @@ int LinearChartView::findXIndexByPosition(
|
||||||
nearestXPercentageIt);
|
nearestXPercentageIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinearChartView::setEnabled(int id, bool enabled, crl::time now) {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
if (it == end(_entries)) {
|
|
||||||
_entries[id] = Entry{ .enabled = enabled, .startedAt = now };
|
|
||||||
} else if (it->second.enabled != enabled) {
|
|
||||||
auto &entry = it->second;
|
|
||||||
entry.enabled = enabled;
|
|
||||||
entry.startedAt = now
|
|
||||||
- kAlphaDuration * (enabled ? entry.alpha : (1. - entry.alpha));
|
|
||||||
}
|
|
||||||
_isFinished = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinearChartView::isFinished() const {
|
|
||||||
return _isFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LinearChartView::isEnabled(int id) const {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
return (it == end(_entries)) ? true : it->second.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
float64 LinearChartView::alpha(int id) const {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
return (it == end(_entries)) ? 1. : it->second.alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractChartView::HeightLimits LinearChartView::heightLimits(
|
AbstractChartView::HeightLimits LinearChartView::heightLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) {
|
Limits xIndices) {
|
||||||
|
@ -262,7 +236,7 @@ AbstractChartView::HeightLimits LinearChartView::heightLimits(
|
||||||
auto minValueFull = std::numeric_limits<int>::max();
|
auto minValueFull = std::numeric_limits<int>::max();
|
||||||
auto maxValueFull = 0;
|
auto maxValueFull = 0;
|
||||||
for (auto &l : chartData.lines) {
|
for (auto &l : chartData.lines) {
|
||||||
if (!isEnabled(l.id)) {
|
if (!linesFilterController()->isEnabled(l.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto r = Ratio(_cachedLineRatios, l.id);
|
const auto r = Ratio(_cachedLineRatios, l.id);
|
||||||
|
@ -280,29 +254,4 @@ AbstractChartView::HeightLimits LinearChartView::heightLimits(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinearChartView::tick(crl::time now) {
|
|
||||||
auto finishedCount = 0;
|
|
||||||
auto idsToRemove = std::vector<int>();
|
|
||||||
for (auto &[id, entry] : _entries) {
|
|
||||||
if (!entry.startedAt) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const auto progress = (now - entry.startedAt) / kAlphaDuration;
|
|
||||||
entry.alpha = std::clamp(
|
|
||||||
entry.enabled ? progress : (1. - progress),
|
|
||||||
0.,
|
|
||||||
1.);
|
|
||||||
if (entry.alpha == 1.) {
|
|
||||||
idsToRemove.push_back(id);
|
|
||||||
}
|
|
||||||
if (progress >= 1.) {
|
|
||||||
finishedCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_isFinished = (finishedCount == _entries.size());
|
|
||||||
for (const auto &id : idsToRemove) {
|
|
||||||
_entries.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -39,17 +39,10 @@ public:
|
||||||
const QRect &rect,
|
const QRect &rect,
|
||||||
float64 x) override;
|
float64 x) override;
|
||||||
|
|
||||||
void setEnabled(int id, bool enabled, crl::time now) override;
|
|
||||||
[[nodiscard]] bool isEnabled(int id) const override;
|
|
||||||
[[nodiscard]] bool isFinished() const override;
|
|
||||||
[[nodiscard]] float64 alpha(int id) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] HeightLimits heightLimits(
|
[[nodiscard]] HeightLimits heightLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) override;
|
Limits xIndices) override;
|
||||||
|
|
||||||
void tick(crl::time now) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CachedLineRatios _cachedLineRatios;
|
CachedLineRatios _cachedLineRatios;
|
||||||
|
|
||||||
|
@ -105,15 +98,6 @@ private:
|
||||||
};
|
};
|
||||||
SelectedPoints _selectedPoints;
|
SelectedPoints _selectedPoints;
|
||||||
|
|
||||||
struct Entry final {
|
|
||||||
bool enabled = false;
|
|
||||||
crl::time startedAt = 0;
|
|
||||||
float64 alpha = 1.;
|
|
||||||
};
|
|
||||||
|
|
||||||
base::flat_map<int, Entry> _entries;
|
|
||||||
bool _isFinished = true;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -8,19 +8,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "statistics/view/stack_chart_view.h"
|
#include "statistics/view/stack_chart_view.h"
|
||||||
|
|
||||||
#include "data/data_statistics.h"
|
#include "data/data_statistics.h"
|
||||||
|
#include "statistics/chart_lines_filter_controller.h"
|
||||||
#include "statistics/view/stack_chart_common.h"
|
#include "statistics/view/stack_chart_common.h"
|
||||||
#include "ui/effects/animation_value_f.h"
|
#include "ui/effects/animation_value_f.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
|
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
namespace {
|
|
||||||
|
|
||||||
constexpr auto kAlphaDuration = float64(200);
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
StackChartView::StackChartView() = default;
|
StackChartView::StackChartView() = default;
|
||||||
|
|
||||||
StackChartView::~StackChartView() = default;
|
StackChartView::~StackChartView() = default;
|
||||||
|
|
||||||
void StackChartView::paint(QPainter &p, const PaintContext &c) {
|
void StackChartView::paint(QPainter &p, const PaintContext &c) {
|
||||||
|
@ -71,7 +66,7 @@ void StackChartView::paintChartAndSelected(
|
||||||
/ float64(c.heightLimits.max - c.heightLimits.min);
|
/ float64(c.heightLimits.max - c.heightLimits.min);
|
||||||
const auto yPoint = yPercentage
|
const auto yPoint = yPercentage
|
||||||
* c.rect.height()
|
* c.rect.height()
|
||||||
* alpha(line.id);
|
* linesFilterController()->alpha(line.id);
|
||||||
|
|
||||||
const auto bottomIndex = x - localStart;
|
const auto bottomIndex = x - localStart;
|
||||||
const auto column = QRectF(
|
const auto column = QRectF(
|
||||||
|
@ -95,9 +90,12 @@ void StackChartView::paintChartAndSelected(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto &line = c.chartData.lines[i];
|
const auto &line = c.chartData.lines[i];
|
||||||
const auto yPercentage = (line.y[_lastSelectedXIndex] - c.heightLimits.min)
|
const auto yPercentage = 0.
|
||||||
|
+ (line.y[_lastSelectedXIndex] - c.heightLimits.min)
|
||||||
/ float64(c.heightLimits.max - c.heightLimits.min);
|
/ float64(c.heightLimits.max - c.heightLimits.min);
|
||||||
const auto yPoint = yPercentage * c.rect.height() * alpha(line.id);
|
const auto yPoint = yPercentage
|
||||||
|
* c.rect.height()
|
||||||
|
* linesFilterController()->alpha(line.id);
|
||||||
|
|
||||||
const auto column = QRectF(
|
const auto column = QRectF(
|
||||||
leftStart + (_lastSelectedXIndex - localStart) * w,
|
leftStart + (_lastSelectedXIndex - localStart) * w,
|
||||||
|
@ -148,41 +146,10 @@ int StackChartView::findXIndexByPosition(
|
||||||
return _lastSelectedXIndex = 0;
|
return _lastSelectedXIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackChartView::setEnabled(int id, bool enabled, crl::time now) {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
if (it == end(_entries)) {
|
|
||||||
_entries[id] = Entry{
|
|
||||||
.enabled = enabled,
|
|
||||||
.startedAt = now,
|
|
||||||
.anim = anim::value(enabled ? 0. : 1., enabled ? 1. : 0.),
|
|
||||||
};
|
|
||||||
} else if (it->second.enabled != enabled) {
|
|
||||||
auto &entry = it->second;
|
|
||||||
entry.enabled = enabled;
|
|
||||||
entry.startedAt = now;
|
|
||||||
entry.anim.start(enabled ? 1. : 0.);
|
|
||||||
}
|
|
||||||
_isFinished = false;
|
|
||||||
_cachedHeightLimits = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StackChartView::isFinished() const {
|
|
||||||
return _isFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StackChartView::isEnabled(int id) const {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
return (it == end(_entries)) ? true : it->second.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
float64 StackChartView::alpha(int id) const {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
return (it == end(_entries)) ? 1. : it->second.alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractChartView::HeightLimits StackChartView::heightLimits(
|
AbstractChartView::HeightLimits StackChartView::heightLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) {
|
Limits xIndices) {
|
||||||
|
_cachedHeightLimits = {};
|
||||||
if (_cachedHeightLimits.ySum.empty()) {
|
if (_cachedHeightLimits.ySum.empty()) {
|
||||||
_cachedHeightLimits.ySum.reserve(chartData.x.size());
|
_cachedHeightLimits.ySum.reserve(chartData.x.size());
|
||||||
|
|
||||||
|
@ -190,7 +157,7 @@ AbstractChartView::HeightLimits StackChartView::heightLimits(
|
||||||
for (auto i = 0; i < chartData.x.size(); i++) {
|
for (auto i = 0; i < chartData.x.size(); i++) {
|
||||||
auto sum = 0;
|
auto sum = 0;
|
||||||
for (const auto &line : chartData.lines) {
|
for (const auto &line : chartData.lines) {
|
||||||
if (isEnabled(line.id)) {
|
if (linesFilterController()->isEnabled(line.id)) {
|
||||||
sum += line.y[i];
|
sum += line.y[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,43 +178,4 @@ AbstractChartView::HeightLimits StackChartView::heightLimits(
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackChartView::tick(crl::time now) {
|
|
||||||
for (auto &[id, entry] : _entries) {
|
|
||||||
const auto dt = std::min(
|
|
||||||
(now - entry.startedAt) / kAlphaDuration,
|
|
||||||
1.);
|
|
||||||
if (dt > 1.) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return update(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StackChartView::update(float64 dt) {
|
|
||||||
auto finishedCount = 0;
|
|
||||||
auto idsToRemove = std::vector<int>();
|
|
||||||
for (auto &[id, entry] : _entries) {
|
|
||||||
if (!entry.startedAt) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
entry.anim.update(dt, anim::linear);
|
|
||||||
const auto progress = entry.anim.current();
|
|
||||||
entry.alpha = std::clamp(
|
|
||||||
progress,
|
|
||||||
0.,
|
|
||||||
1.);
|
|
||||||
if (entry.alpha == 1.) {
|
|
||||||
idsToRemove.push_back(id);
|
|
||||||
}
|
|
||||||
if (entry.anim.current() == entry.anim.to()) {
|
|
||||||
finishedCount++;
|
|
||||||
entry.anim.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_isFinished = (finishedCount == _entries.size());
|
|
||||||
for (const auto &id : idsToRemove) {
|
|
||||||
_entries.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -39,18 +39,10 @@ public:
|
||||||
const QRect &rect,
|
const QRect &rect,
|
||||||
float64 x) override;
|
float64 x) override;
|
||||||
|
|
||||||
void setEnabled(int id, bool enabled, crl::time now) override;
|
|
||||||
[[nodiscard]] bool isEnabled(int id) const override;
|
|
||||||
[[nodiscard]] bool isFinished() const override;
|
|
||||||
[[nodiscard]] float64 alpha(int id) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] HeightLimits heightLimits(
|
[[nodiscard]] HeightLimits heightLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) override;
|
Limits xIndices) override;
|
||||||
|
|
||||||
void tick(crl::time now) override;
|
|
||||||
void update(float64 dt) override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void paintChartAndSelected(QPainter &p, const PaintContext &c);
|
void paintChartAndSelected(QPainter &p, const PaintContext &c);
|
||||||
|
|
||||||
|
@ -64,17 +56,6 @@ private:
|
||||||
int _lastSelectedXIndex = -1;
|
int _lastSelectedXIndex = -1;
|
||||||
float64 _lastSelectedXProgress = 0;
|
float64 _lastSelectedXProgress = 0;
|
||||||
|
|
||||||
struct Entry final {
|
|
||||||
bool enabled = false;
|
|
||||||
crl::time startedAt = 0;
|
|
||||||
float64 alpha = 1.;
|
|
||||||
anim::value anim;
|
|
||||||
bool disabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
base::flat_map<int, Entry> _entries;
|
|
||||||
bool _isFinished = true;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -8,6 +8,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "statistics/view/stack_linear_chart_view.h"
|
#include "statistics/view/stack_linear_chart_view.h"
|
||||||
|
|
||||||
#include "data/data_statistics.h"
|
#include "data/data_statistics.h"
|
||||||
|
#include "statistics/chart_lines_filter_controller.h"
|
||||||
#include "statistics/point_details_widget.h"
|
#include "statistics/point_details_widget.h"
|
||||||
#include "statistics/view/stack_chart_common.h"
|
#include "statistics/view/stack_chart_common.h"
|
||||||
#include "ui/effects/animation_value_f.h"
|
#include "ui/effects/animation_value_f.h"
|
||||||
|
@ -20,7 +21,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kAlphaDuration = float64(200);
|
|
||||||
constexpr auto kCircleSizeRatio = 0.42;
|
constexpr auto kCircleSizeRatio = 0.42;
|
||||||
constexpr auto kMinTextScaleRatio = 0.3;
|
constexpr auto kMinTextScaleRatio = 0.3;
|
||||||
constexpr auto kPieAngleOffset = 90;
|
constexpr auto kPieAngleOffset = 90;
|
||||||
|
@ -121,6 +121,7 @@ void StackLinearChartView::prepareZoom(
|
||||||
Transition::TransitionLine());
|
Transition::TransitionLine());
|
||||||
|
|
||||||
const auto xPercentageLimits = _transition.zoomedOutXPercentage;
|
const auto xPercentageLimits = _transition.zoomedOutXPercentage;
|
||||||
|
const auto &linesFilter = linesFilterController();
|
||||||
|
|
||||||
for (auto j = 0; j < 2; j++) {
|
for (auto j = 0; j < 2; j++) {
|
||||||
const auto i = int((j == 1) ? zoomedEnd : zoomedStart);
|
const auto i = int((j == 1) ? zoomedEnd : zoomedStart);
|
||||||
|
@ -128,11 +129,11 @@ void StackLinearChartView::prepareZoom(
|
||||||
auto sum = 0.;
|
auto sum = 0.;
|
||||||
auto drawingLinesCount = 0;
|
auto drawingLinesCount = 0;
|
||||||
for (const auto &line : c.chartData.lines) {
|
for (const auto &line : c.chartData.lines) {
|
||||||
if (!isEnabled(line.id)) {
|
if (!linesFilter->isEnabled(line.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (line.y[i] > 0) {
|
if (line.y[i] > 0) {
|
||||||
sum += line.y[i] * alpha(line.id);
|
sum += line.y[i] * linesFilter->alpha(line.id);
|
||||||
drawingLinesCount++;
|
drawingLinesCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,12 +143,14 @@ void StackLinearChartView::prepareZoom(
|
||||||
? _transition.lines[k].end
|
? _transition.lines[k].end
|
||||||
: _transition.lines[k].start);
|
: _transition.lines[k].start);
|
||||||
const auto &line = c.chartData.lines[k];
|
const auto &line = c.chartData.lines[k];
|
||||||
if (!isEnabled(line.id)) {
|
if (!linesFilter->isEnabled(line.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto yPercentage = (drawingLinesCount == 1)
|
const auto yPercentage = (drawingLinesCount == 1)
|
||||||
? (line.y[i] ? alpha(line.id) : 0)
|
? (line.y[i] ? linesFilter->alpha(line.id) : 0)
|
||||||
: (sum ? (line.y[i] * alpha(line.id) / sum) : 0);
|
: (sum
|
||||||
|
? (line.y[i] * linesFilter->alpha(line.id) / sum)
|
||||||
|
: 0);
|
||||||
|
|
||||||
const auto xPoint = c.rect.width()
|
const auto xPoint = c.rect.width()
|
||||||
* ((c.chartData.xPercentage[i] - xPercentageLimits.min)
|
* ((c.chartData.xPercentage[i] - xPercentageLimits.min)
|
||||||
|
@ -197,12 +200,13 @@ auto StackLinearChartView::partsPercentage(
|
||||||
auto sums = std::vector<float64>();
|
auto sums = std::vector<float64>();
|
||||||
sums.reserve(chartData.lines.size());
|
sums.reserve(chartData.lines.size());
|
||||||
auto totalSum = 0.;
|
auto totalSum = 0.;
|
||||||
|
const auto &linesFilter = linesFilterController();
|
||||||
for (const auto &line : chartData.lines) {
|
for (const auto &line : chartData.lines) {
|
||||||
auto sum = 0;
|
auto sum = 0;
|
||||||
for (auto i = xIndices.min; i <= xIndices.max; i++) {
|
for (auto i = xIndices.min; i <= xIndices.max; i++) {
|
||||||
sum += line.y[i];
|
sum += line.y[i];
|
||||||
}
|
}
|
||||||
sum *= alpha(line.id);
|
sum *= linesFilter->alpha(line.id);
|
||||||
totalSum += sum;
|
totalSum += sum;
|
||||||
sums.push_back(sum);
|
sums.push_back(sum);
|
||||||
}
|
}
|
||||||
|
@ -262,6 +266,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
}
|
}
|
||||||
return p.setOpacity(0.);
|
return p.setOpacity(0.);
|
||||||
}
|
}
|
||||||
|
const auto &linesFilter = linesFilterController();
|
||||||
const auto hasTransitionAnimation = _transition.progress && !c.footer;
|
const auto hasTransitionAnimation = _transition.progress && !c.footer;
|
||||||
const auto &[localStart, localEnd] = c.footer
|
const auto &[localStart, localEnd] = c.footer
|
||||||
? Limits{ 0., float64(c.chartData.xPercentage.size() - 1) }
|
? Limits{ 0., float64(c.chartData.xPercentage.size() - 1) }
|
||||||
|
@ -326,11 +331,11 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
|
|
||||||
for (auto k = 0; k < c.chartData.lines.size(); k++) {
|
for (auto k = 0; k < c.chartData.lines.size(); k++) {
|
||||||
const auto &line = c.chartData.lines[k];
|
const auto &line = c.chartData.lines[k];
|
||||||
if (!isEnabled(line.id)) {
|
if (!linesFilter->isEnabled(line.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (line.y[i] > 0) {
|
if (line.y[i] > 0) {
|
||||||
sum += line.y[i] * alpha(line.id);
|
sum += line.y[i] * linesFilter->alpha(line.id);
|
||||||
drawingLinesCount++;
|
drawingLinesCount++;
|
||||||
}
|
}
|
||||||
lastEnabled = k;
|
lastEnabled = k;
|
||||||
|
@ -340,11 +345,11 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
const auto &line = c.chartData.lines[k];
|
const auto &line = c.chartData.lines[k];
|
||||||
const auto isLastLine = (k == lastEnabled);
|
const auto isLastLine = (k == lastEnabled);
|
||||||
const auto &transitionLine = _transition.lines[k];
|
const auto &transitionLine = _transition.lines[k];
|
||||||
if (!isEnabled(line.id)) {
|
if (!linesFilter->isEnabled(line.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto &y = line.y;
|
const auto &y = line.y;
|
||||||
const auto lineAlpha = alpha(line.id);
|
const auto lineAlpha = linesFilter->alpha(line.id);
|
||||||
|
|
||||||
auto &chartPath = paths[k];
|
auto &chartPath = paths[k];
|
||||||
|
|
||||||
|
@ -511,7 +516,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto &line = c.chartData.lines[k];
|
const auto &line = c.chartData.lines[k];
|
||||||
p.setOpacity(alpha(line.id) * opacity);
|
p.setOpacity(linesFilter->alpha(line.id) * opacity);
|
||||||
p.setPen(Qt::NoPen);
|
p.setPen(Qt::NoPen);
|
||||||
p.fillPath(paths[k], line.color);
|
p.fillPath(paths[k], line.color);
|
||||||
}
|
}
|
||||||
|
@ -601,7 +606,7 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
|
||||||
for (auto i = zoomedStart; i <= zoomedEnd; i++) {
|
for (auto i = zoomedStart; i <= zoomedEnd; i++) {
|
||||||
sum += line.y[i];
|
sum += line.y[i];
|
||||||
}
|
}
|
||||||
sum *= alpha(line.id);
|
sum *= linesFilterController()->alpha(line.id);
|
||||||
if (sum > 0) {
|
if (sum > 0) {
|
||||||
PaintDetails(p, line, sum, c.rect);
|
PaintDetails(p, line, sum, c.rect);
|
||||||
}
|
}
|
||||||
|
@ -628,10 +633,10 @@ void StackLinearChartView::paintZoomedFooter(
|
||||||
auto sum = 0.;
|
auto sum = 0.;
|
||||||
auto lastEnabledId = int(0);
|
auto lastEnabledId = int(0);
|
||||||
for (const auto &line : c.chartData.lines) {
|
for (const auto &line : c.chartData.lines) {
|
||||||
if (!isEnabled(line.id)) {
|
if (!linesFilterController()->isEnabled(line.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
sum += line.y[i] * alpha(line.id);
|
sum += line.y[i] * linesFilterController()->alpha(line.id);
|
||||||
lastEnabledId = line.id;
|
lastEnabledId = line.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,7 +655,7 @@ void StackLinearChartView::paintZoomedFooter(
|
||||||
auto stack = 0.;
|
auto stack = 0.;
|
||||||
for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) {
|
for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) {
|
||||||
const auto &line = c.chartData.lines[k];
|
const auto &line = c.chartData.lines[k];
|
||||||
if (!isEnabled(line.id)) {
|
if (!linesFilterController()->isEnabled(line.id)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const auto visibleHeight = c.rect.height() * (line.y[i] / sum);
|
const auto visibleHeight = c.rect.height() * (line.y[i] / sum);
|
||||||
|
@ -728,7 +733,8 @@ void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) {
|
||||||
textRectCenter.y() + partOffset.y())
|
textRectCenter.y() + partOffset.y())
|
||||||
.scale(scale, scale)
|
.scale(scale, scale)
|
||||||
.translate(-textRectCenter.x(), -textRectCenter.y()));
|
.translate(-textRectCenter.x(), -textRectCenter.y()));
|
||||||
p.setOpacity(opacity * alpha(c.chartData.lines[k].id));
|
p.setOpacity(opacity
|
||||||
|
* linesFilterController()->alpha(c.chartData.lines[k].id));
|
||||||
p.drawText(textRect, text, style::al_center);
|
p.drawText(textRect, text, style::al_center);
|
||||||
}
|
}
|
||||||
p.resetTransform();
|
p.resetTransform();
|
||||||
|
@ -822,8 +828,7 @@ void StackLinearChartView::handleMouseMove(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StackLinearChartView::skipSelectedTranslation() const {
|
bool StackLinearChartView::skipSelectedTranslation() const {
|
||||||
return _pieHasSinglePart
|
return _pieHasSinglePart;
|
||||||
|| (_entries.size() == (_transition.lines.size() - 1));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackLinearChartView::paintSelectedXIndex(
|
void StackLinearChartView::paintSelectedXIndex(
|
||||||
|
@ -904,37 +909,6 @@ int StackLinearChartView::findXIndexByPosition(
|
||||||
long(localEnd));
|
long(localEnd));
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackLinearChartView::setEnabled(int id, bool enabled, crl::time now) {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
if (it == end(_entries)) {
|
|
||||||
_entries[id] = Entry{
|
|
||||||
.enabled = enabled,
|
|
||||||
.startedAt = now,
|
|
||||||
.anim = anim::value(enabled ? 0. : 1., enabled ? 1. : 0.),
|
|
||||||
};
|
|
||||||
} else if (it->second.enabled != enabled) {
|
|
||||||
auto &entry = it->second;
|
|
||||||
entry.enabled = enabled;
|
|
||||||
entry.startedAt = now;
|
|
||||||
entry.anim.start(enabled ? 1. : 0.);
|
|
||||||
}
|
|
||||||
_isFinished = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StackLinearChartView::isFinished() const {
|
|
||||||
return _isFinished;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StackLinearChartView::isEnabled(int id) const {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
return (it == end(_entries)) ? true : it->second.enabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
float64 StackLinearChartView::alpha(int id) const {
|
|
||||||
const auto it = _entries.find(id);
|
|
||||||
return (it == end(_entries)) ? 1. : it->second.alpha;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractChartView::HeightLimits StackLinearChartView::heightLimits(
|
AbstractChartView::HeightLimits StackLinearChartView::heightLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) {
|
Limits xIndices) {
|
||||||
|
@ -1010,43 +984,4 @@ auto StackLinearChartView::maybeLocalZoom(
|
||||||
return { true, _transition.zoomedInLimitXIndices, resultRange };
|
return { true, _transition.zoomedInLimitXIndices, resultRange };
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackLinearChartView::tick(crl::time now) {
|
|
||||||
for (auto &[id, entry] : _entries) {
|
|
||||||
const auto dt = std::min(
|
|
||||||
(now - entry.startedAt) / kAlphaDuration,
|
|
||||||
1.);
|
|
||||||
if (dt > 1.) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
return update(dt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StackLinearChartView::update(float64 dt) {
|
|
||||||
auto finishedCount = 0;
|
|
||||||
auto idsToRemove = std::vector<int>();
|
|
||||||
for (auto &[id, entry] : _entries) {
|
|
||||||
if (!entry.startedAt) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
entry.anim.update(dt, anim::linear);
|
|
||||||
const auto progress = entry.anim.current();
|
|
||||||
entry.alpha = std::clamp(
|
|
||||||
progress,
|
|
||||||
0.,
|
|
||||||
1.);
|
|
||||||
if (entry.alpha == 1.) {
|
|
||||||
idsToRemove.push_back(id);
|
|
||||||
}
|
|
||||||
if (entry.anim.current() == entry.anim.to()) {
|
|
||||||
finishedCount++;
|
|
||||||
entry.anim.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_isFinished = (finishedCount == _entries.size());
|
|
||||||
for (const auto &id : idsToRemove) {
|
|
||||||
_entries.remove(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -40,18 +40,10 @@ public:
|
||||||
const QRect &rect,
|
const QRect &rect,
|
||||||
float64 x) override;
|
float64 x) override;
|
||||||
|
|
||||||
void setEnabled(int id, bool enabled, crl::time now) override;
|
|
||||||
[[nodiscard]] bool isEnabled(int id) const override;
|
|
||||||
[[nodiscard]] bool isFinished() const override;
|
|
||||||
[[nodiscard]] float64 alpha(int id) const override;
|
|
||||||
|
|
||||||
[[nodiscard]] HeightLimits heightLimits(
|
[[nodiscard]] HeightLimits heightLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) override;
|
Limits xIndices) override;
|
||||||
|
|
||||||
void tick(crl::time now) override;
|
|
||||||
void update(float64 dt) override;
|
|
||||||
|
|
||||||
LocalZoomResult maybeLocalZoom(const LocalZoomArgs &args) override final;
|
LocalZoomResult maybeLocalZoom(const LocalZoomArgs &args) override final;
|
||||||
|
|
||||||
void handleMouseMove(
|
void handleMouseMove(
|
||||||
|
@ -95,17 +87,6 @@ private:
|
||||||
};
|
};
|
||||||
SelectedPoints _selectedPoints;
|
SelectedPoints _selectedPoints;
|
||||||
|
|
||||||
struct Entry final {
|
|
||||||
bool enabled = false;
|
|
||||||
crl::time startedAt = 0;
|
|
||||||
float64 alpha = 1.;
|
|
||||||
anim::value anim;
|
|
||||||
bool disabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
base::flat_map<int, Entry> _entries;
|
|
||||||
bool _isFinished = true;
|
|
||||||
|
|
||||||
struct Transition {
|
struct Transition {
|
||||||
struct TransitionLine {
|
struct TransitionLine {
|
||||||
QPointF start;
|
QPointF start;
|
||||||
|
|
Loading…
Reference in New Issue