Added initial animation of chart y-axis captions.
This commit is contained in:
parent
07cd35b1a8
commit
695542cfd2
|
@ -15,6 +15,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||||
#include "ui/painter.h"
|
#include "ui/painter.h"
|
||||||
#include "ui/rect.h"
|
#include "ui/rect.h"
|
||||||
#include "styles/style_boxes.h"
|
#include "styles/style_boxes.h"
|
||||||
|
#include "styles/style_statistics.h"
|
||||||
|
|
||||||
namespace Statistic {
|
namespace Statistic {
|
||||||
|
|
||||||
|
@ -95,6 +96,50 @@ void PaintCaptionsToHorizontalLines(
|
||||||
p.setOpacity(alpha);
|
p.setOpacity(alpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PaintBottomLine(
|
||||||
|
QPainter &p,
|
||||||
|
const std::vector<ChartWidget::BottomCaptionLineData> &dates,
|
||||||
|
Data::StatisticalChart &chartData,
|
||||||
|
const Limits &xPercentageLimits,
|
||||||
|
int fullWidth,
|
||||||
|
int y) {
|
||||||
|
p.setFont(st::statisticsDetailsPopupStyle.font);
|
||||||
|
|
||||||
|
const auto startXIndex = chartData.findStartIndex(
|
||||||
|
xPercentageLimits.min);
|
||||||
|
const auto endXIndex = chartData.findEndIndex(
|
||||||
|
startXIndex,
|
||||||
|
xPercentageLimits.max);
|
||||||
|
|
||||||
|
for (const auto &date : dates) {
|
||||||
|
const auto resultAlpha = date.alpha;
|
||||||
|
const auto step = std::max(date.step, 1);
|
||||||
|
|
||||||
|
auto start = startXIndex;
|
||||||
|
while (start % step != 0) {
|
||||||
|
start--;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto end = endXIndex;
|
||||||
|
while ((end % step != 0) || end < (chartData.x.size() - 1)) {
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto offset = fullWidth * xPercentageLimits.min;
|
||||||
|
|
||||||
|
for (auto i = start; i < end; i += step) {
|
||||||
|
if ((i < 0) || (i >= (chartData.x.size() - 1))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const auto xPercentage = (chartData.x[i] - chartData.x.front())
|
||||||
|
/ (chartData.x.back() - chartData.x.front());
|
||||||
|
const auto xPoint = xPercentage * fullWidth - offset;
|
||||||
|
p.setOpacity(resultAlpha);
|
||||||
|
p.drawText(xPoint, y, chartData.getDayString(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class RpMouseWidget final : public Ui::AbstractButton {
|
class RpMouseWidget final : public Ui::AbstractButton {
|
||||||
|
@ -495,7 +540,7 @@ QRect ChartWidget::chartAreaRect() const {
|
||||||
st::lineWidth,
|
st::lineWidth,
|
||||||
st::boxTextFont->height,
|
st::boxTextFont->height,
|
||||||
st::lineWidth,
|
st::lineWidth,
|
||||||
st::lineWidth);
|
st::lineWidth + st::statisticsChartBottomCaptionHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChartWidget::setupChartArea() {
|
void ChartWidget::setupChartArea() {
|
||||||
|
@ -552,9 +597,96 @@ void ChartWidget::setupChartArea() {
|
||||||
for (auto &horizontalLine : _horizontalLines) {
|
for (auto &horizontalLine : _horizontalLines) {
|
||||||
PaintCaptionsToHorizontalLines(p, horizontalLine, chartRect);
|
PaintCaptionsToHorizontalLines(p, horizontalLine, chartRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PaintBottomLine(
|
||||||
|
p,
|
||||||
|
_bottomLine.dates,
|
||||||
|
_chartData,
|
||||||
|
_animationController.finalXLimits(),
|
||||||
|
_bottomLine.chartFullWidth,
|
||||||
|
rect::bottom(chartRect) + st::statisticsChartBottomCaptionSkip);
|
||||||
}, _footer->lifetime());
|
}, _footer->lifetime());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ChartWidget::updateBottomDates() {
|
||||||
|
if (!_chartData) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto d = _bottomLine.chartFullWidth * _chartData.oneDayPercentage;
|
||||||
|
const auto k = _chartArea->width() / d;
|
||||||
|
const auto tempStep = int(k / 6);
|
||||||
|
|
||||||
|
const auto isCurrentNull = (_bottomLine.current.stepMinFast == 0);
|
||||||
|
if (!isCurrentNull
|
||||||
|
&& (tempStep < _bottomLine.current.stepMax)
|
||||||
|
&& (tempStep > _bottomLine.current.stepMin)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto highestOneBit = [](unsigned int v) {
|
||||||
|
if (!v) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
auto r = unsigned(1);
|
||||||
|
|
||||||
|
while (v >>= 1) {
|
||||||
|
r *= 2;
|
||||||
|
}
|
||||||
|
return int(r);
|
||||||
|
};
|
||||||
|
const auto step = highestOneBit(tempStep) << 1;
|
||||||
|
if (!isCurrentNull && (_bottomLine.current.step == step)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_bottomLine.animation.animating()) {
|
||||||
|
_bottomLine.animation.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr auto kStepRatio = 0.2;
|
||||||
|
const auto stepMax = int(step + step * kStepRatio);
|
||||||
|
const auto stepMin = int(step - step * kStepRatio);
|
||||||
|
|
||||||
|
auto data = BottomCaptionLineData{
|
||||||
|
.step = step,
|
||||||
|
.stepMax = stepMax,
|
||||||
|
.stepMin = stepMin,
|
||||||
|
.alpha = 1.,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isCurrentNull) {
|
||||||
|
_bottomLine.current = data;
|
||||||
|
_bottomLine.dates.push_back(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_bottomLine.current = data;
|
||||||
|
|
||||||
|
for (auto &date : _bottomLine.dates) {
|
||||||
|
date.fixedAlpha = date.alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
_bottomLine.dates.push_back(data);
|
||||||
|
if (_bottomLine.dates.size() > 2) {
|
||||||
|
_bottomLine.dates.erase(begin(_bottomLine.dates));
|
||||||
|
}
|
||||||
|
|
||||||
|
_bottomLine.animation.start(
|
||||||
|
[=](float64 value) {
|
||||||
|
for (auto &date : _bottomLine.dates) {
|
||||||
|
date.alpha = (1. - value) * date.fixedAlpha;
|
||||||
|
}
|
||||||
|
_bottomLine.dates.back().alpha = value;
|
||||||
|
if (value >= 1.) {
|
||||||
|
_bottomLine.dates.clear();
|
||||||
|
_bottomLine.dates.push_back(data);
|
||||||
|
}
|
||||||
|
_chartArea->update();
|
||||||
|
},
|
||||||
|
0.,
|
||||||
|
1.,
|
||||||
|
200);
|
||||||
|
}
|
||||||
|
|
||||||
void ChartWidget::setupFooter() {
|
void ChartWidget::setupFooter() {
|
||||||
_footer->paintRequest(
|
_footer->paintRequest(
|
||||||
) | rpl::start_with_next([=, fullXLimits = Limits{ 0., 1. }] {
|
) | rpl::start_with_next([=, fullXLimits = Limits{ 0., 1. }] {
|
||||||
|
@ -588,6 +720,12 @@ void ChartWidget::setupFooter() {
|
||||||
_chartData,
|
_chartData,
|
||||||
xPercentageLimits,
|
xPercentageLimits,
|
||||||
now);
|
now);
|
||||||
|
{
|
||||||
|
const auto finalXLimits = _animationController.finalXLimits();
|
||||||
|
_bottomLine.chartFullWidth = _chartArea->width()
|
||||||
|
/ (finalXLimits.max - finalXLimits.min);
|
||||||
|
}
|
||||||
|
updateBottomDates();
|
||||||
if ((now - _lastHeightLimitsChanged) < kHeightLimitsUpdateTimeout) {
|
if ((now - _lastHeightLimitsChanged) < kHeightLimitsUpdateTimeout) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,14 @@ public:
|
||||||
void setChartData(Data::StatisticalChart chartData);
|
void setChartData(Data::StatisticalChart chartData);
|
||||||
void addHorizontalLine(Limits newHeight, bool animated);
|
void addHorizontalLine(Limits newHeight, bool animated);
|
||||||
|
|
||||||
|
struct BottomCaptionLineData final {
|
||||||
|
int step = 0;
|
||||||
|
int stepMax = 0;
|
||||||
|
int stepMin = 0;
|
||||||
|
float64 alpha = 0.;
|
||||||
|
float64 fixedAlpha = 0.;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Footer;
|
class Footer;
|
||||||
|
|
||||||
|
@ -82,6 +90,8 @@ private:
|
||||||
void setupFooter();
|
void setupFooter();
|
||||||
void setupDetails();
|
void setupDetails();
|
||||||
|
|
||||||
|
void updateBottomDates();
|
||||||
|
|
||||||
const base::unique_qptr<RpMouseWidget> _chartArea;
|
const base::unique_qptr<RpMouseWidget> _chartArea;
|
||||||
const std::unique_ptr<Footer> _footer;
|
const std::unique_ptr<Footer> _footer;
|
||||||
Data::StatisticalChart _chartData;
|
Data::StatisticalChart _chartData;
|
||||||
|
@ -91,6 +101,13 @@ private:
|
||||||
float64 currentX = 0;
|
float64 currentX = 0;
|
||||||
} _details;
|
} _details;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
BottomCaptionLineData current;
|
||||||
|
std::vector<BottomCaptionLineData> dates;
|
||||||
|
Ui::Animations::Simple animation;
|
||||||
|
int chartFullWidth = 0;
|
||||||
|
} _bottomLine;
|
||||||
|
|
||||||
bool _useMinHeight = false;
|
bool _useMinHeight = false;
|
||||||
|
|
||||||
ChartAnimationController _animationController;
|
ChartAnimationController _animationController;
|
||||||
|
|
|
@ -17,6 +17,9 @@ statisticsDetailsPopupMidLineSpace: 8px;
|
||||||
statisticsDetailsDotRadius: 4px;
|
statisticsDetailsDotRadius: 4px;
|
||||||
statisticsChartLineWidth: 2px;
|
statisticsChartLineWidth: 2px;
|
||||||
|
|
||||||
|
statisticsChartBottomCaptionHeight: 30px;
|
||||||
|
statisticsChartBottomCaptionSkip: 15px;
|
||||||
|
|
||||||
statisticsDetailsPopupStyle: TextStyle(defaultTextStyle) {
|
statisticsDetailsPopupStyle: TextStyle(defaultTextStyle) {
|
||||||
font: font(11px);
|
font: font(11px);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user