data_statistics_chart.cpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /*
  2. This file is part of Telegram Desktop,
  3. the official desktop application for the Telegram messaging service.
  4. For license and copyright information please follow this link:
  5. https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
  6. */
  7. #include "data/data_statistics_chart.h"
  8. #include "statistics/statistics_format_values.h"
  9. #include "styles/style_basic.h"
  10. #include "styles/style_statistics.h"
  11. #include <QtCore/QDateTime>
  12. #include <QtCore/QLocale>
  13. namespace Data {
  14. void StatisticalChart::measure() {
  15. if (x.empty()) {
  16. return;
  17. }
  18. const auto n = x.size();
  19. const auto start = x.front();
  20. const auto end = x.back();
  21. xPercentage.clear();
  22. xPercentage.resize(n);
  23. if (n == 1) {
  24. xPercentage[0] = 1;
  25. } else {
  26. for (auto i = 0; i < n; i++) {
  27. xPercentage[i] = (x[i] - start) / float64(end - start);
  28. }
  29. }
  30. for (auto &line : lines) {
  31. if (line.maxValue > maxValue) {
  32. maxValue = line.maxValue;
  33. }
  34. if (line.minValue < minValue) {
  35. minValue = line.minValue;
  36. }
  37. line.segmentTree = Statistic::SegmentTree(line.y);
  38. }
  39. daysLookup.clear();
  40. const auto dateCount = int((end - start) / timeStep) + 10;
  41. daysLookup.reserve(dateCount);
  42. constexpr auto kOneDay = 3600 * 24 * 1000;
  43. // View data.
  44. auto maxWidth = 0;
  45. const auto &defaultFont = st::statisticsDetailsBottomCaptionStyle.font;
  46. for (auto i = 0; i < dateCount; i++) {
  47. const auto r = (start + (i * timeStep)) / 1000;
  48. if (timeStep == 1) {
  49. daysLookup.push_back(
  50. QString(((i < 10) ? u"0%1:00"_q : u"%1:00"_q).arg(i)));
  51. } else if (timeStep < kOneDay) {
  52. const auto dateTime = QDateTime::fromSecsSinceEpoch(r);
  53. daysLookup.push_back(u"%1:%2"_q
  54. .arg(dateTime.time().hour(), 2, 10, QChar('0'))
  55. .arg(dateTime.time().minute(), 2, 10, QChar('0')));
  56. } else {
  57. daysLookup.push_back(Statistic::LangDayMonth(r));
  58. }
  59. maxWidth = std::max(maxWidth, defaultFont->width(daysLookup.back()));
  60. }
  61. dayStringMaxWidth = maxWidth;
  62. oneDayPercentage = timeStep / float64(end - start);
  63. }
  64. QString StatisticalChart::getDayString(int i) const {
  65. return daysLookup[int((x[i] - x[0]) / timeStep)];
  66. }
  67. int StatisticalChart::findStartIndex(float64 v) const {
  68. if (!v) {
  69. return 0;
  70. }
  71. const auto n = int(xPercentage.size());
  72. if (n < 2) {
  73. return 0;
  74. }
  75. auto left = 0;
  76. auto right = n - 1;
  77. while (left <= right) {
  78. const auto middle = (right + left) >> 1;
  79. if (v < xPercentage[middle]
  80. && (!middle || (v > xPercentage[middle - 1]))) {
  81. return middle;
  82. }
  83. if (v == xPercentage[middle]) {
  84. return middle;
  85. }
  86. if (v < xPercentage[middle]) {
  87. right = middle - 1;
  88. } else if (v > xPercentage[middle]) {
  89. left = middle + 1;
  90. }
  91. }
  92. return left;
  93. }
  94. int StatisticalChart::findEndIndex(int left, float64 v) const {
  95. const auto wasLeft = left;
  96. const auto n = int(xPercentage.size());
  97. if (v == 1.) {
  98. return n - 1;
  99. }
  100. auto right = n - 1;
  101. while (left <= right) {
  102. const auto middle = (right + left) >> 1;
  103. if (v > xPercentage[middle]
  104. && ((middle == n - 1) || (v < xPercentage[middle + 1]))) {
  105. return middle;
  106. }
  107. if (v == xPercentage[middle]) {
  108. return middle;
  109. }
  110. if (v < xPercentage[middle]) {
  111. right = middle - 1;
  112. } else if (v > xPercentage[middle]) {
  113. left = middle + 1;
  114. }
  115. }
  116. return std::max(wasLeft, right);
  117. }
  118. int StatisticalChart::findIndex(int left, int right, float64 v) const {
  119. const auto n = int(xPercentage.size());
  120. if (v <= xPercentage[left]) {
  121. return left;
  122. }
  123. if (v >= xPercentage[right]) {
  124. return right;
  125. }
  126. while (left <= right) {
  127. const auto middle = (right + left) >> 1;
  128. if (v > xPercentage[middle]
  129. && ((middle == n - 1) || (v < xPercentage[middle + 1]))) {
  130. return middle;
  131. }
  132. if (v == xPercentage[middle]) {
  133. return middle;
  134. }
  135. if (v < xPercentage[middle]) {
  136. right = middle - 1;
  137. } else if (v > xPercentage[middle]) {
  138. left = middle + 1;
  139. }
  140. }
  141. return right;
  142. }
  143. } // namespace Data