mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-15 13:47:05 +02:00
Initially refactored statistics module to simplify value types changing.
This commit is contained in:
parent
7ffa9844e2
commit
a37cbd7d05
14 changed files with 97 additions and 71 deletions
|
@ -30,14 +30,15 @@ struct StatisticalChart {
|
|||
[[nodiscard]] int findIndex(int left, int right, float64 v) const;
|
||||
|
||||
struct Line final {
|
||||
std::vector<int> y;
|
||||
std::vector<Statistic::ChartValue> y;
|
||||
|
||||
Statistic::SegmentTree segmentTree;
|
||||
int id = 0;
|
||||
QString idString;
|
||||
QString name;
|
||||
int maxValue = 0;
|
||||
int minValue = std::numeric_limits<int>::max();
|
||||
Statistic::ChartValue maxValue = 0;
|
||||
Statistic::ChartValue minValue =
|
||||
std::numeric_limits<Statistic::ChartValue>::max();
|
||||
QString colorKey;
|
||||
QColor color;
|
||||
QColor colorDark;
|
||||
|
@ -55,8 +56,9 @@ struct StatisticalChart {
|
|||
float64 max = 0.;
|
||||
} defaultZoomXIndex;
|
||||
|
||||
int maxValue = 0;
|
||||
int minValue = std::numeric_limits<int>::max();
|
||||
Statistic::ChartValue maxValue = 0;
|
||||
Statistic::ChartValue minValue =
|
||||
std::numeric_limits<Statistic::ChartValue>::max();
|
||||
|
||||
float64 oneDayPercentage = 0.;
|
||||
|
||||
|
|
|
@ -12,17 +12,17 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
namespace Statistic {
|
||||
namespace {
|
||||
|
||||
constexpr auto kMinLines = int(2);
|
||||
constexpr auto kMaxLines = int(6);
|
||||
constexpr auto kMinLines = ChartValue(2);
|
||||
constexpr auto kMaxLines = ChartValue(6);
|
||||
constexpr auto kStep = 5.;
|
||||
|
||||
[[nodiscard]] int Round(int maxValue) {
|
||||
const auto k = int(maxValue / kStep);
|
||||
[[nodiscard]] ChartValue Round(ChartValue maxValue) {
|
||||
const auto k = ChartValue(maxValue / kStep);
|
||||
return (k % 10 == 0) ? maxValue : ((maxValue / 10 + 1) * 10);
|
||||
}
|
||||
|
||||
[[nodiscard]] QString Format(int absoluteValue) {
|
||||
constexpr auto kTooMuch = int(10'000);
|
||||
[[nodiscard]] QString Format(ChartValue absoluteValue) {
|
||||
constexpr auto kTooMuch = ChartValue(10'000);
|
||||
return (absoluteValue >= kTooMuch)
|
||||
? Lang::FormatCountToShort(absoluteValue).string
|
||||
: QString::number(absoluteValue);
|
||||
|
@ -31,8 +31,8 @@ constexpr auto kStep = 5.;
|
|||
} // namespace
|
||||
|
||||
ChartRulersData::ChartRulersData(
|
||||
int newMaxHeight,
|
||||
int newMinHeight,
|
||||
ChartValue newMaxHeight,
|
||||
ChartValue newMinHeight,
|
||||
bool useMinHeight,
|
||||
float64 rightRatio,
|
||||
Fn<QString(float64)> leftCustomCaption,
|
||||
|
@ -42,11 +42,13 @@ ChartRulersData::ChartRulersData(
|
|||
? Round(newMaxHeight)
|
||||
: newMaxHeight;
|
||||
|
||||
const auto step = std::max(1, int(std::ceil(v / kStep)));
|
||||
const auto step = std::max(
|
||||
ChartValue(1),
|
||||
ChartValue(std::ceil(v / kStep)));
|
||||
|
||||
auto n = kMaxLines;
|
||||
if (v < kMaxLines) {
|
||||
n = std::max(2, v + 1);
|
||||
n = std::max(2, int(v + 1));
|
||||
} else if (v / 2 < kMaxLines) {
|
||||
n = v / 2 + 1;
|
||||
if (v % 2 != 0) {
|
||||
|
@ -87,11 +89,11 @@ ChartRulersData::ChartRulersData(
|
|||
}
|
||||
|
||||
lines.resize(n);
|
||||
const auto diffAbsoluteValue = int((n - 1) * step);
|
||||
const auto diffAbsoluteValue = ChartValue((n - 1) * step);
|
||||
const auto skipFloatValues = (step / rightRatio) < 1;
|
||||
for (auto i = 0; i < n; i++) {
|
||||
auto &line = lines[i];
|
||||
const auto value = int(i * step);
|
||||
const auto value = ChartValue(i * step);
|
||||
line.absoluteValue = newMinHeight + value;
|
||||
line.relativeValue = 1. - value / float64(diffAbsoluteValue);
|
||||
line.caption = leftCustomCaption
|
||||
|
@ -103,7 +105,7 @@ ChartRulersData::ChartRulersData(
|
|||
? rightCustomCaption(line.absoluteValue)
|
||||
: (!skipFloatValues)
|
||||
? Format(v)
|
||||
: ((v - int(v)) < 0.01)
|
||||
: ((v - ChartValue(v)) < 0.01)
|
||||
? Format(v)
|
||||
: QString();
|
||||
}
|
||||
|
@ -112,8 +114,8 @@ ChartRulersData::ChartRulersData(
|
|||
}
|
||||
|
||||
void ChartRulersData::computeRelative(
|
||||
int newMaxHeight,
|
||||
int newMinHeight) {
|
||||
ChartValue newMaxHeight,
|
||||
ChartValue newMinHeight) {
|
||||
for (auto &line : lines) {
|
||||
line.relativeValue = 1.
|
||||
- ((line.absoluteValue - newMinHeight)
|
||||
|
@ -121,10 +123,10 @@ void ChartRulersData::computeRelative(
|
|||
}
|
||||
}
|
||||
|
||||
int ChartRulersData::LookupHeight(int maxValue) {
|
||||
ChartValue ChartRulersData::LookupHeight(ChartValue maxValue) {
|
||||
const auto v = (maxValue > 100) ? Round(maxValue) : maxValue;
|
||||
|
||||
const auto step = int(std::ceil(v / kStep));
|
||||
const auto step = ChartValue(std::ceil(v / kStep));
|
||||
return step * kStep;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,23 +7,25 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "statistics/statistics_types.h"
|
||||
|
||||
namespace Statistic {
|
||||
|
||||
struct ChartRulersData final {
|
||||
public:
|
||||
ChartRulersData(
|
||||
int newMaxHeight,
|
||||
int newMinHeight,
|
||||
ChartValue newMaxHeight,
|
||||
ChartValue newMinHeight,
|
||||
bool useMinHeight,
|
||||
float64 rightRatio,
|
||||
Fn<QString(float64)> leftCustomCaption = nullptr,
|
||||
Fn<QString(float64)> rightCustomCaption = nullptr);
|
||||
|
||||
void computeRelative(
|
||||
int newMaxHeight,
|
||||
int newMinHeight);
|
||||
ChartValue newMaxHeight,
|
||||
ChartValue newMinHeight);
|
||||
|
||||
[[nodiscard]] static int LookupHeight(int maxValue);
|
||||
[[nodiscard]] static ChartValue LookupHeight(ChartValue maxValue);
|
||||
|
||||
struct Line final {
|
||||
float64 absoluteValue = 0.;
|
||||
|
|
|
@ -1157,7 +1157,7 @@ void ChartWidget::setupDetails() {
|
|||
return;
|
||||
}
|
||||
const auto maxAbsoluteValue = [&] {
|
||||
auto maxValue = 0;
|
||||
auto maxValue = ChartValue(0);
|
||||
for (const auto &l : _chartData.lines) {
|
||||
maxValue = std::max(l.maxValue, maxValue);
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ constexpr auto kMinArraySize = size_t(30);
|
|||
|
||||
} // namespace
|
||||
|
||||
SegmentTree::SegmentTree(std::vector<int> array)
|
||||
SegmentTree::SegmentTree(std::vector<ChartValue> array)
|
||||
: _array(std::move(array)) {
|
||||
if (_array.size() < kMinArraySize) {
|
||||
return;
|
||||
|
@ -28,7 +28,7 @@ SegmentTree::SegmentTree(std::vector<int> array)
|
|||
build(1, 0, _array.size());
|
||||
}
|
||||
|
||||
void SegmentTree::build(int v, int from, int size) {
|
||||
void SegmentTree::build(ChartValue v, int from, int size) {
|
||||
_heap[v].from = from;
|
||||
_heap[v].to = (from + size - 1);
|
||||
|
||||
|
@ -48,9 +48,9 @@ void SegmentTree::build(int v, int from, int size) {
|
|||
}
|
||||
}
|
||||
|
||||
int SegmentTree::rMaxQ(int from, int to) {
|
||||
ChartValue SegmentTree::rMaxQ(int from, int to) {
|
||||
if (_array.size() < kMinArraySize) {
|
||||
auto max = 0;
|
||||
auto max = ChartValue(0);
|
||||
from = std::max(from, 0);
|
||||
to = std::min(to, int(_array.size() - 1));
|
||||
for (auto i = from; i <= to; i++) {
|
||||
|
@ -61,7 +61,7 @@ int SegmentTree::rMaxQ(int from, int to) {
|
|||
return rMaxQ(1, from, to);
|
||||
}
|
||||
|
||||
int SegmentTree::rMaxQ(int v, int from, int to) {
|
||||
ChartValue SegmentTree::rMaxQ(ChartValue v, int from, int to) {
|
||||
const auto &n = _heap[v];
|
||||
// If you did a range update that contained this node,
|
||||
// you can infer the Min value without going down the tree.
|
||||
|
@ -84,9 +84,9 @@ int SegmentTree::rMaxQ(int v, int from, int to) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int SegmentTree::rMinQ(int from, int to) {
|
||||
ChartValue SegmentTree::rMinQ(int from, int to) {
|
||||
if (_array.size() < kMinArraySize) {
|
||||
auto min = std::numeric_limits<int>::max();
|
||||
auto min = std::numeric_limits<ChartValue>::max();
|
||||
from = std::max(from, 0);
|
||||
to = std::min(to, int(_array.size() - 1));
|
||||
for (auto i = from; i <= to; i++) {
|
||||
|
@ -97,7 +97,7 @@ int SegmentTree::rMinQ(int from, int to) {
|
|||
return rMinQ(1, from, to);
|
||||
}
|
||||
|
||||
int SegmentTree::rMinQ(int v, int from, int to) {
|
||||
ChartValue SegmentTree::rMinQ(ChartValue v, int from, int to) {
|
||||
const auto &n = _heap[v];
|
||||
// If you did a range update that contained this node,
|
||||
// you can infer the Min value without going down the tree.
|
||||
|
@ -117,10 +117,10 @@ int SegmentTree::rMinQ(int v, int from, int to) {
|
|||
return std::min(leftMin, rightMin);
|
||||
}
|
||||
|
||||
return std::numeric_limits<int>::max();
|
||||
return std::numeric_limits<ChartValue>::max();
|
||||
}
|
||||
|
||||
void SegmentTree::propagate(int v) {
|
||||
void SegmentTree::propagate(ChartValue v) {
|
||||
auto &n = _heap[v];
|
||||
|
||||
if (n.pendingVal) {
|
||||
|
@ -131,7 +131,7 @@ void SegmentTree::propagate(int v) {
|
|||
}
|
||||
}
|
||||
|
||||
void SegmentTree::change(SegmentTree::Node &n, int value) {
|
||||
void SegmentTree::change(SegmentTree::Node &n, ChartValue value) {
|
||||
n.pendingVal = { value, true };
|
||||
n.sum = n.size() * value;
|
||||
n.max = value;
|
||||
|
|
|
@ -7,12 +7,14 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
*/
|
||||
#pragma once
|
||||
|
||||
#include "statistics/statistics_types.h"
|
||||
|
||||
namespace Statistic {
|
||||
|
||||
class SegmentTree final {
|
||||
public:
|
||||
SegmentTree() = default;
|
||||
SegmentTree(std::vector<int> array);
|
||||
SegmentTree(std::vector<ChartValue> array);
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return _array.empty();
|
||||
|
@ -21,20 +23,20 @@ public:
|
|||
return !empty();
|
||||
}
|
||||
|
||||
[[nodiscard]] int rMaxQ(int from, int to);
|
||||
[[nodiscard]] int rMinQ(int from, int to);
|
||||
[[nodiscard]] ChartValue rMaxQ(int from, int to);
|
||||
[[nodiscard]] ChartValue rMinQ(int from, int to);
|
||||
|
||||
private:
|
||||
struct Node final {
|
||||
int sum = 0;
|
||||
int max = 0;
|
||||
int min = 0;
|
||||
ChartValue sum = 0;
|
||||
ChartValue max = 0;
|
||||
ChartValue min = 0;
|
||||
|
||||
struct PendingVal {
|
||||
[[nodiscard]] explicit operator bool() const {
|
||||
return available;
|
||||
}
|
||||
int value = 0;
|
||||
ChartValue value = 0;
|
||||
bool available = false;
|
||||
};
|
||||
PendingVal pendingVal;
|
||||
|
@ -47,12 +49,12 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
void build(int v, int from, int size);
|
||||
void propagate(int v);
|
||||
void change(Node &n, int value);
|
||||
void build(ChartValue v, int from, int size);
|
||||
void propagate(ChartValue v);
|
||||
void change(Node &n, ChartValue value);
|
||||
|
||||
[[nodiscard]] int rMaxQ(int v, int from, int to);
|
||||
[[nodiscard]] int rMinQ(int v, int from, int to);
|
||||
[[nodiscard]] ChartValue rMaxQ(ChartValue v, int from, int to);
|
||||
[[nodiscard]] ChartValue rMinQ(ChartValue v, int from, int to);
|
||||
|
||||
[[nodiscard]] bool contains(int from1, int to1, int from2, int to2) const;
|
||||
[[nodiscard]] bool intersects(
|
||||
|
@ -61,7 +63,7 @@ private:
|
|||
int from2,
|
||||
int to2) const;
|
||||
|
||||
std::vector<int> _array;
|
||||
std::vector<ChartValue> _array;
|
||||
std::vector<Node> _heap;
|
||||
|
||||
};
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "base/debug_log.h"
|
||||
#include "data/data_statistics_chart.h"
|
||||
#include "statistics/statistics_types.h"
|
||||
|
||||
#include <QtCore/QJsonArray>
|
||||
#include <QtCore/QJsonDocument>
|
||||
|
@ -61,7 +62,7 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
|
|||
line.isHiddenOnStart = ranges::contains(hiddenLines, columnId);
|
||||
line.y.resize(length);
|
||||
for (auto i = 0; i < length; i++) {
|
||||
const auto value = int(base::SafeRound(
|
||||
const auto value = ChartValue(base::SafeRound(
|
||||
array.at(i + 1).toDouble()));
|
||||
line.y[i] = value;
|
||||
if (value > line.maxValue) {
|
||||
|
|
14
Telegram/SourceFiles/statistics/statistics_types.h
Normal file
14
Telegram/SourceFiles/statistics/statistics_types.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
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
|
||||
|
||||
namespace Statistic {
|
||||
|
||||
using ChartValue = int64;
|
||||
|
||||
} // namespace Statistic
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "data/data_statistics_chart.h"
|
||||
#include "statistics/chart_lines_filter_controller.h"
|
||||
#include "statistics/statistics_types.h"
|
||||
|
||||
namespace Statistic {
|
||||
|
||||
|
@ -71,11 +72,11 @@ AbstractChartView::HeightLimits DefaultHeightLimits(
|
|||
const std::shared_ptr<LinesFilterController> &linesFilter,
|
||||
Data::StatisticalChart &chartData,
|
||||
Limits xIndices) {
|
||||
auto minValue = std::numeric_limits<int>::max();
|
||||
auto maxValue = 0;
|
||||
auto minValue = std::numeric_limits<ChartValue>::max();
|
||||
auto maxValue = ChartValue(0);
|
||||
|
||||
auto minValueFull = std::numeric_limits<int>::max();
|
||||
auto maxValueFull = 0;
|
||||
auto minValueFull = std::numeric_limits<ChartValue>::max();
|
||||
auto maxValueFull = ChartValue(0);
|
||||
for (auto &l : chartData.lines) {
|
||||
if (!linesFilter->isEnabled(l.id)) {
|
||||
continue;
|
||||
|
@ -83,11 +84,11 @@ AbstractChartView::HeightLimits DefaultHeightLimits(
|
|||
const auto r = ratios.ratio(l.id);
|
||||
const auto lineMax = l.segmentTree.rMaxQ(xIndices.min, xIndices.max);
|
||||
const auto lineMin = l.segmentTree.rMinQ(xIndices.min, xIndices.max);
|
||||
maxValue = std::max(int(lineMax * r), maxValue);
|
||||
minValue = std::min(int(lineMin * r), minValue);
|
||||
maxValue = std::max(ChartValue(lineMax * r), maxValue);
|
||||
minValue = std::min(ChartValue(lineMin * r), minValue);
|
||||
|
||||
maxValueFull = std::max(int(l.maxValue * r), maxValueFull);
|
||||
minValueFull = std::min(int(l.minValue * r), minValueFull);
|
||||
maxValueFull = std::max(ChartValue(l.maxValue * r), maxValueFull);
|
||||
minValueFull = std::min(ChartValue(l.minValue * r), minValueFull);
|
||||
}
|
||||
if (maxValue == minValue) {
|
||||
maxValue = chartData.maxValue;
|
||||
|
|
|
@ -256,9 +256,9 @@ AbstractChartView::HeightLimits BarChartView::heightLimits(
|
|||
if (_cachedHeightLimits.ySum.empty()) {
|
||||
_cachedHeightLimits.ySum.reserve(chartData.x.size());
|
||||
|
||||
auto maxValueFull = 0;
|
||||
auto maxValueFull = ChartValue(0);
|
||||
for (auto i = 0; i < chartData.x.size(); i++) {
|
||||
auto sum = 0;
|
||||
auto sum = ChartValue(0);
|
||||
for (const auto &line : chartData.lines) {
|
||||
if (linesFilterController()->isEnabled(line.id)) {
|
||||
sum += line.y[i];
|
||||
|
@ -276,7 +276,7 @@ AbstractChartView::HeightLimits BarChartView::heightLimits(
|
|||
_cachedHeightLimits.ySumSegmentTree.rMaxQ(
|
||||
xIndices.min,
|
||||
xIndices.max),
|
||||
1);
|
||||
ChartValue(1));
|
||||
return {
|
||||
.full = _cachedHeightLimits.full,
|
||||
.ranged = { 0., float64(max) },
|
||||
|
|
|
@ -9,6 +9,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
|
||||
#include "statistics/segment_tree.h"
|
||||
#include "statistics/statistics_common.h"
|
||||
#include "statistics/statistics_types.h"
|
||||
#include "statistics/view/abstract_chart_view.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
|
||||
|
@ -48,7 +49,7 @@ private:
|
|||
|
||||
struct {
|
||||
Limits full;
|
||||
std::vector<int> ySum;
|
||||
std::vector<ChartValue> ySum;
|
||||
SegmentTree ySumSegmentTree;
|
||||
} _cachedHeightLimits;
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ PiePartData PiePartsPercentageByIndices(
|
|||
sums.reserve(chartData.lines.size());
|
||||
auto totalSum = 0.;
|
||||
for (const auto &line : chartData.lines) {
|
||||
auto sum = 0;
|
||||
auto sum = ChartValue(0);
|
||||
for (auto i = xIndices.min; i <= xIndices.max; i++) {
|
||||
sum += line.y[i];
|
||||
}
|
||||
|
|
|
@ -165,8 +165,8 @@ void StackLinearChartView::prepareZoom(
|
|||
_transition.zoomedOutXIndices = c.xIndices;
|
||||
_transition.zoomedOutXPercentage = c.xPercentageLimits;
|
||||
} else if (step == TransitionStep::PrepareToZoomIn) {
|
||||
const auto &[zoomedStart, zoomedEnd] =
|
||||
_transition.zoomedOutXIndices;
|
||||
const auto &[zoomedStart, zoomedEnd]
|
||||
= _transition.zoomedOutXIndices;
|
||||
_transition.lines = std::vector<Transition::TransitionLine>(
|
||||
c.chartData.lines.size(),
|
||||
Transition::TransitionLine());
|
||||
|
@ -624,7 +624,7 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
|
|||
|
||||
if (selectedLineIndex >= 0) {
|
||||
const auto &line = c.chartData.lines[selectedLineIndex];
|
||||
auto sum = 0;
|
||||
auto sum = ChartValue(0);
|
||||
for (auto i = zoomedStart; i <= zoomedEnd; i++) {
|
||||
sum += line.y[i];
|
||||
}
|
||||
|
@ -669,8 +669,8 @@ void StackLinearChartView::paintZoomedFooter(
|
|||
0);
|
||||
|
||||
const auto next = std::clamp(i + offset, zoomedStart, zoomedEnd);
|
||||
const auto xPointPercentage =
|
||||
(xPercentage[next] - xPercentage[zoomedStart])
|
||||
const auto xPointPercentage
|
||||
= (xPercentage[next] - xPercentage[zoomedStart])
|
||||
/ (xPercentage[zoomedEnd] - xPercentage[zoomedStart]);
|
||||
const auto xPoint = leftStart + width * xPointPercentage;
|
||||
|
||||
|
|
|
@ -205,6 +205,7 @@ PRIVATE
|
|||
statistics/statistics_data_deserialize.h
|
||||
statistics/statistics_format_values.cpp
|
||||
statistics/statistics_format_values.h
|
||||
statistics/statistics_types.h
|
||||
statistics/view/abstract_chart_view.cpp
|
||||
statistics/view/abstract_chart_view.h
|
||||
statistics/view/bar_chart_view.cpp
|
||||
|
|
Loading…
Add table
Reference in a new issue