Added ability to select part of pie chart.
This commit is contained in:
parent
bedefee1d1
commit
42215343cf
|
@ -47,6 +47,7 @@ statisticsDetailsBottomCaptionStyle: TextStyle(defaultTextStyle) {
|
|||
}
|
||||
|
||||
statisticsPieChartFont: font(20px);
|
||||
statisticsPieChartPartOffset: 8px;
|
||||
|
||||
statisticsChartHeaderHeight: 20px;
|
||||
statisticsHeaderTitleTextStyle: TextStyle(defaultTextStyle) {
|
||||
|
|
|
@ -437,10 +437,17 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
|
|||
|
||||
p.setBrush(c.chartData.lines[k].color);
|
||||
p.setPen(Qt::NoPen);
|
||||
const auto textAngle = (previous + kPieAngleOffset)
|
||||
+ (now - previous) / 2.;
|
||||
const auto partOffset = _piePartController.offset(
|
||||
c.chartData.lines[k].id,
|
||||
textAngle);
|
||||
p.translate(partOffset);
|
||||
p.drawPie(
|
||||
rectF,
|
||||
-(previous + kPieAngleOffset) * 16,
|
||||
-(now - previous) * 16);
|
||||
p.translate(-partOffset);
|
||||
}
|
||||
paintPieText(p, c);
|
||||
}
|
||||
|
@ -482,9 +489,14 @@ void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) {
|
|||
const auto textRect = QRectF(
|
||||
textRectCenter - QPointF(textXShift, textYShift),
|
||||
textRectCenter + QPointF(textXShift, textYShift));
|
||||
const auto partOffset = _piePartController.offset(
|
||||
c.chartData.lines[k].id,
|
||||
textAngle);
|
||||
p.setTransform(
|
||||
QTransform()
|
||||
.translate(textRectCenter.x(), textRectCenter.y())
|
||||
.translate(
|
||||
textRectCenter.x() + partOffset.x(),
|
||||
textRectCenter.y() + partOffset.y())
|
||||
.scale(scale, scale)
|
||||
.translate(-textRectCenter.x(), -textRectCenter.y()));
|
||||
p.setOpacity(opacity * alpha(c.chartData.lines[k].id));
|
||||
|
@ -493,6 +505,81 @@ void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) {
|
|||
p.resetTransform();
|
||||
}
|
||||
|
||||
void StackLinearChartView::setUpdateCallback(Fn<void()> callback) {
|
||||
if (callback) {
|
||||
_piePartAnimation.init([=] { callback(); });
|
||||
}
|
||||
}
|
||||
|
||||
bool StackLinearChartView::PiePartController::set(int id) {
|
||||
if (_selected != id) {
|
||||
update(_selected);
|
||||
_selected = id;
|
||||
update(_selected);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void StackLinearChartView::PiePartController::update(int id) {
|
||||
if (id >= 0) {
|
||||
const auto was = _startedAt[id];
|
||||
const auto p = (crl::now() - was) / st::slideWrapDuration;
|
||||
const auto progress = ((p > 0) && (p < 1)) ? (1. - p) : 0.;
|
||||
_startedAt[id] = crl::now() - (st::slideWrapDuration * progress);
|
||||
}
|
||||
}
|
||||
|
||||
float64 StackLinearChartView::PiePartController::progress(int id) {
|
||||
const auto it = _startedAt.find(id);
|
||||
if (it == end(_startedAt)) {
|
||||
return 0.;
|
||||
}
|
||||
const auto at = it->second;
|
||||
const auto show = (_selected == id);
|
||||
const auto progress = std::clamp(
|
||||
(crl::now() - at) / float64(st::slideWrapDuration),
|
||||
0.,
|
||||
1.);
|
||||
return std::clamp(show ? progress : (1. - progress), 0., 1.);
|
||||
}
|
||||
|
||||
QPointF StackLinearChartView::PiePartController::offset(
|
||||
LineId id,
|
||||
float64 angle) {
|
||||
const auto offset = st::statisticsPieChartPartOffset * progress(id);
|
||||
const auto radians = angle * M_PI / 180.;
|
||||
return { std::cos(radians) * offset, std::sin(radians) * offset };
|
||||
}
|
||||
|
||||
void StackLinearChartView::handleMouseMove(
|
||||
const Data::StatisticalChart &chartData,
|
||||
const QPoint ¢er,
|
||||
const QPoint &p) {
|
||||
if (_transitionProgress < 1) {
|
||||
return;
|
||||
}
|
||||
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;
|
||||
}();
|
||||
for (auto k = 0; k < chartData.lines.size(); k++) {
|
||||
const auto previous = k
|
||||
? _cachedTransition.lines[k - 1].angle
|
||||
: -180;
|
||||
const auto now = _cachedTransition.lines[k].angle;
|
||||
if (angle > previous && angle <= now) {
|
||||
if (_piePartController.set(chartData.lines[k].id)) {
|
||||
if (!_piePartAnimation.animating()) {
|
||||
_piePartAnimation.start();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void StackLinearChartView::paintSelectedXIndex(
|
||||
QPainter &p,
|
||||
const Data::StatisticalChart &chartData,
|
||||
|
@ -548,7 +635,9 @@ int StackLinearChartView::findXIndexByPosition(
|
|||
const Limits &xPercentageLimits,
|
||||
const QRect &rect,
|
||||
float64 x) {
|
||||
if (x < rect.x()) {
|
||||
if (_transitionProgress == 1.) {
|
||||
return -1;
|
||||
} else if (x < rect.x()) {
|
||||
return 0;
|
||||
} else if (x > (rect.x() + rect.width())) {
|
||||
return chartData.xPercentage.size() - 1;
|
||||
|
|
|
@ -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 "ui/effects/animations.h"
|
||||
#include "ui/effects/animation_value.h"
|
||||
|
||||
namespace Data {
|
||||
|
@ -61,6 +62,12 @@ public:
|
|||
void tick(crl::time now) override;
|
||||
void update(float64 dt) override;
|
||||
|
||||
void setUpdateCallback(Fn<void()> callback);
|
||||
void handleMouseMove(
|
||||
const Data::StatisticalChart &chartData,
|
||||
const QPoint ¢er,
|
||||
const QPoint &p);
|
||||
|
||||
private:
|
||||
struct PaintContext final {
|
||||
const Data::StatisticalChart &chartData;
|
||||
|
@ -115,6 +122,23 @@ private:
|
|||
|
||||
std::vector<bool> _skipPoints;
|
||||
|
||||
class PiePartController final {
|
||||
public:
|
||||
using LineId = int;
|
||||
bool set(LineId id);
|
||||
[[nodiscard]] float64 progress(LineId id);
|
||||
[[nodiscard]] QPointF offset(LineId id, float64 angle);
|
||||
|
||||
private:
|
||||
void update(LineId id);
|
||||
|
||||
base::flat_map<LineId, crl::time> _startedAt;
|
||||
LineId _selected = -1;
|
||||
|
||||
};
|
||||
PiePartController _piePartController;
|
||||
Ui::Animations::Basic _piePartAnimation;
|
||||
|
||||
};
|
||||
|
||||
} // namespace Statistic
|
||||
|
|
Loading…
Reference in New Issue