Slightly refactored variables in stack linear chart view.

This commit is contained in:
23rd 2023-09-25 18:14:28 +03:00 committed by John Preston
parent 26c2e7f245
commit be17e2b919
2 changed files with 83 additions and 88 deletions

View file

@ -53,11 +53,11 @@ StackLinearChartView::StackLinearChartView() = default;
StackLinearChartView::~StackLinearChartView() = default; StackLinearChartView::~StackLinearChartView() = default;
void StackLinearChartView::paint(QPainter &p, const PaintContext &c) { void StackLinearChartView::paint(QPainter &p, const PaintContext &c) {
if (!_transitionProgress && !c.footer) { if (!_transition.progress && !c.footer) {
prepareZoom(c, TransitionStep::ZoomedOut); prepareZoom(c, TransitionStep::ZoomedOut);
} }
if (_pendingPrepareCachedTransition) { if (_transition.pendingPrepareToZoomIn) {
_pendingPrepareCachedTransition = false; _transition.pendingPrepareToZoomIn = false;
prepareZoom(c, TransitionStep::PrepareToZoomIn); prepareZoom(c, TransitionStep::PrepareToZoomIn);
} }
@ -69,7 +69,7 @@ void StackLinearChartView::prepareZoom(
TransitionStep step) { TransitionStep step) {
if (step == TransitionStep::ZoomedOut) { if (step == TransitionStep::ZoomedOut) {
constexpr auto kOffset = float64(2); constexpr auto kOffset = float64(2);
_cachedTransition.zoomedOutXIndices = { _transition.zoomedOutXIndices = {
float64(std::max(0., c.xIndices.min - kOffset)), float64(std::max(0., c.xIndices.min - kOffset)),
float64(std::min( float64(std::min(
float64(c.chartData.xPercentage.size() - 1), float64(c.chartData.xPercentage.size() - 1),
@ -77,14 +77,14 @@ void StackLinearChartView::prepareZoom(
}; };
} else if (step == TransitionStep::PrepareToZoomIn) { } else if (step == TransitionStep::PrepareToZoomIn) {
const auto &[zoomedStart, zoomedEnd] = const auto &[zoomedStart, zoomedEnd] =
_cachedTransition.zoomedOutXIndices; _transition.zoomedOutXIndices;
_cachedTransition.lines = std::vector<Transition::TransitionLine>( _transition.lines = std::vector<Transition::TransitionLine>(
c.chartData.lines.size(), c.chartData.lines.size(),
Transition::TransitionLine()); Transition::TransitionLine());
const auto xPercentageLimits = Limits{ const auto xPercentageLimits = Limits{
c.chartData.xPercentage[_cachedTransition.zoomedOutXIndices.min], c.chartData.xPercentage[_transition.zoomedOutXIndices.min],
c.chartData.xPercentage[_cachedTransition.zoomedOutXIndices.max], c.chartData.xPercentage[_transition.zoomedOutXIndices.max],
}; };
for (auto j = 0; j < 2; j++) { for (auto j = 0; j < 2; j++) {
@ -104,8 +104,8 @@ void StackLinearChartView::prepareZoom(
for (auto k = 0; k < c.chartData.lines.size(); k++) { for (auto k = 0; k < c.chartData.lines.size(); k++) {
auto &linePoint = (j auto &linePoint = (j
? _cachedTransition.lines[k].end ? _transition.lines[k].end
: _cachedTransition.lines[k].start); : _transition.lines[k].start);
const auto &line = c.chartData.lines[k]; const auto &line = c.chartData.lines[k];
if (!isEnabled(line.id)) { if (!isEnabled(line.id)) {
continue; continue;
@ -127,38 +127,38 @@ void StackLinearChartView::prepareZoom(
} }
savePieTextParts(c); savePieTextParts(c);
applyParts(_cachedTransition.textParts); applyParts(_transition.textParts);
} }
} }
void StackLinearChartView::applyParts(const std::vector<PiePartData> &parts) { void StackLinearChartView::applyParts(const std::vector<PiePartData> &parts) {
for (auto k = 0; k < parts.size(); k++) { for (auto k = 0; k < parts.size(); k++) {
_cachedTransition.lines[k].angle = parts[k].stackedAngle; _transition.lines[k].angle = parts[k].stackedAngle;
} }
} }
void StackLinearChartView::saveZoomRange(const PaintContext &c) { void StackLinearChartView::saveZoomRange(const PaintContext &c) {
const auto zoomedXPercentage = Limits{ const auto zoomedXPercentage = Limits{
anim::interpolateF( anim::interpolateF(
_localZoom.limit.min, _transition.zoomedInLimit.min,
_localZoom.limit.max, _transition.zoomedInLimit.max,
c.xPercentageLimits.min), c.xPercentageLimits.min),
anim::interpolateF( anim::interpolateF(
_localZoom.limit.min, _transition.zoomedInLimit.min,
_localZoom.limit.max, _transition.zoomedInLimit.max,
c.xPercentageLimits.max), c.xPercentageLimits.max),
}; };
const auto zoomedXIndices = FindNearestElements( const auto zoomedXIndices = FindNearestElements(
c.chartData.xPercentage, c.chartData.xPercentage,
zoomedXPercentage); zoomedXPercentage);
_localZoom.rangeIndices = zoomedXIndices; _transition.zoomedInRangeXIndices = zoomedXIndices;
_localZoom.range = zoomedXPercentage; _transition.zoomedInRange = zoomedXPercentage;
} }
void StackLinearChartView::savePieTextParts(const PaintContext &c) { void StackLinearChartView::savePieTextParts(const PaintContext &c) {
_cachedTransition.textParts = partsPercentage( _transition.textParts = partsPercentage(
c.chartData, c.chartData,
_localZoom.rangeIndices); _transition.zoomedInRangeXIndices);
} }
auto StackLinearChartView::partsPercentage( auto StackLinearChartView::partsPercentage(
@ -224,7 +224,7 @@ auto StackLinearChartView::partsPercentage(
void StackLinearChartView::paintChartOrZoomAnimation( void StackLinearChartView::paintChartOrZoomAnimation(
QPainter &p, QPainter &p,
const PaintContext &c) { const PaintContext &c) {
if (_transitionProgress == 1.) { if (_transition.progress == 1.) {
if (c.footer) { if (c.footer) {
paintZoomedFooter(p, c); paintZoomedFooter(p, c);
} else { } else {
@ -232,10 +232,10 @@ void StackLinearChartView::paintChartOrZoomAnimation(
} }
return p.setOpacity(0.); return p.setOpacity(0.);
} }
const auto hasTransitionAnimation = _transitionProgress && !c.footer; const auto hasTransitionAnimation = _transition.progress && !c.footer;
const auto &[localStart, localEnd] = c.footer const auto &[localStart, localEnd] = c.footer
? Limits{ 0., float64(c.chartData.xPercentage.size() - 1) } ? Limits{ 0., float64(c.chartData.xPercentage.size() - 1) }
: _cachedTransition.zoomedOutXIndices; : _transition.zoomedOutXIndices;
_skipPoints = std::vector<bool>(c.chartData.lines.size(), false); _skipPoints = std::vector<bool>(c.chartData.lines.size(), false);
auto paths = std::vector<QPainterPath>( auto paths = std::vector<QPainterPath>(
c.chartData.lines.size(), c.chartData.lines.size(),
@ -263,7 +263,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
if (hasTransitionAnimation) { if (hasTransitionAnimation) {
constexpr auto kStraightLinePart = 0.6; constexpr auto kStraightLinePart = 0.6;
straightLineProgress = std::clamp( straightLineProgress = std::clamp(
_transitionProgress / kStraightLinePart, _transition.progress / kStraightLinePart,
0., 0.,
1.); 1.);
auto rectPath = QPainterPath(); auto rectPath = QPainterPath();
@ -271,8 +271,8 @@ void StackLinearChartView::paintChartOrZoomAnimation(
const auto r = anim::interpolateF( const auto r = anim::interpolateF(
1., 1.,
kCircleSizeRatio, kCircleSizeRatio,
_transitionProgress); _transition.progress);
const auto per = anim::interpolateF(0., 100., _transitionProgress); const auto per = anim::interpolateF(0., 100., _transition.progress);
const auto side = (c.rect.width() / 2.) * r; const auto side = (c.rect.width() / 2.) * r;
const auto rectF = QRectF( const auto rectF = QRectF(
center - QPointF(side, side), center - QPointF(side, side),
@ -303,7 +303,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
for (auto k = 0; k < c.chartData.lines.size(); k++) { for (auto k = 0; k < c.chartData.lines.size(); k++) {
const auto &line = c.chartData.lines[k]; const auto &line = c.chartData.lines[k];
const auto isLastLine = (k == lastEnabled); const auto isLastLine = (k == lastEnabled);
const auto &transitionLine = _cachedTransition.lines[k]; const auto &transitionLine = _transition.lines[k];
if (!isEnabled(line.id)) { if (!isEnabled(line.id)) {
continue; continue;
} }
@ -358,7 +358,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
} }
if (resultPoint.x() >= center.x()) { if (resultPoint.x() >= center.x()) {
const auto resultAngle = _transitionProgress * angle; const auto resultAngle = _transition.progress * angle;
const auto rotated = rotate(resultAngle, resultPoint); const auto rotated = rotate(resultAngle, resultPoint);
resultPoint = QPointF( resultPoint = QPointF(
std::max(rotated.x(), center.x()), std::max(rotated.x(), center.x()),
@ -379,8 +379,8 @@ void StackLinearChartView::paintChartOrZoomAnimation(
+ center * straightLineProgress + center * straightLineProgress
+ resultPoint * revProgress; + resultPoint * revProgress;
} else { } else {
const auto resultAngle = _transitionProgress * angle const auto resultAngle = _transition.progress * angle
+ _transitionProgress * transitionLine.angle; + _transition.progress * transitionLine.angle;
resultPoint = rotate(resultAngle, resultPoint); resultPoint = rotate(resultAngle, resultPoint);
pointZero = rotate(resultAngle, pointZero); pointZero = rotate(resultAngle, pointZero);
} }
@ -391,8 +391,8 @@ void StackLinearChartView::paintChartOrZoomAnimation(
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) const auto local = (hasTransitionAnimation && !isLastLine)
? rotate( ? rotate(
_transitionProgress * angle _transition.progress * angle
+ _transitionProgress * transitionLine.angle, + _transition.progress * transitionLine.angle,
bottomLeft - QPointF(center.x(), 0)) bottomLeft - QPointF(center.x(), 0))
: bottomLeft; : bottomLeft;
chartPath.setFillRule(Qt::WindingFill); chartPath.setFillRule(Qt::WindingFill);
@ -400,7 +400,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
_skipPoints[k] = false; _skipPoints[k] = false;
} }
const auto yRatio = 1. - (isLastLine ? _transitionProgress : 0.); const auto yRatio = 1. - (isLastLine ? _transition.progress : 0.);
if ((!yPercentage) if ((!yPercentage)
&& (i > 0 && (y[i - 1] == 0)) && (i > 0 && (y[i - 1] == 0))
&& (i < localEnd && (y[i + 1] == 0)) && (i < localEnd && (y[i + 1] == 0))
@ -429,8 +429,8 @@ void StackLinearChartView::paintChartOrZoomAnimation(
} }
const auto local = rotate( const auto local = rotate(
_transitionProgress * angle _transition.progress * angle
+ _transitionProgress * transitionLine.angle, + _transition.progress * transitionLine.angle,
transitionLine.start); transitionLine.start);
const auto ending = true const auto ending = true
@ -473,7 +473,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
p.setClipPath(ovalPath); p.setClipPath(ovalPath);
} }
const auto opacity = c.footer ? (1. - _transitionProgress) : 1.; const auto opacity = c.footer ? (1. - _transition.progress) : 1.;
for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) { for (auto k = int(c.chartData.lines.size() - 1); k >= 0; k--) {
if (paths[k].isEmpty()) { if (paths[k].isEmpty()) {
continue; continue;
@ -487,7 +487,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
if (!c.footer) { if (!c.footer) {
constexpr auto kAlphaTextPart = 0.6; constexpr auto kAlphaTextPart = 0.6;
const auto progress = std::clamp( const auto progress = std::clamp(
(_transitionProgress - kAlphaTextPart) / (1. - kAlphaTextPart), (_transition.progress - kAlphaTextPart) / (1. - kAlphaTextPart),
0., 0.,
1.); 1.);
if (progress > 0) { if (progress > 0) {
@ -499,7 +499,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
} }
// Fix ugly outline. // Fix ugly outline.
if (!c.footer || !_transitionProgress) { if (!c.footer || !_transition.progress) {
p.setBrush(Qt::transparent); p.setBrush(Qt::transparent);
p.setPen(st::boxBg); p.setPen(st::boxBg);
p.drawPath(ovalPath); p.drawPath(ovalPath);
@ -508,7 +508,7 @@ void StackLinearChartView::paintChartOrZoomAnimation(
if (!ovalPath.isEmpty()) { if (!ovalPath.isEmpty()) {
p.setClipRect(c.rect, Qt::NoClip); p.setClipRect(c.rect, Qt::NoClip);
} }
p.setOpacity(1. - _transitionProgress); p.setOpacity(1. - _transition.progress);
} }
void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) { void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
@ -517,7 +517,9 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
} }
saveZoomRange(c); saveZoomRange(c);
const auto parts = partsPercentage(c.chartData, _localZoom.rangeIndices); const auto parts = partsPercentage(
c.chartData,
_transition.zoomedInRangeXIndices);
applyParts(parts); applyParts(parts);
p.fillRect(c.rect + QMargins(0, 0, 0, st::lineWidth), st::boxBg); p.fillRect(c.rect + QMargins(0, 0, 0, st::lineWidth), st::boxBg);
@ -560,7 +562,8 @@ void StackLinearChartView::paintZoomed(QPainter &p, const PaintContext &c) {
paintPieText(p, c); paintPieText(p, c);
if (selectedLineIndex >= 0) { if (selectedLineIndex >= 0) {
const auto &[zoomedStart, zoomedEnd] = _localZoom.rangeIndices; const auto &[zoomedStart, zoomedEnd] =
_transition.zoomedInRangeXIndices;
const auto &line = c.chartData.lines[selectedLineIndex]; const auto &line = c.chartData.lines[selectedLineIndex];
auto sum = 0; auto sum = 0;
for (auto i = zoomedStart; i <= zoomedEnd; i++) { for (auto i = zoomedStart; i <= zoomedEnd; i++) {
@ -579,9 +582,9 @@ void StackLinearChartView::paintZoomedFooter(
if (!c.footer) { if (!c.footer) {
return; return;
} }
auto o = ScopedPainterOpacity(p, _transitionProgress); auto o = ScopedPainterOpacity(p, _transition.progress);
auto hq = PainterHighQualityEnabler(p); auto hq = PainterHighQualityEnabler(p);
const auto &[zoomedStart, zoomedEnd] = _localZoom.limitIndices; const auto &[zoomedStart, zoomedEnd] = _transition.zoomedInLimitXIndices;
const auto &[leftStart, w] = ComputeLeftStartAndStep( const auto &[leftStart, w] = ComputeLeftStartAndStep(
c.chartData, c.chartData,
{ {
@ -626,10 +629,10 @@ void StackLinearChartView::paintZoomedFooter(
} }
void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) { void StackLinearChartView::paintPieText(QPainter &p, const PaintContext &c) {
if (_transitionProgress == 1.) { if (_transition.progress == 1.) {
savePieTextParts(c); savePieTextParts(c);
} }
const auto &parts = _cachedTransition.textParts; const auto &parts = _transition.textParts;
const auto center = QPointF(c.rect.center()); const auto center = QPointF(c.rect.center());
const auto side = (c.rect.width() / 2.) * kCircleSizeRatio; const auto side = (c.rect.width() / 2.) * kCircleSizeRatio;
@ -748,7 +751,7 @@ void StackLinearChartView::handleMouseMove(
const Data::StatisticalChart &chartData, const Data::StatisticalChart &chartData,
const QPoint &center, const QPoint &center,
const QPoint &p) { const QPoint &p) {
if (_transitionProgress < 1) { if (_transition.progress < 1) {
return; return;
} }
const auto theta = std::atan2(center.y() - p.y(), (center.x() - p.x())); const auto theta = std::atan2(center.y() - p.y(), (center.x() - p.x()));
@ -758,9 +761,9 @@ void StackLinearChartView::handleMouseMove(
}(); }();
for (auto k = 0; k < chartData.lines.size(); k++) { for (auto k = 0; k < chartData.lines.size(); k++) {
const auto previous = k const auto previous = k
? _cachedTransition.lines[k - 1].angle ? _transition.lines[k - 1].angle
: -180; : -180;
const auto now = _cachedTransition.lines[k].angle; const auto now = _transition.lines[k].angle;
if (angle > previous && angle <= now) { if (angle > previous && angle <= now) {
const auto id = p.isNull() const auto id = p.isNull()
? -1 ? -1
@ -776,7 +779,7 @@ void StackLinearChartView::handleMouseMove(
} }
bool StackLinearChartView::skipSelectedTranslation() const { bool StackLinearChartView::skipSelectedTranslation() const {
return (_entries.size() == (_cachedTransition.lines.size() - 1)); return (_entries.size() == (_transition.lines.size() - 1));
} }
void StackLinearChartView::paintSelectedXIndex( void StackLinearChartView::paintSelectedXIndex(
@ -831,7 +834,7 @@ int StackLinearChartView::findXIndexByPosition(
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const QRect &rect, const QRect &rect,
float64 x) { float64 x) {
if (_transitionProgress == 1.) { if (_transition.progress == 1.) {
return -1; return -1;
} else if (x < rect.x()) { } else if (x < rect.x()) {
return 0; return 0;
@ -907,13 +910,13 @@ auto StackLinearChartView::maybeLocalZoom(
constexpr auto kLeftSide = int(kLimitLength / 2); constexpr auto kLeftSide = int(kLimitLength / 2);
constexpr auto kRightSide = int(kLimitLength / 2 + kRangeLength); constexpr auto kRightSide = int(kLimitLength / 2 + kRangeLength);
_transitionProgress = args.progress; _transition.progress = args.progress;
if (args.type == LocalZoomArgs::Type::SkipCalculation) { if (args.type == LocalZoomArgs::Type::SkipCalculation) {
return { true, _localZoom.limit, _localZoom.range }; return { true, _transition.zoomedInLimit, _transition.zoomedInRange };
} else if (args.type == LocalZoomArgs::Type::CheckAvailability) { } else if (args.type == LocalZoomArgs::Type::CheckAvailability) {
return { .hasZoom = true }; return { .hasZoom = true };
} else if (args.type == LocalZoomArgs::Type::Prepare) { } else if (args.type == LocalZoomArgs::Type::Prepare) {
_pendingPrepareCachedTransition = true; _transition.pendingPrepareToZoomIn = true;
} }
const auto xIndex = args.xIndex; const auto xIndex = args.xIndex;
const auto &xPercentage = args.chartData.xPercentage; const auto &xPercentage = args.chartData.xPercentage;
@ -921,48 +924,40 @@ auto StackLinearChartView::maybeLocalZoom(
const auto localRangeIndex = (xIndex == backIndex) const auto localRangeIndex = (xIndex == backIndex)
? (backIndex - kRangeLength) ? (backIndex - kRangeLength)
: xIndex; : xIndex;
_localZoom.range = { _transition.zoomedInRange = {
xPercentage[localRangeIndex], xPercentage[localRangeIndex],
xPercentage[localRangeIndex + kRangeLength], xPercentage[localRangeIndex + kRangeLength],
}; };
_localZoom.rangeIndices = { _transition.zoomedInRangeXIndices = {
float64(localRangeIndex), float64(localRangeIndex),
float64(localRangeIndex + kRangeLength), float64(localRangeIndex + kRangeLength),
}; };
if (xIndex < kLeftSide) { _transition.zoomedInLimitXIndices = (xIndex < kLeftSide)
_localZoom.limitIndices = { 0, kLimitLength }; ? Limits{ 0, kLimitLength }
} else if (xIndex > (backIndex - kRightSide)) { : (xIndex > (backIndex - kRightSide))
_localZoom.limitIndices = { ? Limits{ float64(backIndex - kLimitLength), float64(backIndex) }
float64(backIndex - kLimitLength), : Limits{ float64(xIndex - kLeftSide), float64(xIndex + kRightSide) };
float64(backIndex), _transition.zoomedInLimit = {
};
} else {
_localZoom.limitIndices = {
float64(xIndex - kLeftSide),
float64(xIndex + kRightSide),
};
}
_localZoom.limit = {
anim::interpolateF( anim::interpolateF(
0., 0.,
xPercentage[_localZoom.limitIndices.min], xPercentage[_transition.zoomedInLimitXIndices.min],
args.progress), args.progress),
anim::interpolateF( anim::interpolateF(
1., 1.,
xPercentage[_localZoom.limitIndices.max], xPercentage[_transition.zoomedInLimitXIndices.max],
args.progress), args.progress),
}; };
const auto resultRange = Limits{ const auto resultRange = Limits{
InterpolationRatio( InterpolationRatio(
_localZoom.limit.min, _transition.zoomedInLimit.min,
_localZoom.limit.max, _transition.zoomedInLimit.max,
_localZoom.range.min), _transition.zoomedInRange.min),
InterpolationRatio( InterpolationRatio(
_localZoom.limit.min, _transition.zoomedInLimit.min,
_localZoom.limit.max, _transition.zoomedInLimit.max,
_localZoom.range.max), _transition.zoomedInRange.max),
}; };
return { true, _localZoom.limit, resultRange }; return { true, _transition.zoomedInLimit, resultRange };
} }
void StackLinearChartView::tick(crl::time now) { void StackLinearChartView::tick(crl::time now) {

View file

@ -107,7 +107,6 @@ private:
base::flat_map<int, Entry> _entries; base::flat_map<int, Entry> _entries;
bool _isFinished = true; bool _isFinished = true;
float64 _transitionProgress = 0;
struct Transition { struct Transition {
struct TransitionLine { struct TransitionLine {
QPointF start; QPointF start;
@ -116,20 +115,21 @@ private:
float64 sum = 0.; float64 sum = 0.;
}; };
std::vector<TransitionLine> lines; std::vector<TransitionLine> lines;
float64 progress = 0;
bool pendingPrepareToZoomIn = false;
Limits zoomedOutXIndices; Limits zoomedOutXIndices;
Limits zoomedInLimit;
Limits zoomedInLimitXIndices;
Limits zoomedInRange;
Limits zoomedInRangeXIndices;
std::vector<PiePartData> textParts; std::vector<PiePartData> textParts;
} _cachedTransition; } _transition;
std::vector<bool> _skipPoints; std::vector<bool> _skipPoints;
struct {
Limits limit;
Limits limitIndices;
Limits range;
Limits rangeIndices;
} _localZoom;
bool _pendingPrepareCachedTransition = false;
class PiePartController final { class PiePartController final {
public: public:
using LineId = int; using LineId = int;