diff options
Diffstat (limited to 'stats')
-rw-r--r-- | stats/statsaxis.cpp | 56 | ||||
-rw-r--r-- | stats/statsaxis.h | 6 | ||||
-rw-r--r-- | stats/statsview.cpp | 12 |
3 files changed, 63 insertions, 11 deletions
diff --git a/stats/statsaxis.cpp b/stats/statsaxis.cpp index 8b8694964..d31b5827b 100644 --- a/stats/statsaxis.cpp +++ b/stats/statsaxis.cpp @@ -57,6 +57,17 @@ std::pair<double, double> StatsAxis::minMaxScreen() const : std::make_pair(zeroOnScreen, zeroOnScreen - size); } +std::pair<double, double> StatsAxis::horizontalOverhang() const +{ + // If the labels are between ticks, they cannot peak out + if (!horizontal || labelsBetweenTicks) + return { 0.0, 0.0 }; + QFontMetrics fm(labelFont); + auto [firstLabel, lastLabel] = getFirstLastLabel(); + return { fm.size(Qt::TextSingleLine, firstLabel).width() / 2.0, + fm.size(Qt::TextSingleLine, lastLabel).width() / 2.0 }; +} + void StatsAxis::setRange(double minIn, double maxIn) { min = minIn; @@ -223,6 +234,19 @@ ValueAxis::ValueAxis(const QString &title, double min, double max, int decimals, StatsAxis(title, horizontal, false), min(min), max(max), decimals(decimals) { + // Avoid degenerate cases + if (max - min < 0.0001) { + max += 0.5; + min -= 0.5; + } +} + +// Attention: this is only heuristics. Before setting the actual size, we +// don't know the actual numbers of the minimum and maximum value. +std::pair<QString, QString> ValueAxis::getFirstLastLabel() const +{ + QLocale loc; + return { loc.toString(min, 'f', decimals), loc.toString(max, 'f', decimals) }; } void ValueAxis::updateLabels() @@ -230,15 +254,8 @@ void ValueAxis::updateLabels() labels.clear(); ticks.clear(); - // Avoid degenerate cases - if (max - min < 0.0001) { - max += 0.5; - min -= 0.5; - } - QLocale loc; - QString minString = loc.toString(min, 'f', decimals); - QString maxString = loc.toString(max, 'f', decimals); + auto [minString, maxString] = getFirstLastLabel(); int numTicks = guessNumTicks({ minString, maxString}); // Use full decimal increments @@ -279,6 +296,14 @@ CountAxis::CountAxis(const QString &title, int count, bool horizontal) : { } +// Attention: this is only heuristics. Before setting the actual size, we +// don't know the actual numbers of the minimum and maximum value. +std::pair<QString, QString> CountAxis::getFirstLastLabel() const +{ + QLocale loc; + return { QString("0"), loc.toString(count) }; +} + void CountAxis::updateLabels() { labels.clear(); @@ -333,6 +358,13 @@ CategoryAxis::CategoryAxis(const QString &title, const std::vector<QString> &lab setRange(-0.5, static_cast<double>(labels.size()) + 0.5); } +// No implementation because the labels are inside ticks and this +// is only used to calculate the "overhang" of labels under ticks. +std::pair<QString, QString> CategoryAxis::getFirstLastLabel() const +{ + return { QString(), QString() }; +} + void CategoryAxis::updateLabels() { // TODO: paint ellipses if space too small @@ -370,6 +402,14 @@ HistogramAxis::HistogramAxis(const QString &title, std::vector<HistogramAxisEntr setRange(bin_values.front().value, bin_values.back().value); } +std::pair<QString, QString> HistogramAxis::getFirstLastLabel() const +{ + if (bin_values.empty()) + return { QString(), QString() }; + else + return { bin_values.front().name, bin_values.back().name }; +} + // Initialize a histogram axis with the given labels. Labels are specified as (name, value, recommended) triplets. // If labels are skipped, try to skip it in such a way that a recommended label is shown. // The one example where this is relevant is the quarterly bins, which are formated as (2019, q1, q2, q3, 2020, ...). diff --git a/stats/statsaxis.h b/stats/statsaxis.h index 72a191963..9d46f753a 100644 --- a/stats/statsaxis.h +++ b/stats/statsaxis.h @@ -16,6 +16,7 @@ public: // Returns minimum and maximum of shown range, not of data points. std::pair<double, double> minMax() const; std::pair<double, double> minMaxScreen() const; // minimum and maximum in screen coordinates + std::pair<double, double> horizontalOverhang() const; // space that labels peak out in horizontal axes double width() const; // Only supported by vertical axes. Only valid after setSize(). double height() const; // Only supported for horizontal axes. Always valid. @@ -39,6 +40,7 @@ protected: std::vector<Label> labels; void addLabel(const QString &label, double pos); virtual void updateLabels() = 0; + virtual std::pair<QString, QString> getFirstLastLabel() const = 0; struct Tick { std::unique_ptr<QGraphicsLineItem> item; @@ -69,6 +71,7 @@ private: double min, max; int decimals; void updateLabels() override; + std::pair<QString, QString> getFirstLastLabel() const override; }; class CountAxis : public ValueAxis { @@ -77,6 +80,7 @@ public: private: int count; void updateLabels() override; + std::pair<QString, QString> getFirstLastLabel() const override; }; class CategoryAxis : public StatsAxis { @@ -85,6 +89,7 @@ public: private: std::vector<QString> labelsText; void updateLabels(); + std::pair<QString, QString> getFirstLastLabel() const override; }; struct HistogramAxisEntry { @@ -98,6 +103,7 @@ public: HistogramAxis(const QString &title, std::vector<HistogramAxisEntry> bin_values, bool horizontal); private: void updateLabels() override; + std::pair<QString, QString> getFirstLastLabel() const override; std::vector<HistogramAxisEntry> bin_values; int preferred_step; }; diff --git a/stats/statsview.cpp b/stats/statsview.cpp index 1533583ba..5583643d7 100644 --- a/stats/statsview.cpp +++ b/stats/statsview.cpp @@ -97,15 +97,21 @@ void StatsView::plotAreaChanged(const QSizeF &s) if (title) top += title->boundingRect().height() + titleBorder; // Currently, we only have either none, or an x- and a y-axis - if (xAxis) + std::pair<double,double> horizontalSpace{ 0.0, 0.0 }; + if (xAxis) { bottom -= xAxis->height(); + horizontalSpace = xAxis->horizontalOverhang(); + } if (bottom - top < minSize) return; if (yAxis) { yAxis->setSize(bottom - top); - left += yAxis->width(); - yAxis->setPos(QPointF(left, bottom)); + horizontalSpace.first = std::max(horizontalSpace.first, yAxis->width()); } + left += horizontalSpace.first; + right -= horizontalSpace.second; + if (yAxis) + yAxis->setPos(QPointF(left, bottom)); if (right - left < minSize) return; if (xAxis) { |