mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-05 06:33:57 +02:00
Added ability to use BarChartView as non-stack as well.
This commit is contained in:
parent
b7346c203a
commit
44f6280d0a
6 changed files with 129 additions and 16 deletions
|
@ -189,11 +189,11 @@ void FillStatistic(
|
||||||
addChart(
|
addChart(
|
||||||
stats.channel.viewCountBySourceGraph,
|
stats.channel.viewCountBySourceGraph,
|
||||||
tr::lng_chart_title_view_count_by_source(),
|
tr::lng_chart_title_view_count_by_source(),
|
||||||
Type::Stack);
|
Type::StackBar);
|
||||||
addChart(
|
addChart(
|
||||||
stats.channel.joinBySourceGraph,
|
stats.channel.joinBySourceGraph,
|
||||||
tr::lng_chart_title_join_by_source(),
|
tr::lng_chart_title_join_by_source(),
|
||||||
Type::Stack);
|
Type::StackBar);
|
||||||
addChart(
|
addChart(
|
||||||
stats.channel.languageGraph,
|
stats.channel.languageGraph,
|
||||||
tr::lng_chart_title_language(),
|
tr::lng_chart_title_language(),
|
||||||
|
@ -218,7 +218,7 @@ void FillStatistic(
|
||||||
addChart(
|
addChart(
|
||||||
stats.supergroup.joinBySourceGraph,
|
stats.supergroup.joinBySourceGraph,
|
||||||
tr::lng_chart_title_group_join_by_source(),
|
tr::lng_chart_title_group_join_by_source(),
|
||||||
Type::Stack);
|
Type::StackBar);
|
||||||
addChart(
|
addChart(
|
||||||
stats.supergroup.languageGraph,
|
stats.supergroup.languageGraph,
|
||||||
tr::lng_chart_title_group_language(),
|
tr::lng_chart_title_group_language(),
|
||||||
|
@ -226,7 +226,7 @@ void FillStatistic(
|
||||||
addChart(
|
addChart(
|
||||||
stats.supergroup.messageContentGraph,
|
stats.supergroup.messageContentGraph,
|
||||||
tr::lng_chart_title_group_message_content(),
|
tr::lng_chart_title_group_message_content(),
|
||||||
Type::Stack);
|
Type::StackBar);
|
||||||
addChart(
|
addChart(
|
||||||
stats.supergroup.actionGraph,
|
stats.supergroup.actionGraph,
|
||||||
tr::lng_chart_title_group_action(),
|
tr::lng_chart_title_group_action(),
|
||||||
|
|
|
@ -1462,7 +1462,7 @@ void ChartWidget::setChartData(
|
||||||
_chartView = CreateChartView(type);
|
_chartView = CreateChartView(type);
|
||||||
_chartView->setLinesFilterController(_linesFilterController);
|
_chartView->setLinesFilterController(_linesFilterController);
|
||||||
_rulersView.setChartData(_chartData, type, _linesFilterController);
|
_rulersView.setChartData(_chartData, type, _linesFilterController);
|
||||||
_areRulersAbove = (type == ChartViewType::Stack);
|
_areRulersAbove = (type == ChartViewType::StackBar);
|
||||||
|
|
||||||
if (_chartData.isFooterHidden) {
|
if (_chartData.isFooterHidden) {
|
||||||
_footer->hide();
|
_footer->hide();
|
||||||
|
|
|
@ -18,7 +18,8 @@ struct Limits final {
|
||||||
|
|
||||||
enum class ChartViewType {
|
enum class ChartViewType {
|
||||||
Linear,
|
Linear,
|
||||||
Stack,
|
Bar,
|
||||||
|
StackBar,
|
||||||
DoubleLinear,
|
DoubleLinear,
|
||||||
StackLinear,
|
StackLinear,
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,10 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#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"
|
||||||
|
#include "ui/rect.h"
|
||||||
|
#include "styles/style_statistics.h"
|
||||||
|
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
|
|
||||||
BarChartView::BarChartView() = default;
|
BarChartView::BarChartView(bool isStack)
|
||||||
|
: _isStack(isStack)
|
||||||
|
, _cachedLineRatios(false) {
|
||||||
|
}
|
||||||
|
|
||||||
BarChartView::~BarChartView() = default;
|
BarChartView::~BarChartView() = default;
|
||||||
|
|
||||||
void BarChartView::paint(QPainter &p, const PaintContext &c) {
|
void BarChartView::paint(QPainter &p, const PaintContext &c) {
|
||||||
|
@ -40,6 +46,8 @@ void BarChartView::paintChartAndSelected(
|
||||||
c.rect,
|
c.rect,
|
||||||
localStart);
|
localStart);
|
||||||
|
|
||||||
|
p.setClipRect(0, 0, c.rect.width() * 2, rect::bottom(c.rect));
|
||||||
|
|
||||||
const auto opacity = p.opacity();
|
const auto opacity = p.opacity();
|
||||||
auto hq = PainterHighQualityEnabler(p);
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
|
||||||
|
@ -47,7 +55,9 @@ void BarChartView::paintChartAndSelected(
|
||||||
localEnd - localStart + 1,
|
localEnd - localStart + 1,
|
||||||
-c.rect.y());
|
-c.rect.y());
|
||||||
auto selectedBottoms = std::vector<float64>();
|
auto selectedBottoms = std::vector<float64>();
|
||||||
const auto hasSelectedXIndex = !c.footer && (_lastSelectedXIndex >= 0);
|
const auto hasSelectedXIndex = _isStack
|
||||||
|
&& !c.footer
|
||||||
|
&& (_lastSelectedXIndex >= 0);
|
||||||
if (hasSelectedXIndex) {
|
if (hasSelectedXIndex) {
|
||||||
selectedBottoms = std::vector<float64>(c.chartData.lines.size(), 0);
|
selectedBottoms = std::vector<float64>(c.chartData.lines.size(), 0);
|
||||||
constexpr auto kSelectedAlpha = 0.5;
|
constexpr auto kSelectedAlpha = 0.5;
|
||||||
|
@ -77,10 +87,27 @@ void BarChartView::paintChartAndSelected(
|
||||||
if (hasSelectedXIndex && (x == _lastSelectedXIndex)) {
|
if (hasSelectedXIndex && (x == _lastSelectedXIndex)) {
|
||||||
selectedBottoms[i] = column.y();
|
selectedBottoms[i] = column.y();
|
||||||
}
|
}
|
||||||
path.addRect(column);
|
if (_isStack) {
|
||||||
bottoms[bottomIndex] += yPoint;
|
path.addRect(column);
|
||||||
|
bottoms[bottomIndex] += yPoint;
|
||||||
|
} else {
|
||||||
|
if (path.isEmpty()) {
|
||||||
|
path.moveTo(column.topLeft());
|
||||||
|
} else {
|
||||||
|
path.lineTo(column.topLeft());
|
||||||
|
}
|
||||||
|
if (x == localEnd) {
|
||||||
|
path.lineTo(c.rect.width(), column.y());
|
||||||
|
} else {
|
||||||
|
path.lineTo(rect::right(column), column.y());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (_isStack) {
|
||||||
|
p.fillPath(path, line.color);
|
||||||
|
} else {
|
||||||
|
p.strokePath(path, line.color);
|
||||||
}
|
}
|
||||||
p.fillPath(path, line.color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto i = 0; i < selectedBottoms.size(); i++) {
|
for (auto i = 0; i < selectedBottoms.size(); i++) {
|
||||||
|
@ -103,6 +130,8 @@ void BarChartView::paintChartAndSelected(
|
||||||
yPoint);
|
yPoint);
|
||||||
p.fillRect(column, line.color);
|
p.fillRect(column, line.color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.setClipping(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BarChartView::paintSelectedXIndex(
|
void BarChartView::paintSelectedXIndex(
|
||||||
|
@ -113,8 +142,73 @@ void BarChartView::paintSelectedXIndex(
|
||||||
const auto was = _lastSelectedXIndex;
|
const auto was = _lastSelectedXIndex;
|
||||||
_lastSelectedXIndex = selectedXIndex;
|
_lastSelectedXIndex = selectedXIndex;
|
||||||
_lastSelectedXProgress = progress;
|
_lastSelectedXProgress = progress;
|
||||||
if ((_lastSelectedXIndex >= 0) || (was >= 0)) {
|
|
||||||
BarChartView::paintChartAndSelected(p, c);
|
if (_isStack) {
|
||||||
|
if ((_lastSelectedXIndex >= 0) || (was >= 0)) {
|
||||||
|
BarChartView::paintChartAndSelected(p, c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const auto linesFilter = linesFilterController();
|
||||||
|
auto hq = PainterHighQualityEnabler(p);
|
||||||
|
auto o = ScopedPainterOpacity(p, progress);
|
||||||
|
p.setBrush(st::boxBg);
|
||||||
|
const auto r = st::statisticsDetailsDotRadius;
|
||||||
|
const auto i = selectedXIndex;
|
||||||
|
const auto isSameToken = _selectedPoints.isSame(selectedXIndex, c);
|
||||||
|
auto linePainted = false;
|
||||||
|
|
||||||
|
const auto &[localStart, localEnd] = _lastPaintedXIndices;
|
||||||
|
const auto &[leftStart, w] = ComputeLeftStartAndStep(
|
||||||
|
c.chartData,
|
||||||
|
c.xPercentageLimits,
|
||||||
|
c.rect,
|
||||||
|
localStart);
|
||||||
|
|
||||||
|
for (auto i = 0; i < c.chartData.lines.size(); i++) {
|
||||||
|
const auto &line = c.chartData.lines[i];
|
||||||
|
const auto lineAlpha = linesFilter->alpha(line.id);
|
||||||
|
const auto useCache = isSameToken
|
||||||
|
|| (lineAlpha < 1. && !linesFilter->isEnabled(line.id));
|
||||||
|
if (!useCache) {
|
||||||
|
// Calculate.
|
||||||
|
const auto x = _lastSelectedXIndex;
|
||||||
|
const auto yPercentage = (line.y[x] - c.heightLimits.min)
|
||||||
|
/ float64(c.heightLimits.max - c.heightLimits.min);
|
||||||
|
const auto yPoint = (1. - yPercentage) * c.rect.height();
|
||||||
|
|
||||||
|
const auto bottomIndex = x - localStart;
|
||||||
|
const auto column = QRectF(
|
||||||
|
leftStart + (x - localStart) * w,
|
||||||
|
c.rect.height() - 0 - yPoint,
|
||||||
|
w,
|
||||||
|
yPoint);
|
||||||
|
const auto xPoint = column.left() + column.width() / 2.;
|
||||||
|
_selectedPoints.points[line.id] = QPointF(xPoint, yPoint)
|
||||||
|
+ c.rect.topLeft();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!linePainted && lineAlpha) {
|
||||||
|
[[maybe_unused]] const auto o = ScopedPainterOpacity(
|
||||||
|
p,
|
||||||
|
p.opacity() * progress * kRulerLineAlpha);
|
||||||
|
const auto lineRect = QRectF(
|
||||||
|
begin(_selectedPoints.points)->second.x()
|
||||||
|
- (st::lineWidth / 2.),
|
||||||
|
c.rect.y(),
|
||||||
|
st::lineWidth,
|
||||||
|
c.rect.height());
|
||||||
|
p.fillRect(lineRect, st::boxTextFg);
|
||||||
|
linePainted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paint.
|
||||||
|
auto o = ScopedPainterOpacity(p, lineAlpha * p.opacity());
|
||||||
|
p.setPen(QPen(line.color, st::statisticsChartLineWidth));
|
||||||
|
p.drawEllipse(_selectedPoints.points[line.id], r, r);
|
||||||
|
}
|
||||||
|
_selectedPoints.lastXIndex = selectedXIndex;
|
||||||
|
_selectedPoints.lastHeightLimits = c.heightLimits;
|
||||||
|
_selectedPoints.lastXLimits = c.xPercentageLimits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +241,17 @@ int BarChartView::findXIndexByPosition(
|
||||||
AbstractChartView::HeightLimits BarChartView::heightLimits(
|
AbstractChartView::HeightLimits BarChartView::heightLimits(
|
||||||
Data::StatisticalChart &chartData,
|
Data::StatisticalChart &chartData,
|
||||||
Limits xIndices) {
|
Limits xIndices) {
|
||||||
|
if (!_isStack) {
|
||||||
|
if (!_cachedLineRatios) {
|
||||||
|
_cachedLineRatios.init(chartData);
|
||||||
|
}
|
||||||
|
|
||||||
|
return DefaultHeightLimits(
|
||||||
|
_cachedLineRatios,
|
||||||
|
linesFilterController(),
|
||||||
|
chartData,
|
||||||
|
xIndices);
|
||||||
|
}
|
||||||
_cachedHeightLimits = {};
|
_cachedHeightLimits = {};
|
||||||
if (_cachedHeightLimits.ySum.empty()) {
|
if (_cachedHeightLimits.ySum.empty()) {
|
||||||
_cachedHeightLimits.ySum.reserve(chartData.x.size());
|
_cachedHeightLimits.ySum.reserve(chartData.x.size());
|
||||||
|
|
|
@ -22,7 +22,7 @@ struct Limits;
|
||||||
|
|
||||||
class BarChartView final : public AbstractChartView {
|
class BarChartView final : public AbstractChartView {
|
||||||
public:
|
public:
|
||||||
BarChartView();
|
BarChartView(bool isStack);
|
||||||
~BarChartView() override final;
|
~BarChartView() override final;
|
||||||
|
|
||||||
void paint(QPainter &p, const PaintContext &c) override;
|
void paint(QPainter &p, const PaintContext &c) override;
|
||||||
|
@ -52,10 +52,14 @@ private:
|
||||||
SegmentTree ySumSegmentTree;
|
SegmentTree ySumSegmentTree;
|
||||||
} _cachedHeightLimits;
|
} _cachedHeightLimits;
|
||||||
|
|
||||||
|
const bool _isStack;
|
||||||
|
DoubleLineRatios _cachedLineRatios; // Non-stack.
|
||||||
Limits _lastPaintedXIndices;
|
Limits _lastPaintedXIndices;
|
||||||
int _lastSelectedXIndex = -1;
|
int _lastSelectedXIndex = -1;
|
||||||
float64 _lastSelectedXProgress = 0;
|
float64 _lastSelectedXProgress = 0;
|
||||||
|
|
||||||
|
CachedSelectedPoints _selectedPoints; // Non-stack.
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Statistic
|
} // namespace Statistic
|
||||||
|
|
|
@ -19,8 +19,11 @@ std::unique_ptr<AbstractChartView> CreateChartView(ChartViewType type) {
|
||||||
case ChartViewType::Linear: {
|
case ChartViewType::Linear: {
|
||||||
return std::make_unique<LinearChartView>(false);
|
return std::make_unique<LinearChartView>(false);
|
||||||
} break;
|
} break;
|
||||||
case ChartViewType::Stack: {
|
case ChartViewType::Bar: {
|
||||||
return std::make_unique<BarChartView>();
|
return std::make_unique<BarChartView>(false);
|
||||||
|
} break;
|
||||||
|
case ChartViewType::StackBar: {
|
||||||
|
return std::make_unique<BarChartView>(true);
|
||||||
} break;
|
} break;
|
||||||
case ChartViewType::DoubleLinear: {
|
case ChartViewType::DoubleLinear: {
|
||||||
return std::make_unique<LinearChartView>(true);
|
return std::make_unique<LinearChartView>(true);
|
||||||
|
|
Loading…
Add table
Reference in a new issue