mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +02:00
Added support of percentages display to details widget.
This commit is contained in:
parent
515850ec9b
commit
fc3acff5d6
9 changed files with 187 additions and 80 deletions
|
@ -63,6 +63,7 @@ struct StatisticalChart {
|
|||
float64 timeStep = 0.;
|
||||
|
||||
bool isFooterHidden = false;
|
||||
bool hasPercentages = false;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -8,6 +8,8 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "statistics/point_details_widget.h"
|
||||
|
||||
#include "ui/cached_round_corners.h"
|
||||
#include "statistics/statistics_common.h"
|
||||
#include "statistics/view/stack_linear_chart_common.h"
|
||||
#include "ui/effects/ripple_animation.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
|
@ -155,6 +157,16 @@ PointDetailsWidget::PointDetailsWidget(
|
|||
}, lifetime());
|
||||
}
|
||||
|
||||
_maxPercentageWidth = [&] {
|
||||
if (_chartData.hasPercentages) {
|
||||
const auto maxPercentageText = Ui::Text::String(
|
||||
_textStyle,
|
||||
u"10000%"_q);
|
||||
return maxPercentageText.maxWidth();
|
||||
}
|
||||
return 0;
|
||||
}();
|
||||
|
||||
const auto calculatedWidth = [&]{
|
||||
const auto maxValueText = Ui::Text::String(
|
||||
_textStyle,
|
||||
|
@ -186,7 +198,8 @@ PointDetailsWidget::PointDetailsWidget(
|
|||
+ rect::m::sum::h(st::statisticsDetailsPopupMargins)
|
||||
+ rect::m::sum::h(st::statisticsDetailsPopupPadding)
|
||||
+ st::statisticsDetailsPopupPadding.left() // Between strings.
|
||||
+ maxNameTextWidth;
|
||||
+ maxNameTextWidth
|
||||
+ _maxPercentageWidth;
|
||||
}();
|
||||
sizeValue(
|
||||
) | rpl::start_with_next([=](const QSize &s) {
|
||||
|
@ -245,9 +258,19 @@ void PointDetailsWidget::setXIndex(int xIndex) {
|
|||
_lines.clear();
|
||||
_lines.reserve(_chartData.lines.size());
|
||||
auto hasPositiveValues = false;
|
||||
for (const auto &dataLine : _chartData.lines) {
|
||||
const auto parts = _maxPercentageWidth
|
||||
? PiePartsPercentage(
|
||||
_chartData,
|
||||
nullptr,
|
||||
{ float64(xIndex), float64(xIndex) }).parts
|
||||
: std::vector<PiePartData::Part>();
|
||||
for (auto i = 0; i < _chartData.lines.size(); i++) {
|
||||
const auto &dataLine = _chartData.lines[i];
|
||||
auto textLine = Line();
|
||||
textLine.id = dataLine.id;
|
||||
if (_maxPercentageWidth) {
|
||||
textLine.percentage.setText(_textStyle, parts[i].percentageText);
|
||||
}
|
||||
textLine.name.setText(_textStyle, dataLine.name);
|
||||
textLine.value.setText(
|
||||
_textStyle,
|
||||
|
@ -353,12 +376,22 @@ void PointDetailsWidget::paintEvent(QPaintEvent *e) {
|
|||
.availableWidth = valueWidth,
|
||||
};
|
||||
const auto nameContext = Ui::Text::PaintContext{
|
||||
.position = QPoint(_textRect.x(), lineY),
|
||||
.position = QPoint(
|
||||
_textRect.x() + _maxPercentageWidth,
|
||||
lineY),
|
||||
.outerWidth = _textRect.width(),
|
||||
.availableWidth = _textRect.width() - valueWidth,
|
||||
};
|
||||
p.setOpacity(line.alpha * line.alpha);
|
||||
p.setPen(st::boxTextFg);
|
||||
if (_maxPercentageWidth) {
|
||||
const auto percentageContext = Ui::Text::PaintContext{
|
||||
.position = QPoint(_textRect.x(), lineY),
|
||||
.outerWidth = _textRect.width(),
|
||||
.availableWidth = _textRect.width() - valueWidth,
|
||||
};
|
||||
line.percentage.draw(p, percentageContext);
|
||||
}
|
||||
line.name.draw(p, nameContext);
|
||||
p.setPen(line.valueColor);
|
||||
line.value.draw(p, valueContext);
|
||||
|
|
|
@ -60,10 +60,13 @@ private:
|
|||
int id = 0;
|
||||
Ui::Text::String name;
|
||||
Ui::Text::String value;
|
||||
Ui::Text::String percentage;
|
||||
QColor valueColor;
|
||||
float64 alpha = 1.;
|
||||
};
|
||||
|
||||
int _maxPercentageWidth = 0;
|
||||
|
||||
QRect _innerRect;
|
||||
QRect _textRect;
|
||||
QImage _arrow;
|
||||
|
|
|
@ -109,6 +109,15 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
|
|||
result.defaultZoomXIndex.min = std::min(min, max);
|
||||
result.defaultZoomXIndex.max = std::max(min, max);
|
||||
}
|
||||
{
|
||||
|
||||
const auto percentageShowIt = root.constFind(u"percentage"_q);
|
||||
if (percentageShowIt != root.constEnd()) {
|
||||
if (percentageShowIt->isBool()) {
|
||||
result.hasPercentages = (percentageShowIt->toBool());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto colors = root.value(u"colors"_q).toObject();
|
||||
const auto names = root.value(u"names"_q).toObject();
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
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/view/stack_linear_chart_common.h"
|
||||
|
||||
#include "data/data_statistics_chart.h"
|
||||
#include "statistics/chart_lines_filter_controller.h"
|
||||
#include "statistics/statistics_common.h"
|
||||
|
||||
namespace Statistic {
|
||||
|
||||
PiePartData PiePartsPercentage(
|
||||
const Data::StatisticalChart &chartData,
|
||||
const std::shared_ptr<LinesFilterController> &linesFilter,
|
||||
const Limits &xIndices) {
|
||||
auto result = PiePartData();
|
||||
result.parts.reserve(chartData.lines.size());
|
||||
auto sums = std::vector<float64>();
|
||||
sums.reserve(chartData.lines.size());
|
||||
auto totalSum = 0.;
|
||||
for (const auto &line : chartData.lines) {
|
||||
auto sum = 0;
|
||||
for (auto i = xIndices.min; i <= xIndices.max; i++) {
|
||||
sum += line.y[i];
|
||||
}
|
||||
if (linesFilter) {
|
||||
sum *= linesFilter->alpha(line.id);
|
||||
}
|
||||
totalSum += sum;
|
||||
sums.push_back(sum);
|
||||
}
|
||||
auto stackedPercentage = 0.;
|
||||
|
||||
auto sumPercDiffs = 0.;
|
||||
auto maxPercDiff = 0.;
|
||||
auto minPercDiff = 0.;
|
||||
auto maxPercDiffIndex = int(-1);
|
||||
auto minPercDiffIndex = int(-1);
|
||||
auto roundedPercentagesSum = 0.;
|
||||
|
||||
result.pieHasSinglePart = false;
|
||||
constexpr auto kPerChar = '%';
|
||||
for (auto k = 0; k < sums.size(); k++) {
|
||||
const auto rawPercentage = totalSum ? (sums[k] / totalSum) : 0.;
|
||||
const auto rounded = 0.01 * std::round(rawPercentage * 100.);
|
||||
roundedPercentagesSum += rounded;
|
||||
const auto diff = rawPercentage - rounded;
|
||||
sumPercDiffs += diff;
|
||||
const auto diffAbs = std::abs(diff);
|
||||
if (maxPercDiff < diffAbs) {
|
||||
maxPercDiff = diffAbs;
|
||||
maxPercDiffIndex = k;
|
||||
}
|
||||
if (minPercDiff < diffAbs) {
|
||||
minPercDiff = diffAbs;
|
||||
minPercDiffIndex = k;
|
||||
}
|
||||
|
||||
stackedPercentage += rounded;
|
||||
result.parts.push_back({
|
||||
rounded,
|
||||
stackedPercentage * 360. - 180.,
|
||||
QString::number(int(rounded * 100)) + kPerChar,
|
||||
});
|
||||
result.pieHasSinglePart |= (rounded == 1.);
|
||||
}
|
||||
{
|
||||
const auto index = (roundedPercentagesSum > 1.)
|
||||
? maxPercDiffIndex
|
||||
: minPercDiffIndex;
|
||||
if (index >= 0) {
|
||||
result.parts[index].roundedPercentage += sumPercDiffs;
|
||||
result.parts[index].percentageText = QString::number(
|
||||
int(result.parts[index].roundedPercentage * 100)) + kPerChar;
|
||||
const auto angleShrink = (sumPercDiffs) * 360.;
|
||||
for (auto &part : result.parts) {
|
||||
part.stackedAngle += angleShrink;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Statistic
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
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 Data {
|
||||
struct StatisticalChart;
|
||||
} // namespace Data
|
||||
|
||||
namespace Statistic {
|
||||
|
||||
struct Limits;
|
||||
class LinesFilterController;
|
||||
|
||||
struct PiePartData final {
|
||||
struct Part final {
|
||||
float64 roundedPercentage = 0; // 0.XX.
|
||||
float64 stackedAngle = 0.;
|
||||
QString percentageText;
|
||||
};
|
||||
std::vector<Part> parts;
|
||||
bool pieHasSinglePart = false;
|
||||
};
|
||||
|
||||
[[nodiscard]] PiePartData PiePartsPercentage(
|
||||
const Data::StatisticalChart &chartData,
|
||||
const std::shared_ptr<LinesFilterController> &linesFilter,
|
||||
const Limits &xIndices);
|
||||
|
||||
} // namespace Statistic
|
|
@ -166,7 +166,8 @@ void StackLinearChartView::prepareZoom(
|
|||
}
|
||||
}
|
||||
|
||||
void StackLinearChartView::applyParts(const std::vector<PiePartData> &parts) {
|
||||
void StackLinearChartView::applyParts(
|
||||
const std::vector<PiePartData::Part> &parts) {
|
||||
for (auto k = 0; k < parts.size(); k++) {
|
||||
_transition.lines[k].angle = parts[k].stackedAngle;
|
||||
}
|
||||
|
@ -184,72 +185,12 @@ void StackLinearChartView::saveZoomRange(const PaintContext &c) {
|
|||
}
|
||||
|
||||
void StackLinearChartView::savePieTextParts(const PaintContext &c) {
|
||||
_transition.textParts = partsPercentage(
|
||||
auto data = PiePartsPercentage(
|
||||
c.chartData,
|
||||
linesFilterController(),
|
||||
_transition.zoomedInRangeXIndices);
|
||||
}
|
||||
|
||||
auto StackLinearChartView::partsPercentage(
|
||||
const Data::StatisticalChart &chartData,
|
||||
const Limits &xIndices) -> std::vector<PiePartData> {
|
||||
auto result = std::vector<PiePartData>();
|
||||
result.reserve(chartData.lines.size());
|
||||
auto sums = std::vector<float64>();
|
||||
sums.reserve(chartData.lines.size());
|
||||
auto totalSum = 0.;
|
||||
const auto &linesFilter = linesFilterController();
|
||||
for (const auto &line : chartData.lines) {
|
||||
auto sum = 0;
|
||||
for (auto i = xIndices.min; i <= xIndices.max; i++) {
|
||||
sum += line.y[i];
|
||||
}
|
||||
sum *= linesFilter->alpha(line.id);
|
||||
totalSum += sum;
|
||||
sums.push_back(sum);
|
||||
}
|
||||
auto stackedPercentage = 0.;
|
||||
|
||||
auto sumPercDiffs = 0.;
|
||||
auto maxPercDiff = 0.;
|
||||
auto minPercDiff = 0.;
|
||||
auto maxPercDiffIndex = int(-1);
|
||||
auto minPercDiffIndex = int(-1);
|
||||
auto roundedPercentagesSum = 0.;
|
||||
|
||||
_pieHasSinglePart = false;
|
||||
for (auto k = 0; k < sums.size(); k++) {
|
||||
const auto rawPercentage = totalSum ? (sums[k] / totalSum) : 0.;
|
||||
const auto rounded = 0.01 * std::round(rawPercentage * 100.);
|
||||
roundedPercentagesSum += rounded;
|
||||
const auto diff = rawPercentage - rounded;
|
||||
sumPercDiffs += diff;
|
||||
const auto diffAbs = std::abs(diff);
|
||||
if (maxPercDiff < diffAbs) {
|
||||
maxPercDiff = diffAbs;
|
||||
maxPercDiffIndex = k;
|
||||
}
|
||||
if (minPercDiff < diffAbs) {
|
||||
minPercDiff = diffAbs;
|
||||
minPercDiffIndex = k;
|
||||
}
|
||||
|
||||
stackedPercentage += rounded;
|
||||
result.push_back({ rounded, stackedPercentage * 360. - 180. });
|
||||
_pieHasSinglePart |= (rounded == 1.);
|
||||
}
|
||||
{
|
||||
const auto index = (roundedPercentagesSum > 1.)
|
||||
? maxPercDiffIndex
|
||||
: minPercDiffIndex;
|
||||
if (index >= 0) {
|
||||
result[index].roundedPercentage += sumPercDiffs;
|
||||
const auto angleShrink = (sumPercDiffs) * 360.;
|
||||
for (auto i = index; i < result.size(); i++) {
|
||||
result[i].stackedAngle += angleShrink;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
_transition.textParts = std::move(data.parts);
|
||||
_pieHasSinglePart = data.pieHasSinglePart;
|
||||
}
|
||||
|
||||
void StackLinearChartView::paintChartOrZoomAnimation(
|
||||
|
@ -564,9 +505,12 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
|
|||
}
|
||||
|
||||
saveZoomRange(c);
|
||||
const auto parts = partsPercentage(
|
||||
const auto partsData = PiePartsPercentage(
|
||||
c.chartData,
|
||||
linesFilterController(),
|
||||
_transition.zoomedInRangeXIndices);
|
||||
_pieHasSinglePart = partsData.pieHasSinglePart;
|
||||
const auto &parts = partsData.parts;
|
||||
applyParts(parts);
|
||||
|
||||
p.fillRect(c.rect + QMargins(0, 0, 0, st::lineWidth), st::boxBg);
|
||||
|
@ -726,7 +670,7 @@ void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) {
|
|||
const auto scale = (maxScale == minScale)
|
||||
? 0.
|
||||
: (minScale) + percentage * (maxScale - minScale);
|
||||
const auto text = QString::number(int(percentage * 100)) + u"%"_q;
|
||||
const auto text = parts[k].percentageText;
|
||||
const auto textW = font->width(text);
|
||||
const auto textH = font->height;
|
||||
const auto textXShift = textW / 2.;
|
||||
|
|
|
@ -10,6 +10,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "statistics/segment_tree.h"
|
||||
#include "statistics/statistics_common.h"
|
||||
#include "statistics/view/abstract_chart_view.h"
|
||||
#include "statistics/view/stack_linear_chart_common.h"
|
||||
#include "ui/effects/animations.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
|
||||
|
@ -65,19 +66,11 @@ private:
|
|||
|
||||
[[nodiscard]] bool skipSelectedTranslation() const;
|
||||
|
||||
struct PiePartData {
|
||||
float64 roundedPercentage = 0; // 0.XX.
|
||||
float64 stackedAngle = 0.;
|
||||
};
|
||||
|
||||
void prepareZoom(const PaintContext &c, TransitionStep step);
|
||||
|
||||
void saveZoomRange(const PaintContext &c);
|
||||
void savePieTextParts(const PaintContext &c);
|
||||
void applyParts(const std::vector<PiePartData> &parts);
|
||||
[[nodiscard]] std::vector<PiePartData> partsPercentage(
|
||||
const Data::StatisticalChart &chartData,
|
||||
const Limits &xIndices);
|
||||
void applyParts(const std::vector<PiePartData::Part> &parts);
|
||||
|
||||
struct SelectedPoints final {
|
||||
int lastXIndex = -1;
|
||||
|
@ -107,7 +100,7 @@ private:
|
|||
Limits zoomedInRange;
|
||||
Limits zoomedInRangeXIndices;
|
||||
|
||||
std::vector<PiePartData> textParts;
|
||||
std::vector<PiePartData::Part> textParts;
|
||||
} _transition;
|
||||
|
||||
std::vector<bool> _skipPoints;
|
||||
|
|
|
@ -189,6 +189,8 @@ PRIVATE
|
|||
statistics/view/stack_chart_common.h
|
||||
statistics/view/stack_chart_view.cpp
|
||||
statistics/view/stack_chart_view.h
|
||||
statistics/view/stack_linear_chart_common.cpp
|
||||
statistics/view/stack_linear_chart_common.h
|
||||
statistics/view/stack_linear_chart_view.cpp
|
||||
statistics/view/stack_linear_chart_view.h
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue