Fixed position of selected X in linear chart animations.

This commit is contained in:
23rd 2023-09-05 17:03:08 +03:00 committed by John Preston
parent 20c2250abb
commit 54d5358b75
9 changed files with 83 additions and 65 deletions

View File

@ -830,20 +830,6 @@ Limits ChartWidget::ChartAnimationController::finalHeightLimits() const {
return _finalHeightLimits; return _finalHeightLimits;
} }
float64 ChartWidget::ChartAnimationController::detailsProgress(
crl::time now,
const Limits &appearedOnXLimits) const {
const auto xLimitsChanged = false
|| (appearedOnXLimits.min != _animationValueXMin.to())
|| (appearedOnXLimits.max != _animationValueXMax.to());
return (_animation.animating() && xLimitsChanged)
? std::clamp(
(now - _animation.started()) / float64(kExpandingDelay),
0.,
1.)
: 0.;
}
bool ChartWidget::ChartAnimationController::animating() const { bool ChartWidget::ChartAnimationController::animating() const {
return _animation.animating(); return _animation.animating();
} }
@ -964,35 +950,6 @@ void ChartWidget::setupChartArea() {
PaintHorizontalLines(p, horizontalLine, chartRect); PaintHorizontalLines(p, horizontalLine, chartRect);
} }
const auto detailsAlpha = 1.
- _animationController.detailsProgress(
now,
_details.appearedOnXLimits);
if (_details.widget) {
if (!detailsAlpha && _details.currentX) {
_details.widget->hide();
_details.widget->setXIndex(-1);
_details.currentX = 0;
_details.appearedOnXLimits = {};
}
if (_details.currentX) {
const auto lineRect = QRectF(
_details.currentX - (st::lineWidth / 2.),
0,
st::lineWidth,
_chartArea->height());
const auto opacity = ScopedPainterOpacity(p, detailsAlpha);
p.fillRect(lineRect, st::windowSubTextFg);
_details.widget->setAlpha(detailsAlpha);
for (const auto &line : _chartData.lines) {
_details.widget->setLineAlpha(
line.id,
_chartView->alpha(line.id));
}
}
}
if (_chartData) { if (_chartData) {
// p.setRenderHint( // p.setRenderHint(
// QPainter::Antialiasing, // QPainter::Antialiasing,
@ -1020,16 +977,22 @@ void ChartWidget::setupChartArea() {
QRect(bottom.x(), bottom.y(), bottom.width(), st::lineWidth), QRect(bottom.x(), bottom.y(), bottom.width(), st::lineWidth),
st::windowSubTextFg); st::windowSubTextFg);
} }
if (_details.widget && (detailsAlpha > 0.)) { if (_details.widget) {
auto hq = PainterHighQualityEnabler(p); const auto detailsAlpha = _details.widget->alpha();
auto o = ScopedPainterOpacity(p, detailsAlpha);
for (const auto &line : _chartData.lines) {
_details.widget->setLineAlpha(
line.id,
_chartView->alpha(line.id));
}
_chartView->paintSelectedXIndex( _chartView->paintSelectedXIndex(
p, p,
_chartData, _chartData,
_animationController.currentXLimits(), _animationController.currentXLimits(),
_animationController.currentHeightLimits(), _animationController.currentHeightLimits(),
chartRect, chartRect,
_details.widget->xIndex()); _details.widget->xIndex(),
detailsAlpha);
} }
p.setPen(st::windowSubTextFg); p.setPen(st::windowSubTextFg);
@ -1158,6 +1121,12 @@ void ChartWidget::setupFooter() {
_footer->xPercentageLimitsChange( _footer->xPercentageLimitsChange(
) | rpl::start_with_next([=](Limits xPercentageLimits) { ) | rpl::start_with_next([=](Limits xPercentageLimits) {
const auto now = crl::now(); const auto now = crl::now();
if (_details.widget
&& (_details.widget->xIndex() >= 0)
&& !_details.animation.animating()) {
_details.hideOnAnimationEnd = true;
_details.animation.start();
}
_animationController.setXPercentageLimits( _animationController.setXPercentageLimits(
_chartData, _chartData,
xPercentageLimits, xPercentageLimits,
@ -1176,7 +1145,7 @@ void ChartWidget::setupFooter() {
void ChartWidget::setupDetails() { void ChartWidget::setupDetails() {
if (!_chartData) { if (!_chartData) {
_details = {}; _details.widget = nullptr;
_chartArea->update(); _chartArea->update();
return; return;
} }
@ -1229,23 +1198,26 @@ void ChartWidget::setupDetails() {
const auto nearestXIndex = std::distance( const auto nearestXIndex = std::distance(
begin(_chartData.xPercentage), begin(_chartData.xPercentage),
nearestXPercentageIt); nearestXPercentageIt);
_details.currentX = 0 const auto currentX = 0
+ chartRect.width() * InterpolationRatio( + chartRect.width() * InterpolationRatio(
currentXLimits.min, currentXLimits.min,
currentXLimits.max, currentXLimits.max,
*nearestXPercentageIt); *nearestXPercentageIt);
_details.appearedOnXLimits = currentXLimits; const auto xLeft = currentX
const auto xLeft = _details.currentX
- _details.widget->width(); - _details.widget->width();
const auto x = (xLeft >= 0) const auto x = (xLeft >= 0)
? xLeft ? xLeft
: ((_details.currentX : ((currentX
+ _details.widget->width() + _details.widget->width()
- _chartArea->width()) > 0) - _chartArea->width()) > 0)
? 0 ? 0
: _details.currentX; : currentX;
_details.widget->moveToLeft(x, _chartArea->y()); _details.widget->moveToLeft(x, _chartArea->y());
_details.widget->setXIndex(nearestXIndex); _details.widget->setXIndex(nearestXIndex);
if (_details.widget->isHidden()) {
_details.hideOnAnimationEnd = false;
_details.animation.start();
}
_details.widget->show(); _details.widget->show();
_chartArea->update(); _chartArea->update();
} break; } break;
@ -1253,6 +1225,26 @@ void ChartWidget::setupDetails() {
} break; } break;
} }
}, _details.widget->lifetime()); }, _details.widget->lifetime());
_details.animation.init([=](crl::time now) {
const auto value = std::clamp(
(now - _details.animation.started()) / float64(200),
0.,
1.);
const auto alpha = _details.hideOnAnimationEnd ? (1. - value) : value;
_chartArea->update();
if (_details.widget) {
_details.widget->setAlpha(alpha);
_details.widget->update();
}
if (value >= 1.) {
if (_details.hideOnAnimationEnd && _details.widget) {
_details.widget->hide();
_details.widget->setXIndex(-1);
}
_details.animation.stop();
}
});
} }
void ChartWidget::setupFilterButtons() { void ChartWidget::setupFilterButtons() {

View File

@ -75,9 +75,6 @@ private:
[[nodiscard]] Limits currentHeightLimits() const; [[nodiscard]] Limits currentHeightLimits() const;
[[nodiscard]] Limits currentFooterHeightLimits() const; [[nodiscard]] Limits currentFooterHeightLimits() const;
[[nodiscard]] Limits finalHeightLimits() const; [[nodiscard]] Limits finalHeightLimits() const;
[[nodiscard]] float64 detailsProgress(
crl::time now,
const Limits &appearedOnXLimits) const;
[[nodiscard]] bool animating() const; [[nodiscard]] bool animating() const;
[[nodiscard]] bool footerAnimating() const; [[nodiscard]] bool footerAnimating() const;
[[nodiscard]] bool isFPSSlow() const; [[nodiscard]] bool isFPSSlow() const;
@ -146,8 +143,8 @@ private:
struct { struct {
base::unique_qptr<PointDetailsWidget> widget; base::unique_qptr<PointDetailsWidget> widget;
float64 currentX = 0; Ui::Animations::Basic animation;
Limits appearedOnXLimits; bool hideOnAnimationEnd = false;
} _details; } _details;
struct { struct {

View File

@ -143,6 +143,10 @@ void PointDetailsWidget::setAlpha(float64 alpha) {
update(); update();
} }
float64 PointDetailsWidget::alpha() const {
return _alpha;
}
int PointDetailsWidget::lineYAt(int index) const { int PointDetailsWidget::lineYAt(int index) const {
auto linesHeight = 0.; auto linesHeight = 0.;
for (auto i = 0; i < index; i++) { for (auto i = 0; i < index; i++) {
@ -186,7 +190,7 @@ void PointDetailsWidget::paintEvent(QPaintEvent *e) {
.outerWidth = _textRect.width() - valueWidth, .outerWidth = _textRect.width() - valueWidth,
.availableWidth = _textRect.width(), .availableWidth = _textRect.width(),
}; };
p.setOpacity(line.alpha * line.alpha); p.setOpacity(line.alpha * line.alpha * _alpha);
p.setPen(st::boxTextFg); p.setPen(st::boxTextFg);
line.name.draw(p, nameContext); line.name.draw(p, nameContext);
p.setPen(line.valueColor); p.setPen(line.valueColor);

View File

@ -23,6 +23,7 @@ public:
[[nodiscard]] int xIndex() const; [[nodiscard]] int xIndex() const;
void setXIndex(int xIndex); void setXIndex(int xIndex);
void setAlpha(float64 alpha); void setAlpha(float64 alpha);
[[nodiscard]] float64 alpha() const;
void setLineAlpha(int lineId, float64 alpha); void setLineAlpha(int lineId, float64 alpha);
protected: protected:

View File

@ -34,7 +34,8 @@ public:
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const Limits &heightLimits, const Limits &heightLimits,
const QRect &rect, const QRect &rect,
int selectedXIndex) = 0; int selectedXIndex,
float64 progress) = 0;
virtual void setEnabled(int id, bool enabled, crl::time now) = 0; virtual void setEnabled(int id, bool enabled, crl::time now) = 0;
[[nodiscard]] virtual bool isEnabled(int id) const = 0; [[nodiscard]] virtual bool isEnabled(int id) const = 0;

View File

@ -135,16 +135,22 @@ void LinearChartView::paintSelectedXIndex(
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const Limits &heightLimits, const Limits &heightLimits,
const QRect &rect, const QRect &rect,
int selectedXIndex) { int selectedXIndex,
float64 progress) {
if (selectedXIndex < 0) { if (selectedXIndex < 0) {
return; return;
} }
auto hq = PainterHighQualityEnabler(p);
auto o = ScopedPainterOpacity(p, progress);
p.setBrush(st::boxBg); p.setBrush(st::boxBg);
const auto r = st::statisticsDetailsDotRadius; const auto r = st::statisticsDetailsDotRadius;
const auto i = selectedXIndex; const auto i = selectedXIndex;
const auto isSameToken = (_selectedPoints.lastXIndex == selectedXIndex) const auto isSameToken = (_selectedPoints.lastXIndex == selectedXIndex)
&& (_selectedPoints.lastHeightLimits.min == heightLimits.min) && (_selectedPoints.lastHeightLimits.min == heightLimits.min)
&& (_selectedPoints.lastHeightLimits.max == heightLimits.max); && (_selectedPoints.lastHeightLimits.max == heightLimits.max)
&& (_selectedPoints.lastXLimits.min == xPercentageLimits.min)
&& (_selectedPoints.lastXLimits.max == xPercentageLimits.max);
auto linePainted = false;
for (const auto &line : chartData.lines) { for (const auto &line : chartData.lines) {
const auto lineAlpha = alpha(line.id); const auto lineAlpha = alpha(line.id);
const auto useCache = isSameToken const auto useCache = isSameToken
@ -161,6 +167,18 @@ void LinearChartView::paintSelectedXIndex(
+ rect.topLeft(); + rect.topLeft();
} }
if (!linePainted) {
const auto lineRect = QRectF(
rect.x()
+ begin(_selectedPoints.points)->second.x()
- (st::lineWidth / 2.),
rect.y(),
st::lineWidth,
rect.height());
p.fillRect(lineRect, st::windowSubTextFg);
linePainted = true;
}
// Paint. // Paint.
auto o = ScopedPainterOpacity(p, lineAlpha * p.opacity()); auto o = ScopedPainterOpacity(p, lineAlpha * p.opacity());
p.setPen(QPen(line.color, st::statisticsChartLineWidth)); p.setPen(QPen(line.color, st::statisticsChartLineWidth));
@ -168,6 +186,7 @@ void LinearChartView::paintSelectedXIndex(
} }
_selectedPoints.lastXIndex = selectedXIndex; _selectedPoints.lastXIndex = selectedXIndex;
_selectedPoints.lastHeightLimits = heightLimits; _selectedPoints.lastHeightLimits = heightLimits;
_selectedPoints.lastXLimits = xPercentageLimits;
} }
void LinearChartView::setEnabled(int id, bool enabled, crl::time now) { void LinearChartView::setEnabled(int id, bool enabled, crl::time now) {

View File

@ -38,7 +38,8 @@ public:
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const Limits &heightLimits, const Limits &heightLimits,
const QRect &rect, const QRect &rect,
int selectedXIndex) override; int selectedXIndex,
float64 progress) override;
void setEnabled(int id, bool enabled, crl::time now) override; void setEnabled(int id, bool enabled, crl::time now) override;
[[nodiscard]] bool isEnabled(int id) const override; [[nodiscard]] bool isEnabled(int id) const override;
@ -97,6 +98,7 @@ private:
struct SelectedPoints final { struct SelectedPoints final {
int lastXIndex = -1; int lastXIndex = -1;
Limits lastHeightLimits; Limits lastHeightLimits;
Limits lastXLimits;
base::flat_map<int, QPointF> points; base::flat_map<int, QPointF> points;
}; };
SelectedPoints _selectedPoints; SelectedPoints _selectedPoints;

View File

@ -94,7 +94,8 @@ void StackChartView::paintSelectedXIndex(
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const Limits &heightLimits, const Limits &heightLimits,
const QRect &rect, const QRect &rect,
int selectedXIndex) { int selectedXIndex,
float64 progress) {
} }
void StackChartView::setEnabled(int id, bool enabled, crl::time now) { void StackChartView::setEnabled(int id, bool enabled, crl::time now) {

View File

@ -39,7 +39,8 @@ public:
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const Limits &heightLimits, const Limits &heightLimits,
const QRect &rect, const QRect &rect,
int selectedXIndex) override; int selectedXIndex,
float64 progress) override;
void setEnabled(int id, bool enabled, crl::time now) override; void setEnabled(int id, bool enabled, crl::time now) override;
[[nodiscard]] bool isEnabled(int id) const override; [[nodiscard]] bool isEnabled(int id) const override;