diff options
author | Alexander Mishin <apmishin@yandex.com> | 2016-11-06 20:09:29 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2016-12-16 13:24:21 +0000 |
commit | 80f1c28b5caa83234dbf85cb78f1ab0fea431fe2 (patch) | |
tree | 20b8c424dbe355de4f2500065a70f7eb68c9044a /src/charts/axis/polarchartaxisradial.cpp | |
parent | 9e788f7e9d083be44c91f9949eece4dbca273f29 (diff) |
Add minor ticks support for QLogValueAxis
- added QLogValueAxis::minorTickCount property
- added QLogValueAxis::tickCount property (read-only)
- added logarithmically distributed minor ticks for VerticalAxis
- added logarithmically distributed minor ticks for HorizontalAxis
- added logarithmically distributed minor ticks for PolarChartAxisAngular
- added logarithmically distributed minor ticks for PolarChartAxisRadial
- updated example for QLogValueAxis
- added tickCount and minorTickCount properties documentation for QLogValueAxis
Task-number: QTBUG-51612
Change-Id: I92a0af81f741e7b2ba871a64f801176399b9e9a5
Reviewed-by: Alexander Mishin <apmishin@yandex.com>
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Diffstat (limited to 'src/charts/axis/polarchartaxisradial.cpp')
-rw-r--r-- | src/charts/axis/polarchartaxisradial.cpp | 218 |
1 files changed, 158 insertions, 60 deletions
diff --git a/src/charts/axis/polarchartaxisradial.cpp b/src/charts/axis/polarchartaxisradial.cpp index f746c038..23ba1e41 100644 --- a/src/charts/axis/polarchartaxisradial.cpp +++ b/src/charts/axis/polarchartaxisradial.cpp @@ -27,17 +27,18 @@ ** ****************************************************************************/ -#include <private/polarchartaxisradial_p.h> +#include <QtCharts/qcategoryaxis.h> +#include <QtCharts/qlogvalueaxis.h> +#include <QtCore/qmath.h> +#include <QtGui/qtextdocument.h> #include <private/chartpresenter_p.h> -#include <private/abstractchartlayout_p.h> -#include <private/qabstractaxis_p.h> #include <private/linearrowitem_p.h> -#include <QtCharts/QCategoryAxis> -#include <QtGui/QTextDocument> +#include <private/polarchartaxisradial_p.h> QT_CHARTS_BEGIN_NAMESPACE -PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis) +PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, + bool intervalAxis) : PolarChartAxis(axis, item, intervalAxis) { } @@ -225,39 +226,10 @@ void PolarChartAxisRadial::updateGeometry() shadeItem->setVisible(true); firstShade = false; } - - // Minor ticks - QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis()); - if ((i + 1) != layout.size() && valueAxis) { - int minorTickCount = valueAxis->minorTickCount(); - if (minorTickCount != 0) { - qreal minorRadialCoordinate = (layout[i + 1] - layout[i]) - / qreal(minorTickCount + 1) * 2.0; - for (int j = 0; j < minorTickCount; j++) { - QGraphicsEllipseItem *minorGridItem = - static_cast<QGraphicsEllipseItem *>(minorGridItemList.at(i * minorTickCount + j)); - QGraphicsLineItem *minorTickItem = - static_cast<QGraphicsLineItem *>(minorArrowItemList.at(i * minorTickCount + j)); - - QRectF minorGridRect; - minorGridRect.setWidth(minorRadialCoordinate * qreal(i + 1) - + minorRadialCoordinate * qreal(i * minorTickCount + j)); - minorGridRect.setHeight(minorRadialCoordinate * qreal(i + 1) - + minorRadialCoordinate - * qreal(i * minorTickCount + j)); - minorGridRect.moveCenter(center); - minorGridItem->setRect(minorGridRect); - minorGridItem->setVisible(true); - - QLineF minorTickLine(-tickWidth() + 1, 0.0, tickWidth() - 1, 0.0); - tickLine.translate(center.rx(), minorGridRect.top()); - minorTickItem->setLine(minorTickLine); - minorTickItem->setVisible(true); - } - } - } } + updateMinorTickGeometry(); + // Title, along the 0 axis QString titleText = axis()->titleText(); if (!titleText.isEmpty() && axis()->isTitleVisible()) { @@ -378,31 +350,157 @@ qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize) return radius; } -void PolarChartAxisRadial::updateMinorTickItems() +void PolarChartAxisRadial::updateMinorTickGeometry() { - QValueAxis *valueAxis = qobject_cast<QValueAxis *>(this->axis()); - if (valueAxis) { - int currentCount = minorArrowItems().size(); - int expectedCount = valueAxis->minorTickCount() * (valueAxis->tickCount() - 1); - int diff = expectedCount - currentCount; - if (diff > 0) { - for (int i = 0; i < diff; i++) { - QGraphicsLineItem *minorArrow = new QGraphicsLineItem(presenter()->rootItem()); - QGraphicsEllipseItem *minorGrid = new QGraphicsEllipseItem(presenter()->rootItem()); - minorArrow->setPen(valueAxis->linePen()); - minorGrid->setPen(valueAxis->minorGridLinePen()); - minorArrowGroup()->addToGroup(minorArrow); - minorGridGroup()->addToGroup(minorGrid); - } + if (!axis()) + return; + + QVector<qreal> layout = ChartAxisElement::layout(); + int minorTickCount = 0; + qreal tickRadius = 0.0; + QVector<qreal> minorTickRadiuses; + switch (axis()->type()) { + case QAbstractAxis::AxisTypeValue: { + const QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis()); + + minorTickCount = valueAxis->minorTickCount(); + + if (valueAxis->tickCount() >= 2) + tickRadius = layout.at(1) - layout.at(0); + + for (int i = 0; i < minorTickCount; ++i) { + const qreal ratio = (1.0 / qreal(minorTickCount + 1)) * qreal(i + 1); + minorTickRadiuses.append(tickRadius * ratio); + } + break; + } + case QAbstractAxis::AxisTypeLogValue: { + const QLogValueAxis *logValueAxis = qobject_cast<QLogValueAxis *>(axis()); + const qreal base = logValueAxis->base(); + const qreal logBase = qLn(base); + + minorTickCount = logValueAxis->minorTickCount(); + if (minorTickCount < 0) + minorTickCount = qMax(int(qFloor(base) - 2.0), 0); + + // Two "virtual" ticks are required to make sure that all minor ticks + // are displayed properly (even for the partially visible segments of + // the chart). + if (layout.size() >= 2) { + // Calculate tickRadius as a difference between visible ticks + // whenever it is possible. Virtual ticks will not be correctly + // positioned when the layout is animating. + tickRadius = layout.at(1) - layout.at(0); + layout.prepend(layout.at(0) - tickRadius); + layout.append(layout.at(layout.size() - 1) + tickRadius); } else { - QList<QGraphicsItem *> minorGridLines = minorGridItems(); - QList<QGraphicsItem *> minorArrows = minorArrowItems(); - for (int i = 0; i > diff; i--) { - if (!minorGridLines.isEmpty()) - delete(minorGridLines.takeLast()); - if (!minorArrows.isEmpty()) - delete(minorArrows.takeLast()); - } + const qreal logMax = qLn(logValueAxis->max()); + const qreal logMin = qLn(logValueAxis->min()); + const qreal logExtraMaxTick = qLn(qPow(base, qFloor(logMax / logBase) + 1.0)); + const qreal logExtraMinTick = qLn(qPow(base, qCeil(logMin / logBase) - 1.0)); + const qreal edge = qMin(logMin, logMax); + const qreal delta = (axisGeometry().width() / 2.0) / qAbs(logMax - logMin); + const qreal extraMaxTick = edge + (logExtraMaxTick - edge) * delta; + const qreal extraMinTick = edge + (logExtraMinTick - edge) * delta; + + // Calculate tickRadius using one (if layout.size() == 1) or two + // (if layout.size() == 0) "virtual" ticks. In both cases animation + // will not work as expected. This should be fixed later. + layout.prepend(extraMinTick); + layout.append(extraMaxTick); + tickRadius = layout.at(1) - layout.at(0); + } + + const qreal minorTickStepValue = qFabs(base - 1.0) / qreal(minorTickCount + 1); + for (int i = 0; i < minorTickCount; ++i) { + const qreal x = minorTickStepValue * qreal(i + 1) + 1.0; + const qreal minorTickSpacing = tickRadius * (qLn(x) / logBase); + minorTickRadiuses.append(minorTickSpacing); + } + break; + } + default: + // minor ticks are not supported + break; + } + + if (minorTickCount < 1 || tickRadius == 0.0 || minorTickRadiuses.count() != minorTickCount) + return; + + const QPointF axisCenter = axisGeometry().center(); + const qreal axisRadius = axisGeometry().height() / 2.0; + + for (int i = 0; i < layout.size() - 1; ++i) { + for (int j = 0; j < minorTickCount; ++j) { + const int minorItemIndex = i * minorTickCount + j; + QGraphicsEllipseItem *minorGridLineItem = + static_cast<QGraphicsEllipseItem *>(minorGridItems().at(minorItemIndex)); + QGraphicsLineItem *minorArrowLineItem = + static_cast<QGraphicsLineItem *>(minorArrowItems().at(minorItemIndex)); + if (!minorGridLineItem || !minorArrowLineItem) + continue; + + const qreal minorTickRadius = layout.at(i) + minorTickRadiuses.value(j, 0.0); + const qreal minorTickDiameter = minorTickRadius * 2.0; + + QRectF minorGridLine(0.0, 0.0, minorTickDiameter, minorTickDiameter); + minorGridLine.moveCenter(axisCenter); + minorGridLineItem->setRect(minorGridLine); + + QLineF minorArrowLine(-tickWidth() + 1.0, 0.0, tickWidth() - 1.0, 0.0); + minorArrowLine.translate(axisCenter.x(), minorGridLine.top()); + minorArrowLineItem->setLine(minorArrowLine); + + // check if the minor grid line and the minor axis arrow should be shown + bool minorGridLineVisible = (minorTickRadius >= 0.0 && minorTickRadius <= axisRadius); + minorGridLineItem->setVisible(minorGridLineVisible); + minorArrowLineItem->setVisible(minorGridLineVisible); + } + } +} + +void PolarChartAxisRadial::updateMinorTickItems() +{ + int currentCount = minorArrowItems().size(); + int expectedCount = 0; + if (axis()->type() == QAbstractAxis::AxisTypeValue) { + QValueAxis *valueAxis = qobject_cast<QValueAxis *>(axis()); + expectedCount = valueAxis->minorTickCount() * (valueAxis->tickCount() - 1); + expectedCount = qMax(expectedCount, 0); + } else if (axis()->type() == QAbstractAxis::AxisTypeLogValue) { + QLogValueAxis *logValueAxis = qobject_cast<QLogValueAxis *>(axis()); + + int minorTickCount = logValueAxis->minorTickCount(); + if (minorTickCount < 0) + minorTickCount = qMax(int(qFloor(logValueAxis->base()) - 2.0), 0); + + expectedCount = minorTickCount * (logValueAxis->tickCount() + 1); + expectedCount = qMax(expectedCount, logValueAxis->minorTickCount()); + } else { + // minor ticks are not supported + return; + } + + int diff = expectedCount - currentCount; + if (diff > 0) { + for (int i = 0; i < diff; ++i) { + QGraphicsEllipseItem *minorGridItem = new QGraphicsEllipseItem(presenter()->rootItem()); + minorGridItem->setPen(axis()->minorGridLinePen()); + minorGridGroup()->addToGroup(minorGridItem); + + QGraphicsLineItem *minorArrowItem = new QGraphicsLineItem(presenter()->rootItem()); + minorArrowItem->setPen(axis()->linePen()); + minorArrowGroup()->addToGroup(minorArrowItem); + } + } else { + QList<QGraphicsItem *> minorGridItemsList = minorGridItems(); + QList<QGraphicsItem *> minorArrowItemsList = minorArrowItems(); + for (int i = 0; i > diff; --i) { + if (!minorGridItemsList.isEmpty()) + delete minorGridItemsList.takeLast(); + + if (!minorArrowItemsList.isEmpty()) + delete minorArrowItemsList.takeLast(); } } } |