mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-04-16 14:17:12 +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(
|
||||
stats.channel.viewCountBySourceGraph,
|
||||
tr::lng_chart_title_view_count_by_source(),
|
||||
Type::Stack);
|
||||
Type::StackBar);
|
||||
addChart(
|
||||
stats.channel.joinBySourceGraph,
|
||||
tr::lng_chart_title_join_by_source(),
|
||||
Type::Stack);
|
||||
Type::StackBar);
|
||||
addChart(
|
||||
stats.channel.languageGraph,
|
||||
tr::lng_chart_title_language(),
|
||||
|
@ -218,7 +218,7 @@ void FillStatistic(
|
|||
addChart(
|
||||
stats.supergroup.joinBySourceGraph,
|
||||
tr::lng_chart_title_group_join_by_source(),
|
||||
Type::Stack);
|
||||
Type::StackBar);
|
||||
addChart(
|
||||
stats.supergroup.languageGraph,
|
||||
tr::lng_chart_title_group_language(),
|
||||
|
@ -226,7 +226,7 @@ void FillStatistic(
|
|||
addChart(
|
||||
stats.supergroup.messageContentGraph,
|
||||
tr::lng_chart_title_group_message_content(),
|
||||
Type::Stack);
|
||||
Type::StackBar);
|
||||
addChart(
|
||||
stats.supergroup.actionGraph,
|
||||
tr::lng_chart_title_group_action(),
|
||||
|
|
|
@ -1462,7 +1462,7 @@ void ChartWidget::setChartData(
|
|||
_chartView = CreateChartView(type);
|
||||
_chartView->setLinesFilterController(_linesFilterController);
|
||||
_rulersView.setChartData(_chartData, type, _linesFilterController);
|
||||
_areRulersAbove = (type == ChartViewType::Stack);
|
||||
_areRulersAbove = (type == ChartViewType::StackBar);
|
||||
|
||||
if (_chartData.isFooterHidden) {
|
||||
_footer->hide();
|
||||
|
|
|
@ -18,7 +18,8 @@ struct Limits final {
|
|||
|
||||
enum class ChartViewType {
|
||||
Linear,
|
||||
Stack,
|
||||
Bar,
|
||||
StackBar,
|
||||
DoubleLinear,
|
||||
StackLinear,
|
||||
};
|
||||
|
|
|
@ -12,10 +12,16 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "statistics/view/stack_chart_common.h"
|
||||
#include "ui/effects/animation_value_f.h"
|
||||
#include "ui/painter.h"
|
||||
#include "ui/rect.h"
|
||||
#include "styles/style_statistics.h"
|
||||
|
||||
namespace Statistic {
|
||||
|
||||
BarChartView::BarChartView() = default;
|
||||
BarChartView::BarChartView(bool isStack)
|
||||
: _isStack(isStack)
|
||||
, _cachedLineRatios(false) {
|
||||
}
|
||||
|
||||
BarChartView::~BarChartView() = default;
|
||||
|
||||
void BarChartView::paint(QPainter &p, const PaintContext &c) {
|
||||
|
@ -40,6 +46,8 @@ void BarChartView::paintChartAndSelected(
|
|||
c.rect,
|
||||
localStart);
|
||||
|
||||
p.setClipRect(0, 0, c.rect.width() * 2, rect::bottom(c.rect));
|
||||
|
||||
const auto opacity = p.opacity();
|
||||
auto hq = PainterHighQualityEnabler(p);
|
||||
|
||||
|
@ -47,7 +55,9 @@ void BarChartView::paintChartAndSelected(
|
|||
localEnd - localStart + 1,
|
||||
-c.rect.y());
|
||||
auto selectedBottoms = std::vector<float64>();
|
||||
const auto hasSelectedXIndex = !c.footer && (_lastSelectedXIndex >= 0);
|
||||
const auto hasSelectedXIndex = _isStack
|
||||
&& !c.footer
|
||||
&& (_lastSelectedXIndex >= 0);
|
||||
if (hasSelectedXIndex) {
|
||||
selectedBottoms = std::vector<float64>(c.chartData.lines.size(), 0);
|
||||
constexpr auto kSelectedAlpha = 0.5;
|
||||
|
@ -77,10 +87,27 @@ void BarChartView::paintChartAndSelected(
|
|||
if (hasSelectedXIndex && (x == _lastSelectedXIndex)) {
|
||||
selectedBottoms[i] = column.y();
|
||||
}
|
||||
path.addRect(column);
|
||||
bottoms[bottomIndex] += yPoint;
|
||||
if (_isStack) {
|
||||
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++) {
|
||||
|
@ -103,6 +130,8 @@ void BarChartView::paintChartAndSelected(
|
|||
yPoint);
|
||||
p.fillRect(column, line.color);
|
||||
}
|
||||
|
||||
p.setClipping(false);
|
||||
}
|
||||
|
||||
void BarChartView::paintSelectedXIndex(
|
||||
|
@ -113,8 +142,73 @@ void BarChartView::paintSelectedXIndex(
|
|||
const auto was = _lastSelectedXIndex;
|
||||
_lastSelectedXIndex = selectedXIndex;
|
||||
_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(
|
||||
Data::StatisticalChart &chartData,
|
||||
Limits xIndices) {
|
||||
if (!_isStack) {
|
||||
if (!_cachedLineRatios) {
|
||||
_cachedLineRatios.init(chartData);
|
||||
}
|
||||
|
||||
return DefaultHeightLimits(
|
||||
_cachedLineRatios,
|
||||
linesFilterController(),
|
||||
chartData,
|
||||
xIndices);
|
||||
}
|
||||
_cachedHeightLimits = {};
|
||||
if (_cachedHeightLimits.ySum.empty()) {
|
||||
_cachedHeightLimits.ySum.reserve(chartData.x.size());
|
||||
|
|
|
@ -22,7 +22,7 @@ struct Limits;
|
|||
|
||||
class BarChartView final : public AbstractChartView {
|
||||
public:
|
||||
BarChartView();
|
||||
BarChartView(bool isStack);
|
||||
~BarChartView() override final;
|
||||
|
||||
void paint(QPainter &p, const PaintContext &c) override;
|
||||
|
@ -52,10 +52,14 @@ private:
|
|||
SegmentTree ySumSegmentTree;
|
||||
} _cachedHeightLimits;
|
||||
|
||||
const bool _isStack;
|
||||
DoubleLineRatios _cachedLineRatios; // Non-stack.
|
||||
Limits _lastPaintedXIndices;
|
||||
int _lastSelectedXIndex = -1;
|
||||
float64 _lastSelectedXProgress = 0;
|
||||
|
||||
CachedSelectedPoints _selectedPoints; // Non-stack.
|
||||
|
||||
};
|
||||
|
||||
} // namespace Statistic
|
||||
|
|
|
@ -19,8 +19,11 @@ std::unique_ptr<AbstractChartView> CreateChartView(ChartViewType type) {
|
|||
case ChartViewType::Linear: {
|
||||
return std::make_unique<LinearChartView>(false);
|
||||
} break;
|
||||
case ChartViewType::Stack: {
|
||||
return std::make_unique<BarChartView>();
|
||||
case ChartViewType::Bar: {
|
||||
return std::make_unique<BarChartView>(false);
|
||||
} break;
|
||||
case ChartViewType::StackBar: {
|
||||
return std::make_unique<BarChartView>(true);
|
||||
} break;
|
||||
case ChartViewType::DoubleLinear: {
|
||||
return std::make_unique<LinearChartView>(true);
|
||||
|
|
Loading…
Add table
Reference in a new issue