2023-04-26 20:26:30 +00:00
|
|
|
/*
|
|
|
|
This file is part of Telegram Desktop,
|
|
|
|
the official desktop application for the Telegram messaging service.
|
|
|
|
|
|
|
|
For license and copyright information please follow this link:
|
|
|
|
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|
|
|
*/
|
2023-09-29 13:32:07 +00:00
|
|
|
#include "data/data_statistics_chart.h"
|
|
|
|
|
2023-11-29 06:09:36 +00:00
|
|
|
#include "statistics/statistics_format_values.h"
|
2023-12-06 19:28:57 +00:00
|
|
|
#include "styles/style_basic.h"
|
|
|
|
#include "styles/style_statistics.h"
|
2023-11-29 06:09:36 +00:00
|
|
|
|
2023-09-29 13:32:07 +00:00
|
|
|
#include <QtCore/QDateTime>
|
2023-10-13 06:04:29 +00:00
|
|
|
#include <QtCore/QLocale>
|
2023-04-26 20:26:30 +00:00
|
|
|
|
|
|
|
namespace Data {
|
|
|
|
|
2023-05-02 14:31:56 +00:00
|
|
|
void StatisticalChart::measure() {
|
|
|
|
if (x.empty()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const auto n = x.size();
|
|
|
|
const auto start = x.front();
|
|
|
|
const auto end = x.back();
|
|
|
|
|
|
|
|
xPercentage.clear();
|
|
|
|
xPercentage.resize(n);
|
|
|
|
if (n == 1) {
|
|
|
|
xPercentage[0] = 1;
|
|
|
|
} else {
|
|
|
|
for (auto i = 0; i < n; i++) {
|
|
|
|
xPercentage[i] = (x[i] - start) / float64(end - start);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-29 14:21:53 +00:00
|
|
|
for (auto &line : lines) {
|
|
|
|
if (line.maxValue > maxValue) {
|
|
|
|
maxValue = line.maxValue;
|
2023-05-02 14:31:56 +00:00
|
|
|
}
|
2023-09-29 14:21:53 +00:00
|
|
|
if (line.minValue < minValue) {
|
|
|
|
minValue = line.minValue;
|
2023-05-02 14:31:56 +00:00
|
|
|
}
|
2023-09-29 14:21:53 +00:00
|
|
|
line.segmentTree = Statistic::SegmentTree(line.y);
|
2023-05-02 14:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
daysLookup.clear();
|
|
|
|
const auto dateCount = int((end - start) / timeStep) + 10;
|
|
|
|
daysLookup.reserve(dateCount);
|
|
|
|
constexpr auto kOneDay = 3600 * 24 * 1000;
|
2023-12-06 19:28:57 +00:00
|
|
|
|
|
|
|
// View data.
|
|
|
|
auto maxWidth = 0;
|
|
|
|
const auto &defaultFont = st::statisticsDetailsBottomCaptionStyle.font;
|
|
|
|
|
2023-05-02 14:31:56 +00:00
|
|
|
for (auto i = 0; i < dateCount; i++) {
|
|
|
|
const auto r = (start + (i * timeStep)) / 1000;
|
|
|
|
if (timeStep == 1) {
|
|
|
|
daysLookup.push_back(
|
|
|
|
QString(((i < 10) ? u"0%1:00"_q : u"%1:00"_q).arg(i)));
|
|
|
|
} else if (timeStep < kOneDay) {
|
2023-11-29 06:09:36 +00:00
|
|
|
const auto dateTime = QDateTime::fromSecsSinceEpoch(r);
|
2023-05-02 14:31:56 +00:00
|
|
|
daysLookup.push_back(u"%1:%2"_q
|
|
|
|
.arg(dateTime.time().hour(), 2, 10, QChar('0'))
|
|
|
|
.arg(dateTime.time().minute(), 2, 10, QChar('0')));
|
|
|
|
} else {
|
2023-11-29 06:09:36 +00:00
|
|
|
daysLookup.push_back(Statistic::LangDayMonth(r));
|
2023-05-02 14:31:56 +00:00
|
|
|
}
|
2023-12-06 19:28:57 +00:00
|
|
|
maxWidth = std::max(maxWidth, defaultFont->width(daysLookup.back()));
|
2023-05-02 14:31:56 +00:00
|
|
|
}
|
2023-12-06 19:28:57 +00:00
|
|
|
dayStringMaxWidth = maxWidth;
|
2023-05-02 14:31:56 +00:00
|
|
|
|
|
|
|
oneDayPercentage = timeStep / float64(end - start);
|
|
|
|
}
|
|
|
|
|
|
|
|
QString StatisticalChart::getDayString(int i) const {
|
|
|
|
return daysLookup[int((x[i] - x[0]) / timeStep)];
|
|
|
|
}
|
|
|
|
|
2023-10-02 13:43:11 +00:00
|
|
|
int StatisticalChart::findStartIndex(float64 v) const {
|
|
|
|
if (!v) {
|
2023-05-02 14:31:56 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
const auto n = int(xPercentage.size());
|
|
|
|
|
|
|
|
if (n < 2) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
auto left = 0;
|
|
|
|
auto right = n - 1;
|
|
|
|
|
|
|
|
while (left <= right) {
|
|
|
|
const auto middle = (right + left) >> 1;
|
|
|
|
if (v < xPercentage[middle]
|
2023-10-02 13:43:11 +00:00
|
|
|
&& (!middle || (v > xPercentage[middle - 1]))) {
|
2023-05-02 14:31:56 +00:00
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
if (v == xPercentage[middle]) {
|
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
if (v < xPercentage[middle]) {
|
|
|
|
right = middle - 1;
|
|
|
|
} else if (v > xPercentage[middle]) {
|
|
|
|
left = middle + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return left;
|
|
|
|
}
|
|
|
|
|
2023-10-02 13:43:11 +00:00
|
|
|
int StatisticalChart::findEndIndex(int left, float64 v) const {
|
2023-11-22 21:07:08 +00:00
|
|
|
const auto wasLeft = left;
|
2023-05-02 14:31:56 +00:00
|
|
|
const auto n = int(xPercentage.size());
|
|
|
|
if (v == 1.) {
|
|
|
|
return n - 1;
|
|
|
|
}
|
|
|
|
auto right = n - 1;
|
|
|
|
|
|
|
|
while (left <= right) {
|
|
|
|
const auto middle = (right + left) >> 1;
|
|
|
|
if (v > xPercentage[middle]
|
2023-10-02 13:43:11 +00:00
|
|
|
&& ((middle == n - 1) || (v < xPercentage[middle + 1]))) {
|
2023-05-02 14:31:56 +00:00
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
if (v == xPercentage[middle]) {
|
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
if (v < xPercentage[middle]) {
|
|
|
|
right = middle - 1;
|
|
|
|
} else if (v > xPercentage[middle]) {
|
|
|
|
left = middle + 1;
|
|
|
|
}
|
|
|
|
}
|
2023-11-22 21:07:08 +00:00
|
|
|
return std::max(wasLeft, right);
|
2023-05-02 14:31:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2023-10-02 13:43:11 +00:00
|
|
|
int StatisticalChart::findIndex(int left, int right, float64 v) const {
|
2023-05-02 14:31:56 +00:00
|
|
|
const auto n = int(xPercentage.size());
|
|
|
|
|
|
|
|
if (v <= xPercentage[left]) {
|
|
|
|
return left;
|
|
|
|
}
|
|
|
|
if (v >= xPercentage[right]) {
|
|
|
|
return right;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (left <= right) {
|
|
|
|
const auto middle = (right + left) >> 1;
|
|
|
|
if (v > xPercentage[middle]
|
2023-10-02 13:43:11 +00:00
|
|
|
&& ((middle == n - 1) || (v < xPercentage[middle + 1]))) {
|
2023-05-02 14:31:56 +00:00
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v == xPercentage[middle]) {
|
|
|
|
return middle;
|
|
|
|
}
|
|
|
|
if (v < xPercentage[middle]) {
|
|
|
|
right = middle - 1;
|
|
|
|
} else if (v > xPercentage[middle]) {
|
|
|
|
left = middle + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return right;
|
|
|
|
}
|
|
|
|
|
2023-04-26 20:26:30 +00:00
|
|
|
} // namespace Data
|