Slightly refactored code for statistical charts.

This commit is contained in:
23rd 2023-09-29 17:21:53 +03:00 committed by John Preston
parent af0e11a1aa
commit cb4c629178
7 changed files with 41 additions and 66 deletions

View file

@ -29,14 +29,14 @@ void StatisticalChart::measure() {
}
}
for (auto i = 0; i < lines.size(); i++) {
if (lines[i].maxValue > maxValue) {
maxValue = lines[i].maxValue;
for (auto &line : lines) {
if (line.maxValue > maxValue) {
maxValue = line.maxValue;
}
if (lines[i].minValue < minValue) {
minValue = lines[i].minValue;
if (line.minValue < minValue) {
minValue = line.minValue;
}
lines[i].segmentTree = Statistic::SegmentTree(lines[i].y);
line.segmentTree = Statistic::SegmentTree(line.y);
}
daysLookup.clear();

View file

@ -7,7 +7,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
*/
#include "statistics/chart_widget.h"
#include "ui/effects/show_animation.h"
#include "base/qt/qt_key_modifiers.h"
#include "lang/lang_keys.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 "ui/abstract_button.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/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 "styles/style_layers.h"
#include "styles/style_boxes.h"
#include "styles/style_statistics.h"
namespace Statistic {
@ -34,7 +32,6 @@ namespace Statistic {
namespace {
constexpr auto kHeightLimitsUpdateTimeout = crl::time(320);
constexpr auto kExpandingDelay = crl::time(1);
inline float64 InterpolationRatio(float64 from, float64 to, float64 result) {
return (result - from) / (to - from);
@ -78,10 +75,6 @@ void FillLineColorsByKey(Data::StatisticalChart &chartData) {
+ chartData.getDayString(limits.max);
}
[[nodiscard]] bool IsChartHasLocalZoom(ChartViewType type) {
return type == ChartViewType::StackLinear;
}
void PaintBottomLine(
QPainter &p,
const std::vector<ChartWidget::BottomCaptionLineData> &dates,
@ -213,13 +206,12 @@ class ChartWidget::Footer final : public RpMouseWidget {
public:
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);
[[nodiscard]] Limits xPercentageLimits() const;
[[nodiscard]] rpl::producer<Limits> xPercentageLimitsChange() const;
[[nodiscard]] rpl::producer<> userInteractionFinished() const;
void setPaintChartCallback(PaintCallback paintChartCallback);
@ -228,7 +220,6 @@ protected:
private:
rpl::event_stream<Limits> _xPercentageLimitsChange;
rpl::event_stream<> _userInteractionFinished;
void prepareCache(int height);
@ -338,7 +329,6 @@ ChartWidget::Footer::Footer(not_null<Ui::RpWidget*> parent)
case QEvent::MouseButtonRelease: {
const auto finish = [=] {
_dragArea = DragArea::None;
_userInteractionFinished.fire({});
fire();
};
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 r = rect();
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;
_frame.fill(Qt::transparent);
@ -524,10 +509,6 @@ rpl::producer<Limits> ChartWidget::Footer::xPercentageLimitsChange() const {
return _xPercentageLimitsChange.events();
}
rpl::producer<> ChartWidget::Footer::userInteractionFinished() const {
return _userInteractionFinished.events();
}
ChartWidget::ChartAnimationController::ChartAnimationController(
Fn<void()> &&updateCallback)
: _animation(std::move(updateCallback)) {
@ -830,10 +811,6 @@ bool ChartWidget::ChartAnimationController::footerAnimating() const {
!= _animationValueFooterHeightMax.to());
}
bool ChartWidget::ChartAnimationController::isFPSSlow() const {
return _benchmark.lastFPSSlow;
}
ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
: Ui::RpWidget(parent)
, _chartArea(base::make_unique_q<RpMouseWidget>(this))

View file

@ -83,7 +83,6 @@ private:
[[nodiscard]] Limits finalHeightLimits() const;
[[nodiscard]] bool animating() const;
[[nodiscard]] bool footerAnimating() const;
[[nodiscard]] bool isFPSSlow() const;
[[nodiscard]] rpl::producer<> addHorizontalLineRequests() const;

View file

@ -37,7 +37,7 @@ void SegmentTree::build(int v, int from, int size) {
_heap[v].max = _array[from];
_heap[v].min = _array[from];
} else {
// Build childs.
// Build children.
build(2 * v, from, size / 2);
build(2 * v + 1, from + size / 2, size - size / 2);

View file

@ -21,19 +21,4 @@ enum class ChartViewType {
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

View file

@ -18,7 +18,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
namespace Statistic {
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;
}

View file

@ -218,7 +218,7 @@ auto StackLinearChartView::partsPercentage(
_pieHasSinglePart = false;
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.);
roundedPercentagesSum += rounded;
const auto diff = rawPercentage - rounded;
@ -342,13 +342,16 @@ void StackLinearChartView::paintChartOrZoomAnimation(
for (auto k = 0; k < c.chartData.lines.size(); k++) {
const auto &line = c.chartData.lines[k];
const auto isLastLine = (k == lastEnabled);
const auto &transitionLine = hasTransitionAnimation
? _transition.lines[k]
: Transition::TransitionLine();
const auto lineAlpha = linesFilter->alpha(line.id);
if (isLastLine && (lineAlpha < 1.)) {
hasEmptyPoint = true;
}
if (!lineAlpha) {
continue;
}
const auto &transitionLine = hasTransitionAnimation
? _transition.lines[k]
: Transition::TransitionLine();
const auto &y = line.y;
auto &chartPath = paths[k];
@ -357,7 +360,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
? float64(y[i] ? lineAlpha : 0.)
: float64(sum ? (y[i] * lineAlpha / sum) : 0.);
if (!yPercentage && isLastLine) {
if (isLastLine && !yPercentage) {
hasEmptyPoint = true;
}
const auto height = yPercentage * c.rect.height();
@ -425,7 +428,9 @@ void StackLinearChartView::paintChartOrZoomAnimation(
}
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)
? rotate(
_transition.progress * angle
@ -495,7 +500,9 @@ void StackLinearChartView::paintChartOrZoomAnimation(
: rect::right(c.rect));
}
} 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);
}
if (hasEmptyPoint) {
p.fillRect(c.rect, st::boxDividerBg);
}
const auto opacity = c.footer ? (1. - _transition.progress) : 1.;
for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) {
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 textAngle = (previous + kPieAngleOffset)
+ (now - previous) / 2.;
const auto textAngle = (now == previous)
? 0.
: ((previous + kPieAngleOffset) + (now - previous) / 2.);
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 textW = font->width(text);
const auto textH = font->height;
@ -753,7 +767,7 @@ bool StackLinearChartView::PiePartController::set(int id) {
void StackLinearChartView::PiePartController::update(int id) {
if (id >= 0) {
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.;
_startedAt[id] = crl::now() - (st::slideWrapDuration * progress);
}
@ -804,10 +818,8 @@ void StackLinearChartView::handleMouseMove(
}
const auto center = rect.center();
const auto theta = std::atan2(center.y() - p.y(), (center.x() - p.x()));
const auto angle = [&] {
const auto a = theta * (180. / M_PI) + 90.;
return (a > 180.) ? (a - 360.) : a;
}();
const auto rawAngle = theta * (180. / M_PI) + 90.;
const auto angle = (rawAngle > 180.) ? (rawAngle - 360.) : rawAngle;
for (auto k = 0; k < chartData.lines.size(); k++) {
const auto previous = k
? _transition.lines[k - 1].angle