mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Slightly refactored code for statistical charts.
This commit is contained in:
parent
af0e11a1aa
commit
cb4c629178
7 changed files with 41 additions and 66 deletions
|
@ -29,14 +29,14 @@ void StatisticalChart::measure() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i = 0; i < lines.size(); i++) {
|
for (auto &line : lines) {
|
||||||
if (lines[i].maxValue > maxValue) {
|
if (line.maxValue > maxValue) {
|
||||||
maxValue = lines[i].maxValue;
|
maxValue = line.maxValue;
|
||||||
}
|
}
|
||||||
if (lines[i].minValue < minValue) {
|
if (line.minValue < minValue) {
|
||||||
minValue = lines[i].minValue;
|
minValue = line.minValue;
|
||||||
}
|
}
|
||||||
lines[i].segmentTree = Statistic::SegmentTree(lines[i].y);
|
line.segmentTree = Statistic::SegmentTree(line.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
daysLookup.clear();
|
daysLookup.clear();
|
||||||
|
|
|
@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
*/
|
*/
|
||||||
#include "statistics/chart_widget.h"
|
#include "statistics/chart_widget.h"
|
||||||
|
|
||||||
#include "ui/effects/show_animation.h"
|
|
||||||
#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"
|
||||||
|
@ -19,14 +18,13 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "statistics/view/stack_chart_common.h"
|
#include "statistics/view/stack_chart_common.h"
|
||||||
#include "ui/abstract_button.h"
|
#include "ui/abstract_button.h"
|
||||||
#include "ui/effects/animation_value_f.h"
|
#include "ui/effects/animation_value_f.h"
|
||||||
|
#include "ui/effects/ripple_animation.h"
|
||||||
|
#include "ui/effects/show_animation.h"
|
||||||
|
#include "ui/image/image_prepare.h"
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/rect.h"
|
#include "ui/rect.h"
|
||||||
#include "ui/round_rect.h"
|
|
||||||
#include "ui/effects/ripple_animation.h"
|
|
||||||
#include "ui/image/image_prepare.h"
|
|
||||||
#include "ui/widgets/buttons.h"
|
#include "ui/widgets/buttons.h"
|
||||||
#include "styles/style_layers.h"
|
#include "styles/style_layers.h"
|
||||||
#include "styles/style_boxes.h"
|
|
||||||
#include "styles/style_statistics.h"
|
#include "styles/style_statistics.h"
|
||||||
|
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
|
@ -34,7 +32,6 @@ namespace Statistic {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr auto kHeightLimitsUpdateTimeout = crl::time(320);
|
constexpr auto kHeightLimitsUpdateTimeout = crl::time(320);
|
||||||
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);
|
||||||
|
@ -78,10 +75,6 @@ void FillLineColorsByKey(Data::StatisticalChart &chartData) {
|
||||||
+ chartData.getDayString(limits.max);
|
+ chartData.getDayString(limits.max);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool IsChartHasLocalZoom(ChartViewType type) {
|
|
||||||
return type == ChartViewType::StackLinear;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PaintBottomLine(
|
void PaintBottomLine(
|
||||||
QPainter &p,
|
QPainter &p,
|
||||||
const std::vector<ChartWidget::BottomCaptionLineData> &dates,
|
const std::vector<ChartWidget::BottomCaptionLineData> &dates,
|
||||||
|
@ -213,13 +206,12 @@ class ChartWidget::Footer final : public RpMouseWidget {
|
||||||
public:
|
public:
|
||||||
using PaintCallback = Fn<void(QPainter &, const QRect &)>;
|
using PaintCallback = Fn<void(QPainter &, const QRect &)>;
|
||||||
|
|
||||||
Footer(not_null<Ui::RpWidget*> parent);
|
explicit Footer(not_null<Ui::RpWidget*> parent);
|
||||||
|
|
||||||
void setXPercentageLimits(const Limits &xLimits);
|
void setXPercentageLimits(const Limits &xLimits);
|
||||||
|
|
||||||
[[nodiscard]] Limits xPercentageLimits() const;
|
[[nodiscard]] Limits xPercentageLimits() const;
|
||||||
[[nodiscard]] rpl::producer<Limits> xPercentageLimitsChange() const;
|
[[nodiscard]] rpl::producer<Limits> xPercentageLimitsChange() const;
|
||||||
[[nodiscard]] rpl::producer<> userInteractionFinished() const;
|
|
||||||
|
|
||||||
void setPaintChartCallback(PaintCallback paintChartCallback);
|
void setPaintChartCallback(PaintCallback paintChartCallback);
|
||||||
|
|
||||||
|
@ -228,7 +220,6 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
rpl::event_stream<Limits> _xPercentageLimitsChange;
|
rpl::event_stream<Limits> _xPercentageLimitsChange;
|
||||||
rpl::event_stream<> _userInteractionFinished;
|
|
||||||
|
|
||||||
void prepareCache(int height);
|
void prepareCache(int height);
|
||||||
|
|
||||||
|
@ -338,7 +329,6 @@ ChartWidget::Footer::Footer(not_null<Ui::RpWidget*> parent)
|
||||||
case QEvent::MouseButtonRelease: {
|
case QEvent::MouseButtonRelease: {
|
||||||
const auto finish = [=] {
|
const auto finish = [=] {
|
||||||
_dragArea = DragArea::None;
|
_dragArea = DragArea::None;
|
||||||
_userInteractionFinished.fire({});
|
|
||||||
fire();
|
fire();
|
||||||
};
|
};
|
||||||
if ((_dragArea == DragArea::None) && !_draggedAfterPress) {
|
if ((_dragArea == DragArea::None) && !_draggedAfterPress) {
|
||||||
|
@ -456,11 +446,6 @@ void ChartWidget::Footer::paintEvent(QPaintEvent *e) {
|
||||||
const auto innerMargins = QMargins{ 0, lineWidth, 0, lineWidth };
|
const auto innerMargins = QMargins{ 0, lineWidth, 0, lineWidth };
|
||||||
const auto r = rect();
|
const auto r = rect();
|
||||||
const auto innerRect = r - innerMargins;
|
const auto innerRect = r - innerMargins;
|
||||||
const auto inactiveLeftRect = Rect(QSizeF(_leftSide.max, r.height()))
|
|
||||||
- innerMargins;
|
|
||||||
const auto inactiveRightRect = r
|
|
||||||
- QMarginsF{ _rightSide.min, 0, 0, 0 }
|
|
||||||
- innerMargins;
|
|
||||||
const auto &inactiveColor = st::statisticsChartInactive;
|
const auto &inactiveColor = st::statisticsChartInactive;
|
||||||
|
|
||||||
_frame.fill(Qt::transparent);
|
_frame.fill(Qt::transparent);
|
||||||
|
@ -524,10 +509,6 @@ rpl::producer<Limits> ChartWidget::Footer::xPercentageLimitsChange() const {
|
||||||
return _xPercentageLimitsChange.events();
|
return _xPercentageLimitsChange.events();
|
||||||
}
|
}
|
||||||
|
|
||||||
rpl::producer<> ChartWidget::Footer::userInteractionFinished() const {
|
|
||||||
return _userInteractionFinished.events();
|
|
||||||
}
|
|
||||||
|
|
||||||
ChartWidget::ChartAnimationController::ChartAnimationController(
|
ChartWidget::ChartAnimationController::ChartAnimationController(
|
||||||
Fn<void()> &&updateCallback)
|
Fn<void()> &&updateCallback)
|
||||||
: _animation(std::move(updateCallback)) {
|
: _animation(std::move(updateCallback)) {
|
||||||
|
@ -830,10 +811,6 @@ bool ChartWidget::ChartAnimationController::footerAnimating() const {
|
||||||
!= _animationValueFooterHeightMax.to());
|
!= _animationValueFooterHeightMax.to());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChartWidget::ChartAnimationController::isFPSSlow() const {
|
|
||||||
return _benchmark.lastFPSSlow;
|
|
||||||
}
|
|
||||||
|
|
||||||
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))
|
||||||
|
|
|
@ -83,7 +83,6 @@ private:
|
||||||
[[nodiscard]] Limits finalHeightLimits() const;
|
[[nodiscard]] Limits finalHeightLimits() const;
|
||||||
[[nodiscard]] bool animating() const;
|
[[nodiscard]] bool animating() const;
|
||||||
[[nodiscard]] bool footerAnimating() const;
|
[[nodiscard]] bool footerAnimating() const;
|
||||||
[[nodiscard]] bool isFPSSlow() const;
|
|
||||||
|
|
||||||
[[nodiscard]] rpl::producer<> addHorizontalLineRequests() const;
|
[[nodiscard]] rpl::producer<> addHorizontalLineRequests() const;
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ void SegmentTree::build(int v, int from, int size) {
|
||||||
_heap[v].max = _array[from];
|
_heap[v].max = _array[from];
|
||||||
_heap[v].min = _array[from];
|
_heap[v].min = _array[from];
|
||||||
} else {
|
} else {
|
||||||
// Build childs.
|
// Build children.
|
||||||
build(2 * v, from, size / 2);
|
build(2 * v, from, size / 2);
|
||||||
build(2 * v + 1, from + size / 2, size - size / 2);
|
build(2 * v + 1, from + size / 2, size - size / 2);
|
||||||
|
|
||||||
|
|
|
@ -21,19 +21,4 @@ enum class ChartViewType {
|
||||||
StackLinear,
|
StackLinear,
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] inline Limits FindNearestElements(
|
|
||||||
const std::vector<float64> &vector,
|
|
||||||
const Limits &limit) {
|
|
||||||
const auto find = [&](float64 raw) -> float64 {
|
|
||||||
const auto it = ranges::lower_bound(vector, raw);
|
|
||||||
const auto left = raw - (*(it - 1));
|
|
||||||
const auto right = (*it) - raw;
|
|
||||||
const auto nearestXPercentageIt = ((right) > (left)) ? (it - 1) : it;
|
|
||||||
return std::distance(
|
|
||||||
begin(vector),
|
|
||||||
nearestXPercentageIt);
|
|
||||||
};
|
|
||||||
return { find(limit.min), find(limit.max) };
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -18,7 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
float64 Ratio(const LinearChartView::CachedLineRatios &ratios, int id) {
|
[[nodiscard]] float64 Ratio(
|
||||||
|
const LinearChartView::CachedLineRatios &ratios,
|
||||||
|
int id) {
|
||||||
return (id == 1) ? ratios.first : ratios.second;
|
return (id == 1) ? ratios.first : ratios.second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -218,7 +218,7 @@ auto StackLinearChartView::partsPercentage(
|
||||||
|
|
||||||
_pieHasSinglePart = false;
|
_pieHasSinglePart = false;
|
||||||
for (auto k = 0; k < sums.size(); k++) {
|
for (auto k = 0; k < sums.size(); k++) {
|
||||||
const auto rawPercentage = sums[k] / totalSum;
|
const auto rawPercentage = totalSum ? (sums[k] / totalSum) : 0.;
|
||||||
const auto rounded = 0.01 * std::round(rawPercentage * 100.);
|
const auto rounded = 0.01 * std::round(rawPercentage * 100.);
|
||||||
roundedPercentagesSum += rounded;
|
roundedPercentagesSum += rounded;
|
||||||
const auto diff = rawPercentage - rounded;
|
const auto diff = rawPercentage - rounded;
|
||||||
|
@ -342,13 +342,16 @@ 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];
|
||||||
const auto isLastLine = (k == lastEnabled);
|
const auto isLastLine = (k == lastEnabled);
|
||||||
const auto &transitionLine = hasTransitionAnimation
|
|
||||||
? _transition.lines[k]
|
|
||||||
: Transition::TransitionLine();
|
|
||||||
const auto lineAlpha = linesFilter->alpha(line.id);
|
const auto lineAlpha = linesFilter->alpha(line.id);
|
||||||
|
if (isLastLine && (lineAlpha < 1.)) {
|
||||||
|
hasEmptyPoint = true;
|
||||||
|
}
|
||||||
if (!lineAlpha) {
|
if (!lineAlpha) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
const auto &transitionLine = hasTransitionAnimation
|
||||||
|
? _transition.lines[k]
|
||||||
|
: Transition::TransitionLine();
|
||||||
const auto &y = line.y;
|
const auto &y = line.y;
|
||||||
|
|
||||||
auto &chartPath = paths[k];
|
auto &chartPath = paths[k];
|
||||||
|
@ -357,7 +360,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
? float64(y[i] ? lineAlpha : 0.)
|
? float64(y[i] ? lineAlpha : 0.)
|
||||||
: float64(sum ? (y[i] * lineAlpha / sum) : 0.);
|
: float64(sum ? (y[i] * lineAlpha / sum) : 0.);
|
||||||
|
|
||||||
if (!yPercentage && isLastLine) {
|
if (isLastLine && !yPercentage) {
|
||||||
hasEmptyPoint = true;
|
hasEmptyPoint = true;
|
||||||
}
|
}
|
||||||
const auto height = yPercentage * c.rect.height();
|
const auto height = yPercentage * c.rect.height();
|
||||||
|
@ -425,7 +428,9 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i == localStart) {
|
if (i == localStart) {
|
||||||
const auto bottomLeft = QPointF(c.rect.x(), rect::bottom(c.rect));
|
const auto bottomLeft = QPointF(
|
||||||
|
c.rect.x(),
|
||||||
|
rect::bottom(c.rect));
|
||||||
const auto local = (hasTransitionAnimation && !isLastLine)
|
const auto local = (hasTransitionAnimation && !isLastLine)
|
||||||
? rotate(
|
? rotate(
|
||||||
_transition.progress * angle
|
_transition.progress * angle
|
||||||
|
@ -495,7 +500,9 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
: rect::right(c.rect));
|
: rect::right(c.rect));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
chartPath.lineTo(rect::right(c.rect), rect::bottom(c.rect));
|
chartPath.lineTo(
|
||||||
|
rect::right(c.rect),
|
||||||
|
rect::bottom(c.rect));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -510,6 +517,10 @@ void StackLinearChartView::paintChartOrZoomAnimation(
|
||||||
p.setClipPath(ovalPath);
|
p.setClipPath(ovalPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasEmptyPoint) {
|
||||||
|
p.fillRect(c.rect, st::boxDividerBg);
|
||||||
|
}
|
||||||
|
|
||||||
const auto opacity = c.footer ? (1. - _transition.progress) : 1.;
|
const auto opacity = c.footer ? (1. - _transition.progress) : 1.;
|
||||||
for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) {
|
for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) {
|
||||||
if (paths[k].isEmpty()) {
|
if (paths[k].isEmpty()) {
|
||||||
|
@ -708,10 +719,13 @@ void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto rText = side * std::sqrt(1. - percentage);
|
const auto rText = side * std::sqrt(1. - percentage);
|
||||||
const auto textAngle = (previous + kPieAngleOffset)
|
const auto textAngle = (now == previous)
|
||||||
+ (now - previous) / 2.;
|
? 0.
|
||||||
|
: ((previous + kPieAngleOffset) + (now - previous) / 2.);
|
||||||
const auto textRadians = textAngle * M_PI / 180.;
|
const auto textRadians = textAngle * M_PI / 180.;
|
||||||
const auto scale = (minScale) + percentage * (maxScale - minScale);
|
const auto scale = (maxScale == minScale)
|
||||||
|
? 0.
|
||||||
|
: (minScale) + percentage * (maxScale - minScale);
|
||||||
const auto text = QString::number(int(percentage * 100)) + u"%"_q;
|
const auto text = QString::number(int(percentage * 100)) + u"%"_q;
|
||||||
const auto textW = font->width(text);
|
const auto textW = font->width(text);
|
||||||
const auto textH = font->height;
|
const auto textH = font->height;
|
||||||
|
@ -753,7 +767,7 @@ bool StackLinearChartView::PiePartController::set(int id) {
|
||||||
void StackLinearChartView::PiePartController::update(int id) {
|
void StackLinearChartView::PiePartController::update(int id) {
|
||||||
if (id >= 0) {
|
if (id >= 0) {
|
||||||
const auto was = _startedAt[id];
|
const auto was = _startedAt[id];
|
||||||
const auto p = (crl::now() - was) / st::slideWrapDuration;
|
const auto p = (crl::now() - was) / float64(st::slideWrapDuration);
|
||||||
const auto progress = ((p > 0) && (p < 1)) ? (1. - p) : 0.;
|
const auto progress = ((p > 0) && (p < 1)) ? (1. - p) : 0.;
|
||||||
_startedAt[id] = crl::now() - (st::slideWrapDuration * progress);
|
_startedAt[id] = crl::now() - (st::slideWrapDuration * progress);
|
||||||
}
|
}
|
||||||
|
@ -804,10 +818,8 @@ void StackLinearChartView::handleMouseMove(
|
||||||
}
|
}
|
||||||
const auto center = rect.center();
|
const auto center = rect.center();
|
||||||
const auto theta = std::atan2(center.y() - p.y(), (center.x() - p.x()));
|
const auto theta = std::atan2(center.y() - p.y(), (center.x() - p.x()));
|
||||||
const auto angle = [&] {
|
const auto rawAngle = theta * (180. / M_PI) + 90.;
|
||||||
const auto a = theta * (180. / M_PI) + 90.;
|
const auto angle = (rawAngle > 180.) ? (rawAngle - 360.) : rawAngle;
|
||||||
return (a > 180.) ? (a - 360.) : a;
|
|
||||||
}();
|
|
||||||
for (auto k = 0; k < chartData.lines.size(); k++) {
|
for (auto k = 0; k < chartData.lines.size(); k++) {
|
||||||
const auto previous = k
|
const auto previous = k
|
||||||
? _transition.lines[k - 1].angle
|
? _transition.lines[k - 1].angle
|
||||||
|
|
Loading…
Add table
Reference in a new issue