Added initial ability to filter chart lines.

This commit is contained in:
23rd 2023-07-14 03:45:59 +03:00 committed by John Preston
parent 4c02d19a51
commit 520989a7e6
7 changed files with 124 additions and 10 deletions

View File

@ -57,7 +57,8 @@ struct StatisticalChart {
std::vector<int> y; std::vector<int> y;
Statistic::SegmentTree segmentTree; Statistic::SegmentTree segmentTree;
QString id; int id = 0;
QString idString;
QString name; QString name;
int maxValue = 0; int maxValue = 0;
int minValue = std::numeric_limits<int>::max(); int minValue = std::numeric_limits<int>::max();

View File

@ -528,6 +528,7 @@ ChartWidget::ChartAnimationController::ChartAnimationController(
void ChartWidget::ChartAnimationController::setXPercentageLimits( void ChartWidget::ChartAnimationController::setXPercentageLimits(
Data::StatisticalChart &chartData, Data::StatisticalChart &chartData,
Limits xPercentageLimits, Limits xPercentageLimits,
std::vector<ChartLineViewContext> &chartLinesViewContext,
crl::time now) { crl::time now) {
if ((_animationValueXMin.to() == xPercentageLimits.min) if ((_animationValueXMin.to() == xPercentageLimits.min)
&& (_animationValueXMax.to() == xPercentageLimits.max)) { && (_animationValueXMax.to() == xPercentageLimits.max)) {
@ -550,6 +551,24 @@ void ChartWidget::ChartAnimationController::setXPercentageLimits(
float64(FindMaxValue(chartData, startXIndex, endXIndex)), float64(FindMaxValue(chartData, startXIndex, endXIndex)),
}; };
{
auto minValue = std::numeric_limits<int>::max();
auto maxValue = 0;
for (auto &l : chartData.lines) {
const auto it = ranges::find_if(chartLinesViewContext, [&](const auto &a) {
return a.id == l.id;
});
if (it != end(chartLinesViewContext) && !it->enabled) {
continue;
}
const auto lineMax = l.segmentTree.rMaxQ(startXIndex, endXIndex);
const auto lineMin = l.segmentTree.rMinQ(startXIndex, endXIndex);
maxValue = std::max(lineMax, maxValue);
minValue = std::min(lineMin, minValue);
}
_finalHeightLimits = { float64(minValue), float64(maxValue) };
}
_animationValueHeightMin = anim::value( _animationValueHeightMin = anim::value(
_animationValueHeightMin.current(), _animationValueHeightMin.current(),
_finalHeightLimits.min); _finalHeightLimits.min);
@ -612,7 +631,8 @@ void ChartWidget::ChartAnimationController::restartBottomLineAlpha() {
void ChartWidget::ChartAnimationController::tick( void ChartWidget::ChartAnimationController::tick(
crl::time now, crl::time now,
std::vector<ChartHorizontalLinesData> &horizontalLines, std::vector<ChartHorizontalLinesData> &horizontalLines,
std::vector<BottomCaptionLineData> &dateLines) { std::vector<BottomCaptionLineData> &dateLines,
std::vector<ChartLineViewContext> &chartLinesViewContext) {
if (!_animation.animating()) { if (!_animation.animating()) {
return; return;
} }
@ -669,7 +689,33 @@ void ChartWidget::ChartAnimationController::tick(
const auto bottomLineAlphaFinished = isFinished( const auto bottomLineAlphaFinished = isFinished(
_animValueBottomLineAlpha); _animValueBottomLineAlpha);
if (xFinished && yFinished && alphaFinished && bottomLineAlphaFinished) { auto chartLinesViewContextFinished = false;
{
auto finishedCount = 0;
for (auto &viewLine : chartLinesViewContext) {
if (!viewLine.startedAt) {
continue;
}
const auto progress = (now - viewLine.startedAt)
/ (kXExpandingDuration * 2);
viewLine.alpha = std::clamp(
viewLine.enabled ? progress : (1. - progress),
0.,
1.);
if (progress >= 1.) {
finishedCount++;
}
}
chartLinesViewContextFinished =
(finishedCount == chartLinesViewContext.size());
}
if (xFinished
&& yFinished
&& alphaFinished
&& bottomLineAlphaFinished
&& chartLinesViewContextFinished) {
const auto &lines = horizontalLines.back().lines; const auto &lines = horizontalLines.back().lines;
if ((lines.front().absoluteValue == _animationValueHeightMin.to()) if ((lines.front().absoluteValue == _animationValueHeightMin.to())
&& lines.back().absoluteValue == _animationValueHeightMax.to()) { && lines.back().absoluteValue == _animationValueHeightMax.to()) {
@ -794,9 +840,41 @@ ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
, _chartArea(base::make_unique_q<RpMouseWidget>(this)) , _chartArea(base::make_unique_q<RpMouseWidget>(this))
, _footer(std::make_unique<Footer>(this)) , _footer(std::make_unique<Footer>(this))
, _animationController([=] { _chartArea->update(); }) { , _animationController([=] { _chartArea->update(); }) {
const auto asd = Ui::CreateChild<Ui::AbstractButton>(this);
const auto oiu = std::make_shared<bool>(false);
asd->paintRequest(
) | rpl::start_with_next([=](const QRect &r) {
auto p = QPainter(asd);
p.setOpacity(0.3);
p.fillRect(r, Qt::darkRed);
}, asd->lifetime());
asd->setClickedCallback([=] {
*oiu = !(*oiu);
auto data = ChartLineViewContext{
.id = 1,
.enabled = (*oiu),
.startedAt = crl::now(),
};
_animatedChartLines.clear();
_animatedChartLines.push_back(data);
_animationController.setXPercentageLimits(
_chartData,
_animationController.currentXLimits(),
_animatedChartLines,
data.startedAt);
});
sizeValue( sizeValue(
) | rpl::start_with_next([=](const QSize &s) { ) | rpl::start_with_next([=](const QSize &s) {
_footer->setGeometry( _footer->setGeometry(
0,
s.height() - st::statisticsChartFooterHeight * 2,
s.width(),
st::statisticsChartFooterHeight);
asd->setGeometry(
0, 0,
s.height() - st::statisticsChartFooterHeight, s.height() - st::statisticsChartFooterHeight,
s.width(), s.width(),
@ -806,7 +884,7 @@ ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
0, 0,
s.width(), s.width(),
s.height() s.height()
- st::statisticsChartFooterHeight - st::statisticsChartFooterHeight * 2
- st::statisticsChartFooterSkip); - st::statisticsChartFooterSkip);
}, lifetime()); }, lifetime());
@ -817,7 +895,8 @@ ChartWidget::ChartWidget(not_null<Ui::RpWidget*> parent)
width(), width(),
st::statisticsChartHeight st::statisticsChartHeight
+ st::statisticsChartFooterHeight + st::statisticsChartFooterHeight
+ st::statisticsChartFooterSkip); + st::statisticsChartFooterSkip
+ st::statisticsChartFooterHeight);
} }
QRect ChartWidget::chartAreaRect() const { QRect ChartWidget::chartAreaRect() const {
@ -836,7 +915,11 @@ void ChartWidget::setupChartArea() {
const auto now = crl::now(); const auto now = crl::now();
_animationController.tick(now, _horizontalLines, _bottomLine.dates); _animationController.tick(
now,
_horizontalLines,
_bottomLine.dates,
_animatedChartLines);
const auto chartRect = chartAreaRect(); const auto chartRect = chartAreaRect();
@ -884,6 +967,7 @@ void ChartWidget::setupChartArea() {
_animationController.currentXLimits(), _animationController.currentXLimits(),
_animationController.currentHeightLimits(), _animationController.currentHeightLimits(),
chartRect, chartRect,
_animatedChartLines,
detailsPaintContext); detailsPaintContext);
} }
@ -1005,6 +1089,7 @@ void ChartWidget::setupFooter() {
fullXLimits, fullXLimits,
_footer->fullHeightLimits(), _footer->fullHeightLimits(),
r, r,
_animatedChartLines,
detailsPaintContext); detailsPaintContext);
} }
}); });
@ -1024,6 +1109,7 @@ void ChartWidget::setupFooter() {
_animationController.setXPercentageLimits( _animationController.setXPercentageLimits(
_chartData, _chartData,
xPercentageLimits, xPercentageLimits,
_animatedChartLines,
now); now);
{ {
const auto finalXLimits = _animationController.finalXLimits(); const auto finalXLimits = _animationController.finalXLimits();
@ -1124,6 +1210,7 @@ void ChartWidget::setChartData(Data::StatisticalChart chartData) {
_animationController.setXPercentageLimits( _animationController.setXPercentageLimits(
_chartData, _chartData,
{ _chartData.xPercentage.front(), _chartData.xPercentage.back() }, { _chartData.xPercentage.front(), _chartData.xPercentage.back() },
_animatedChartLines,
0); 0);
{ {
const auto finalXLimits = _animationController.finalXLimits(); const auto finalXLimits = _animationController.finalXLimits();

View File

@ -47,6 +47,7 @@ private:
void setXPercentageLimits( void setXPercentageLimits(
Data::StatisticalChart &chartData, Data::StatisticalChart &chartData,
Limits xPercentageLimits, Limits xPercentageLimits,
std::vector<ChartLineViewContext> &chartLinesViewContext,
crl::time now); crl::time now);
void start(); void start();
void finish(); void finish();
@ -55,7 +56,8 @@ private:
void tick( void tick(
crl::time now, crl::time now,
std::vector<ChartHorizontalLinesData> &horizontalLines, std::vector<ChartHorizontalLinesData> &horizontalLines,
std::vector<BottomCaptionLineData> &dateLines); std::vector<BottomCaptionLineData> &dateLines,
std::vector<ChartLineViewContext> &chartLinesViewContext);
[[nodiscard]] Limits currentXLimits() const; [[nodiscard]] Limits currentXLimits() const;
[[nodiscard]] Limits currentXIndices() const; [[nodiscard]] Limits currentXIndices() const;
@ -112,6 +114,8 @@ private:
const std::unique_ptr<Footer> _footer; const std::unique_ptr<Footer> _footer;
Data::StatisticalChart _chartData; Data::StatisticalChart _chartData;
std::vector<ChartLineViewContext> _animatedChartLines;
struct { struct {
base::unique_qptr<PointDetailsWidget> widget; base::unique_qptr<PointDetailsWidget> widget;
float64 currentX = 0; float64 currentX = 0;

View File

@ -23,11 +23,22 @@ void PaintLinearChartView(
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const Limits &heightLimits, const Limits &heightLimits,
const QRect &rect, const QRect &rect,
const std::vector<ChartLineViewContext> &linesContext,
DetailsPaintContext &detailsPaintContext) { DetailsPaintContext &detailsPaintContext) {
const auto currentMinHeight = rect.y(); // const auto currentMinHeight = rect.y(); //
const auto currentMaxHeight = rect.height() + rect.y(); // const auto currentMaxHeight = rect.height() + rect.y(); //
for (const auto &line : chartData.lines) { for (const auto &line : chartData.lines) {
p.setOpacity(1.);
for (const auto &lineContext : linesContext) {
if (lineContext.id == line.id) {
p.setOpacity(lineContext.alpha);
break;
}
}
if (!p.opacity()) {
continue;
}
const auto additionalP = (chartData.xPercentage.size() < 2) const auto additionalP = (chartData.xPercentage.size() < 2)
? 0. ? 0.
: (chartData.xPercentage.front() * rect.width()); : (chartData.xPercentage.front() * rect.width());

View File

@ -15,6 +15,7 @@ namespace Statistic {
struct Limits; struct Limits;
struct DetailsPaintContext; struct DetailsPaintContext;
struct ChartLineViewContext;
void PaintLinearChartView( void PaintLinearChartView(
QPainter &p, QPainter &p,
@ -23,6 +24,7 @@ void PaintLinearChartView(
const Limits &xPercentageLimits, const Limits &xPercentageLimits,
const Limits &heightLimits, const Limits &heightLimits,
const QRect &rect, const QRect &rect,
const std::vector<ChartLineViewContext> &linesContext,
DetailsPaintContext &detailsPaintContext); DetailsPaintContext &detailsPaintContext);
} // namespace Statistic } // namespace Statistic

View File

@ -25,4 +25,11 @@ struct DetailsPaintContext final {
std::vector<Dot> dots; std::vector<Dot> dots;
}; };
struct ChartLineViewContext final {
int id = 0;
bool enabled = false;
crl::time startedAt = 0;
float64 alpha = 1.;
};
} // namespace Statistic } // namespace Statistic

View File

@ -30,6 +30,7 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
return {}; return {};
} }
auto result = Data::StatisticalChart(); auto result = Data::StatisticalChart();
auto columnIdCount = 0;
for (const auto &column : columns) { for (const auto &column : columns) {
const auto array = column.toArray(); const auto array = column.toArray();
if (array.empty()) { if (array.empty()) {
@ -46,7 +47,8 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
} else { } else {
auto line = Data::StatisticalChart::Line(); auto line = Data::StatisticalChart::Line();
const auto length = array.size() - 1; const auto length = array.size() - 1;
line.id = columnId; line.id = (++columnIdCount);
line.idString = columnId;
line.y.resize(length); line.y.resize(length);
for (auto i = 0; i < length; i++) { for (auto i = 0; i < length; i++) {
const auto value = array.at(i + 1).toInt(); const auto value = array.at(i + 1).toInt();
@ -73,7 +75,7 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
const auto colorPattern = u"(.*)(#.*)"_q; const auto colorPattern = u"(.*)(#.*)"_q;
for (auto &line : result.lines) { for (auto &line : result.lines) {
const auto colorIt = colors.constFind(line.id); const auto colorIt = colors.constFind(line.idString);
if (colorIt != colors.constEnd() && (*colorIt).isString()) { if (colorIt != colors.constEnd() && (*colorIt).isString()) {
const auto match = QRegularExpression(colorPattern).match( const auto match = QRegularExpression(colorPattern).match(
colorIt->toString()); colorIt->toString());
@ -82,7 +84,7 @@ Data::StatisticalChart StatisticalChartFromJSON(const QByteArray &json) {
line.color = QColor(match.captured(2)); line.color = QColor(match.captured(2));
} }
} }
const auto nameIt = names.constFind(line.id); const auto nameIt = names.constFind(line.idString);
if (nameIt != names.constEnd() && (*nameIt).isString()) { if (nameIt != names.constEnd() && (*nameIt).isString()) {
line.name = nameIt->toString().replace('-', QChar(8212)); line.name = nameIt->toString().replace('-', QChar(8212));
} }