summaryrefslogtreecommitdiffstats
path: root/src/charts/axis/polarchartaxisradial.cpp
diff options
context:
space:
mode:
authorAlexander Mishin <apmishin@yandex.com>2016-11-06 20:09:29 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2016-12-16 13:24:21 +0000
commit80f1c28b5caa83234dbf85cb78f1ab0fea431fe2 (patch)
tree20b8c424dbe355de4f2500065a70f7eb68c9044a /src/charts/axis/polarchartaxisradial.cpp
parent9e788f7e9d083be44c91f9949eece4dbca273f29 (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.cpp218
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();
}
}
}