statistics: draw title of axes

Easy enough to implement, but one weirdness:
To get the height of the rotated text, one has to access the
width() member of the boundingRect. I'm not sure if that makes
sense, but so be it.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2021-01-05 13:04:53 +01:00 committed by Dirk Hohndel
parent 4ab9f1c6b0
commit 8dfa3f6db3
3 changed files with 55 additions and 29 deletions

View file

@ -23,10 +23,10 @@ static const double axisLabelSpaceVertical = 2.0; // Space between axis or ticks
static const double axisTitleSpaceHorizontal = 2.0; // Space between labels and title
static const double axisTitleSpaceVertical = 2.0; // Space between labels and title
StatsAxis::StatsAxis(QtCharts::QChart *chart, bool horizontal, bool labelsBetweenTicks) :
StatsAxis::StatsAxis(QtCharts::QChart *chart, const QString &titleIn, bool horizontal, bool labelsBetweenTicks) :
QGraphicsLineItem(chart),
chart(chart), horizontal(horizontal), labelsBetweenTicks(labelsBetweenTicks),
size(1.0), zeroOnScreen(0.0), min(0.0), max(1.0)
size(1.0), zeroOnScreen(0.0), min(0.0), max(1.0), labelWidth(0.0)
{
// use a Light version of the application fond for both labels and title
labelFont = QFont();
@ -34,6 +34,13 @@ StatsAxis::StatsAxis(QtCharts::QChart *chart, bool horizontal, bool labelsBetwee
titleFont = labelFont;
setPen(QPen(axisColor, axisWidth));
setZValue(ZValues::axes);
if (!titleIn.isEmpty()) {
title = std::make_unique<QGraphicsSimpleTextItem>(titleIn, chart);
title->setFont(titleFont);
title->setBrush(darkLabelColor);
if (!horizontal)
title->setRotation(-90.0);
}
}
StatsAxis::~StatsAxis()
@ -76,18 +83,19 @@ int StatsAxis::guessNumTicks(const std::vector<QString> &strings) const
return std::max(numTicks, 2);
}
double StatsAxis::titleSpace() const
{
if (!title)
return 0.0;
return horizontal ? QFontMetrics(titleFont).height() + axisTitleSpaceHorizontal
: QFontMetrics(titleFont).height() + axisTitleSpaceVertical;
}
double StatsAxis::width() const
{
if (horizontal)
return 0.0; // Only supported for vertical axes
double labelWidth = 0.0;
for (const Label &label: labels) {
double w = label.label->boundingRect().width();
if (w > labelWidth)
labelWidth = w;
}
return labelWidth + axisLabelSpaceVertical +
QFontMetrics(titleFont).height() + axisTitleSpaceVertical +
return labelWidth + axisLabelSpaceVertical + titleSpace() +
(labelsBetweenTicks ? 0.0 : axisTickSizeVertical);
}
@ -96,7 +104,7 @@ double StatsAxis::height() const
if (!horizontal)
return 0.0; // Only supported for horizontal axes
return QFontMetrics(labelFont).height() + axisLabelSpaceHorizontal +
QFontMetrics(titleFont).height() + axisTitleSpaceHorizontal +
titleSpace() +
(labelsBetweenTicks ? 0.0 : axisTickSizeHorizontal);
}
@ -146,6 +154,12 @@ void StatsAxis::setSize(double sizeIn)
{
size = sizeIn;
updateLabels();
labelWidth = 0.0;
for (const Label &label: labels) {
double w = label.label->boundingRect().width();
if (w > labelWidth)
labelWidth = w;
}
}
void StatsAxis::setPos(QPointF pos)
@ -164,6 +178,9 @@ void StatsAxis::setPos(QPointF pos)
tick.item->setLine(x, y, x, y + axisTickSizeHorizontal);
}
setLine(zeroOnScreen, y, zeroOnScreen + size, y);
if (title)
title->setPos(zeroOnScreen + (size - title->boundingRect().width()) / 2.0,
labelY + QFontMetrics(labelFont).height() + axisTitleSpaceHorizontal);
} else {
double fontHeight = QFontMetrics(labelFont).height();
zeroOnScreen = pos.y();
@ -178,12 +195,18 @@ void StatsAxis::setPos(QPointF pos)
double y = toScreen(tick.pos);
tick.item->setLine(x, y, x - axisTickSizeVertical, y);
}
// This is very confusing: even though we need the height of the title, the correct
// size is stored in boundingRect().width(). Presumably because the item is rotated
// by -90°. Apparently, the boundingRect is in item-local coordinates?
if (title)
title->setPos(labelX - labelWidth - QFontMetrics(labelFont).height() - axisTitleSpaceVertical,
zeroOnScreen - (size - title->boundingRect().width()) / 2.0);
setLine(x, zeroOnScreen, x, zeroOnScreen - size);
}
}
ValueAxis::ValueAxis(QtCharts::QChart *chart, double min, double max, int decimals, bool horizontal) :
StatsAxis(chart, horizontal, false),
ValueAxis::ValueAxis(QtCharts::QChart *chart, const QString &title, double min, double max, int decimals, bool horizontal) :
StatsAxis(chart, title, horizontal, false),
min(min), max(max), decimals(decimals)
{
}
@ -237,8 +260,8 @@ void ValueAxis::updateLabels()
}
}
CountAxis::CountAxis(QtCharts::QChart *chart, int count, bool horizontal) :
ValueAxis(chart, 0.0, (double)count, 0, horizontal),
CountAxis::CountAxis(QtCharts::QChart *chart, const QString &title, int count, bool horizontal) :
ValueAxis(chart, title, 0.0, (double)count, 0, horizontal),
count(count)
{
}
@ -290,8 +313,8 @@ void CountAxis::updateLabels()
}
}
CategoryAxis::CategoryAxis(QtCharts::QChart *chart, const std::vector<QString> &labelsIn, bool horizontal) :
StatsAxis(chart, horizontal, true)
CategoryAxis::CategoryAxis(QtCharts::QChart *chart, const QString &title, const std::vector<QString> &labelsIn, bool horizontal) :
StatsAxis(chart, title, horizontal, true)
{
labels.reserve(labelsIn.size());
ticks.reserve(labelsIn.size() + 1);
@ -309,8 +332,8 @@ void CategoryAxis::updateLabels()
{
}
HistogramAxis::HistogramAxis(QtCharts::QChart *chart, std::vector<HistogramAxisEntry> bins, bool horizontal) :
StatsAxis(chart, horizontal, false),
HistogramAxis::HistogramAxis(QtCharts::QChart *chart, const QString &title, std::vector<HistogramAxisEntry> bins, bool horizontal) :
StatsAxis(chart, title, horizontal, false),
bin_values(std::move(bins))
{
if (bin_values.size() < 2) // Less than two makes no sense -> there must be at least one category
@ -498,7 +521,7 @@ static std::vector<HistogramAxisEntry> timeRangeToBins(double from, double to)
return res;
}
DateAxis::DateAxis(QtCharts::QChart *chart, double from, double to, bool horizontal) :
HistogramAxis(chart, timeRangeToBins(from, to), horizontal)
DateAxis::DateAxis(QtCharts::QChart *chart, const QString &title, double from, double to, bool horizontal) :
HistogramAxis(chart, title, timeRangeToBins(from, to), horizontal)
{
}

View file

@ -31,7 +31,7 @@ public:
double toScreen(double) const;
double toValue(double) const;
protected:
StatsAxis(QtCharts::QChart *chart, bool horizontal, bool labelsBetweenTicks);
StatsAxis(QtCharts::QChart *chart, const QString &title, bool horizontal, bool labelsBetweenTicks);
QtCharts::QChart *chart;
struct Label {
@ -56,14 +56,18 @@ protected:
bool labelsBetweenTicks; // When labels are between ticks, they can be moved closer to the axis
QFont labelFont, titleFont;
std::unique_ptr<QGraphicsSimpleTextItem> title;
double size; // width for horizontal, height for vertical
double zeroOnScreen;
double min, max;
double labelWidth; // Maximum width of labels
private:
double titleSpace() const; // Space needed for title
};
class ValueAxis : public StatsAxis {
public:
ValueAxis(QtCharts::QChart *chart, double min, double max, int decimals, bool horizontal);
ValueAxis(QtCharts::QChart *chart, const QString &title, double min, double max, int decimals, bool horizontal);
private:
double min, max;
int decimals;
@ -72,7 +76,7 @@ private:
class CountAxis : public ValueAxis {
public:
CountAxis(QtCharts::QChart *chart, int count, bool horizontal);
CountAxis(QtCharts::QChart *chart, const QString &title, int count, bool horizontal);
private:
int count;
void updateLabels() override;
@ -80,7 +84,7 @@ private:
class CategoryAxis : public StatsAxis {
public:
CategoryAxis(QtCharts::QChart *chart, const std::vector<QString> &labels, bool horizontal);
CategoryAxis(QtCharts::QChart *chart, const QString &title, const std::vector<QString> &labels, bool horizontal);
private:
void updateLabels();
};
@ -93,7 +97,7 @@ struct HistogramAxisEntry {
class HistogramAxis : public StatsAxis {
public:
HistogramAxis(QtCharts::QChart *chart, std::vector<HistogramAxisEntry> bin_values, bool horizontal);
HistogramAxis(QtCharts::QChart *chart, const QString &title, std::vector<HistogramAxisEntry> bin_values, bool horizontal);
private:
void updateLabels() override;
std::vector<HistogramAxisEntry> bin_values;
@ -102,7 +106,7 @@ private:
class DateAxis : public HistogramAxis {
public:
DateAxis(QtCharts::QChart *chart, double from, double to, bool horizontal);
DateAxis(QtCharts::QChart *chart, const QString &title, double from, double to, bool horizontal);
};
#endif

View file

@ -186,8 +186,7 @@ void StatsView::updateTitlePos()
template <typename T, class... Args>
T *StatsView::createAxis(const QString &title, Args&&... args)
{
// TODO: set title
T *res = new T(chart, std::forward<Args>(args)...);
T *res = new T(chart, title, std::forward<Args>(args)...);
axes.emplace_back(res);
return res;
}