summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorLukas Kosinski <lukasz@scythe-studio.com>2021-05-18 15:28:02 +0200
committerLukas Kosinski <lukasz@scythe-studio.com>2021-06-03 14:16:15 +0200
commit3fadbefd2e12e1d3bf1a0bc240d92202926c4889 (patch)
tree0e804fc6485a3e4bb7d8830730a6eb0118a0a65b /src
parent0d9811775fbf82d0630b8725806fe229694e2449 (diff)
Add colorBy method to QXYSeries and QColorAxis
This feature adds the availability to pass list of values that will be used to colorize points using points configuration feature according to the gradient. Gradient can be either set when calling the colorBy method or can be taken from attached QColorAxis. QColorAxis displays color scale widget with ticks and range based on data passed as colorBy method's parameter. Task-number: QTBUG-89447 Change-Id: I611048fac0e787e0a1eeaf181c5d8e8a8354fac5 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/charts/CMakeLists.txt4
-rw-r--r--src/charts/axis/chartaxiselement.cpp77
-rw-r--r--src/charts/axis/chartaxiselement_p.h8
-rw-r--r--src/charts/axis/coloraxis/chartcoloraxisx.cpp120
-rw-r--r--src/charts/axis/coloraxis/chartcoloraxisx_p.h68
-rw-r--r--src/charts/axis/coloraxis/chartcoloraxisy.cpp122
-rw-r--r--src/charts/axis/coloraxis/chartcoloraxisy_p.h68
-rw-r--r--src/charts/axis/coloraxis/qcoloraxis.cpp399
-rw-r--r--src/charts/axis/coloraxis/qcoloraxis.h91
-rw-r--r--src/charts/axis/coloraxis/qcoloraxis_p.h81
-rw-r--r--src/charts/axis/horizontalaxis.cpp94
-rw-r--r--src/charts/axis/qabstractaxis.cpp1
-rw-r--r--src/charts/axis/qabstractaxis.h3
-rw-r--r--src/charts/axis/qabstractaxis_p.h2
-rw-r--r--src/charts/axis/verticalaxis.cpp99
-rw-r--r--src/charts/chartdataset.cpp5
-rw-r--r--src/charts/domain/abstractdomain.cpp18
-rw-r--r--src/charts/xychart/qxyseries.cpp83
-rw-r--r--src/charts/xychart/qxyseries.h2
-rw-r--r--src/charts/xychart/qxyseries_p.h3
20 files changed, 1288 insertions, 60 deletions
diff --git a/src/charts/CMakeLists.txt b/src/charts/CMakeLists.txt
index 3eedc51f..6f61dd0e 100644
--- a/src/charts/CMakeLists.txt
+++ b/src/charts/CMakeLists.txt
@@ -20,6 +20,9 @@ qt_internal_add_module(Charts
axis/categoryaxis/polarchartcategoryaxisangular.cpp axis/categoryaxis/polarchartcategoryaxisangular_p.h
axis/categoryaxis/polarchartcategoryaxisradial.cpp axis/categoryaxis/polarchartcategoryaxisradial_p.h
axis/categoryaxis/qcategoryaxis.cpp axis/categoryaxis/qcategoryaxis.h axis/categoryaxis/qcategoryaxis_p.h
+ axis/coloraxis/qcoloraxis.cpp axis/coloraxis/qcoloraxis.h axis/coloraxis/qcoloraxis_p.h
+ axis/coloraxis/chartcoloraxisy.cpp axis/coloraxis/chartcoloraxisy_p.h
+ axis/coloraxis/chartcoloraxisx.cpp axis/coloraxis/chartcoloraxisx_p.h
axis/chartaxiselement.cpp axis/chartaxiselement_p.h
axis/editableaxislabel.cpp axis/editableaxislabel_p.h
axis/horizontalaxis.cpp axis/horizontalaxis_p.h
@@ -96,6 +99,7 @@ qt_internal_add_module(Charts
axis
axis/barcategoryaxis
axis/categoryaxis
+ axis/coloraxis
axis/logvalueaxis
axis/valueaxis
domain
diff --git a/src/charts/axis/chartaxiselement.cpp b/src/charts/axis/chartaxiselement.cpp
index 93cbebda..d152d7bb 100644
--- a/src/charts/axis/chartaxiselement.cpp
+++ b/src/charts/axis/chartaxiselement.cpp
@@ -32,10 +32,12 @@
#include <private/chartpresenter_p.h>
#include <private/abstractchartlayout_p.h>
#include <QtCharts/QCategoryAxis>
+#include <QtCharts/QColorAxis>
#include <QtCore/QtMath>
#include <QtCore/QDateTime>
#include <QtCore/QRegularExpression>
#include <QtGui/QTextDocument>
+#include <QPainter>
#include <cmath>
QT_BEGIN_NAMESPACE
@@ -66,6 +68,7 @@ ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, boo
m_shades(new QGraphicsItemGroup(item)),
m_labels(new QGraphicsItemGroup(item)),
m_title(new QGraphicsTextItem(item)),
+ m_colorScale(nullptr),
m_intervalAxis(intervalAxis)
{
@@ -80,6 +83,12 @@ ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, boo
m_minorGrid->setZValue(ChartPresenter::GridZValue);
m_title->setZValue(ChartPresenter::GridZValue);
m_title->document()->setDocumentMargin(ChartPresenter::textMargin());
+ if (m_axis->type() == QAbstractAxis::AxisTypeColor) {
+ m_colorScale = std::make_unique<QGraphicsPixmapItem>(new QGraphicsPixmapItem(item));
+ m_colorScale->setZValue(ChartPresenter::GridZValue);
+ m_colorScale->setVisible(false);
+ }
+
handleVisibleChanged(axis->isVisible());
connectSlots();
@@ -131,6 +140,12 @@ void ChartAxisElement::connectSlots()
SIGNAL(labelsPositionChanged(QCategoryAxis::AxisLabelsPosition)),
this, SLOT(handleLabelsPositionChanged()));
}
+
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ QObject::connect(colorAxis, &QColorAxis::sizeChanged, this, &ChartAxisElement::handleColorScaleSizeChanged);
+ QObject::connect(colorAxis, &QColorAxis::gradientChanged, this, &ChartAxisElement::handleColorScaleGradientChanged);
+ }
}
void ChartAxisElement::handleArrowVisibleChanged(bool visible)
@@ -165,6 +180,17 @@ void ChartAxisElement::handleTruncateLabelsChanged()
presenter()->layout()->invalidate();
}
+void ChartAxisElement::handleColorScaleSizeChanged()
+{
+ QGraphicsLayoutItem::updateGeometry();
+}
+
+void ChartAxisElement::handleColorScaleGradientChanged()
+{
+ const QPixmap &pixmap = m_colorScale->pixmap();
+ prepareColorScale(pixmap.width(), pixmap.height());
+}
+
void ChartAxisElement::valueLabelEdited(qreal oldValue, qreal newValue)
{
qreal range = max() - min();
@@ -416,6 +442,42 @@ QString ChartAxisElement::formatLabel(const QString &formatSpec, const QByteArra
return retVal;
}
+void ChartAxisElement::prepareColorScale(const qreal width, const qreal height)
+{
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+
+ if (colorAxis->gradient() != QLinearGradient() && width != 0 && height != 0) {
+ m_colorScale->setVisible(true);
+
+ QImage image(width, height, QImage::Format_ARGB32);
+ QPainter painter(&image);
+
+ QLinearGradient gradient;
+ if (colorAxis->orientation() == Qt::Horizontal) {
+ gradient = QLinearGradient(QPointF(0, 0), QPointF(width, 0));
+ const auto &stops = colorAxis->gradient().stops();
+ for (const auto &stop : stops)
+ gradient.setColorAt(stop.first, stop.second);
+ } else {
+ gradient = QLinearGradient(QPointF(0, 0), QPointF(0, height));
+ for (int i = colorAxis->gradient().stops().length() - 1; i >= 0; --i) {
+ const auto &stop = colorAxis->gradient().stops()[i];
+ gradient.setColorAt(1 - stop.first, stop.second);
+ }
+ }
+
+ painter.fillRect(image.rect(), gradient);
+
+ painter.setPen(axis()->linePen());
+ painter.drawRect(image.rect());
+
+ const QPixmap &pixmap = QPixmap::fromImage(image);
+ m_colorScale->setPixmap(pixmap);
+ }
+ }
+}
+
QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks,
qreal tickInterval, qreal tickAnchor,
QValueAxis::TickType tickType,
@@ -564,6 +626,21 @@ QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int tick
return labels;
}
+QStringList ChartAxisElement::createColorLabels(qreal min, qreal max, int ticks) const
+{
+ QStringList labels;
+
+ if (max <= min || ticks < 1)
+ return labels;
+
+ int n = qMax(int(-qFloor(std::log10((max - min) / (ticks - 1)))), 0) + 1;
+ for (int i = 0; i < ticks; ++i) {
+ qreal value = min + (i * (max - min) / (ticks - 1));
+ labels << presenter()->numberToString(value, 'f', n);
+ }
+
+ return labels;
+}
bool ChartAxisElement::labelsEditable() const
{
diff --git a/src/charts/axis/chartaxiselement_p.h b/src/charts/axis/chartaxiselement_p.h
index ca19e6a5..7a63ca5c 100644
--- a/src/charts/axis/chartaxiselement_p.h
+++ b/src/charts/axis/chartaxiselement_p.h
@@ -85,6 +85,7 @@ public:
} // Modifiable reference
inline qreal labelPadding() const { return qreal(4.0); }
inline qreal titlePadding() const { return qreal(2.0); }
+ inline qreal colorScalePadding() const { return qreal { 8.0 }; }
void setLabels(const QStringList &labels) { m_labelsList = labels; }
QStringList labels() const { return m_labelsList; }
@@ -108,6 +109,7 @@ public:
QStringList createLogValueLabels(qreal min, qreal max, qreal base, int ticks,
const QString &format) const;
QStringList createDateTimeLabels(qreal max, qreal min, int ticks, const QString &format) const;
+ QStringList createColorLabels(qreal min, qreal max, int ticks) const;
// from QGraphicsLayoutItem
QRectF boundingRect() const override
@@ -134,6 +136,7 @@ protected:
QList<QGraphicsItem *> arrowItems() { return m_arrow->childItems(); }
QList<QGraphicsItem *> minorArrowItems() { return m_minorArrow->childItems(); }
QGraphicsTextItem *titleItem() const { return m_title.data(); }
+ QGraphicsPixmapItem *colorScaleItem() const { return m_colorScale.get(); }
QGraphicsItemGroup *gridGroup() { return m_grid.data(); }
QGraphicsItemGroup *minorGridGroup() { return m_minorGrid.data(); }
QGraphicsItemGroup *labelGroup() { return m_labels.data(); }
@@ -141,6 +144,8 @@ protected:
QGraphicsItemGroup *arrowGroup() { return m_arrow.data(); }
QGraphicsItemGroup *minorArrowGroup() { return m_minorArrow.data(); }
+ void prepareColorScale(const qreal width, const qreal height);
+
public Q_SLOTS:
void handleVisibleChanged(bool visible);
void handleArrowVisibleChanged(bool visible);
@@ -168,6 +173,8 @@ public Q_SLOTS:
void handleMinorGridVisibleChanged(bool visible);
void handleLabelsPositionChanged();
void handleTruncateLabelsChanged();
+ void handleColorScaleSizeChanged();
+ void handleColorScaleGradientChanged();
void valueLabelEdited(qreal oldValue, qreal newValue);
void dateTimeLabelEdited(const QDateTime &oldTime, const QDateTime &newTime);
@@ -193,6 +200,7 @@ private:
QScopedPointer<QGraphicsItemGroup> m_shades;
QScopedPointer<QGraphicsItemGroup> m_labels;
QScopedPointer<QGraphicsTextItem> m_title;
+ std::unique_ptr<QGraphicsPixmapItem> m_colorScale;
bool m_intervalAxis;
bool m_labelsEditable = false;
};
diff --git a/src/charts/axis/coloraxis/chartcoloraxisx.cpp b/src/charts/axis/coloraxis/chartcoloraxisx.cpp
new file mode 100644
index 00000000..43806164
--- /dev/null
+++ b/src/charts/axis/coloraxis/chartcoloraxisx.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "chartcoloraxisx_p.h"
+#include <QtCharts/QColorAxis>
+#include <private/chartpresenter_p.h>
+#include <private/abstractchartlayout_p.h>
+#include <QtWidgets/QGraphicsLayout>
+
+QT_BEGIN_NAMESPACE
+
+ChartColorAxisX::ChartColorAxisX(QColorAxis *axis, QGraphicsItem *item)
+ : HorizontalAxis(axis, item, true)
+ , m_axis(axis)
+{
+
+}
+
+ChartColorAxisX::~ChartColorAxisX()
+{
+}
+
+QSizeF ChartColorAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_UNUSED(constraint);
+
+ QSizeF sh;
+
+ QSizeF base = HorizontalAxis::sizeHint(which, constraint);
+ const QStringList &ticksList = createColorLabels(min(), max(), m_axis->tickCount());
+ // Width of horizontal axis sizeHint indicates the maximum distance labels can extend past
+ // first and last ticks. Base width is irrelevant.
+ qreal width = 0;
+ qreal height = 0;
+
+ switch (which) {
+ case Qt::MinimumSize: {
+ QRectF boundingRect = ChartPresenter::textBoundingRect(
+ axis()->labelsFont(), QStringLiteral("..."), axis()->labelsAngle());
+ width = boundingRect.width() / 2.0;
+ height = boundingRect.height() + labelPadding() + base.height() + m_axis->size()
+ + colorScalePadding() + 1.0;
+ sh = QSizeF(width, height);
+ break;
+ }
+ case Qt::PreferredSize: {
+ qreal labelHeight = 0.0;
+ qreal firstWidth = -1.0;
+ for (const QString &s : ticksList) {
+ QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s,
+ axis()->labelsAngle());
+ labelHeight = qMax(rect.height(), labelHeight);
+ width = rect.width();
+ if (firstWidth < 0.0)
+ firstWidth = width;
+ }
+ height = labelHeight + labelPadding() + base.height() + m_axis->size() + colorScalePadding()
+ + 1.0;
+ width = qMax(width, firstWidth) / 2.0;
+ sh = QSizeF(width, height);
+ break;
+ }
+ default:
+ break;
+ }
+ return sh;
+}
+
+QList<qreal> ChartColorAxisX::calculateLayout() const
+{
+ int tickCount = m_axis->tickCount();
+
+ Q_ASSERT(tickCount >= 2);
+
+ QList<qreal> points;
+ points.resize(tickCount);
+
+ const QRectF &gridRect = gridGeometry();
+ const qreal deltaX = gridRect.width() / (qreal(tickCount) - 1.0);
+ for (int i = 0; i < tickCount; ++i)
+ points[i] = qreal(i) * deltaX + gridRect.left();
+ return points;
+}
+
+void ChartColorAxisX::updateGeometry()
+{
+ setLabels(createColorLabels(min(), max(), m_axis->tickCount()));
+ HorizontalAxis::updateGeometry();
+}
+
+
+QT_END_NAMESPACE
+
+#include "moc_chartcoloraxisx_p.cpp"
diff --git a/src/charts/axis/coloraxis/chartcoloraxisx_p.h b/src/charts/axis/coloraxis/chartcoloraxisx_p.h
new file mode 100644
index 00000000..170f6519
--- /dev/null
+++ b/src/charts/axis/coloraxis/chartcoloraxisx_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CHARTCOLORAXISX_H
+#define CHARTCOLORAXISX_H
+
+#include <private/horizontalaxis_p.h>
+#include <QtCharts/private/qchartglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QColorAxis;
+
+class Q_CHARTS_PRIVATE_EXPORT ChartColorAxisX : public HorizontalAxis
+{
+ Q_OBJECT
+public:
+ ChartColorAxisX(QColorAxis *axis, QGraphicsItem* item = 0);
+ ~ChartColorAxisX();
+
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const override;
+
+protected:
+ QList<qreal> calculateLayout() const override;
+ void updateGeometry() override;
+
+private:
+ QColorAxis *m_axis;
+};
+
+QT_END_NAMESPACE
+
+#endif // CHARTCOLORAXISX_H
diff --git a/src/charts/axis/coloraxis/chartcoloraxisy.cpp b/src/charts/axis/coloraxis/chartcoloraxisy.cpp
new file mode 100644
index 00000000..24a4bf8d
--- /dev/null
+++ b/src/charts/axis/coloraxis/chartcoloraxisy.cpp
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <private/chartcoloraxisy_p.h>
+#include <QtCharts/QColorAxis>
+#include <private/chartpresenter_p.h>
+#include <private/abstractchartlayout_p.h>
+#include <QtWidgets/QGraphicsLayout>
+
+QT_BEGIN_NAMESPACE
+
+ChartColorAxisY::ChartColorAxisY(QColorAxis *axis, QGraphicsItem *item)
+ : VerticalAxis(axis, item, true)
+ , m_axis(axis)
+{
+}
+
+ChartColorAxisY::~ChartColorAxisY()
+{
+}
+
+QList<qreal> ChartColorAxisY::calculateLayout() const
+{
+ int tickCount = m_axis->tickCount();
+
+ Q_ASSERT(tickCount >= 2);
+
+ QList<qreal> points;
+ points.resize(tickCount);
+
+ const QRectF &gridRect = gridGeometry();
+
+ const qreal deltaY = gridRect.height() / (qreal(tickCount) - 1.0);
+ for (int i = 0; i < tickCount; ++i)
+ points[i] = qreal(i) * -deltaY + gridRect.bottom();
+
+ return points;
+}
+
+void ChartColorAxisY::updateGeometry()
+{
+ setLabels(createColorLabels(min(), max(), m_axis->tickCount()) << QString());
+
+ VerticalAxis::updateGeometry();
+}
+
+QSizeF ChartColorAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_UNUSED(constraint);
+
+ QSizeF sh;
+ QSizeF base = VerticalAxis::sizeHint(which, constraint);
+ const QStringList &ticksList = createColorLabels(min(), max(), m_axis->tickCount());
+ qreal width = 0;
+ // Height of vertical axis sizeHint indicates the maximum distance labels can extend past
+ // first and last ticks. Base height is irrelevant.
+ qreal height = 0;
+
+ switch (which) {
+ case Qt::MinimumSize: {
+ QRectF boundingRect = ChartPresenter::textBoundingRect(axis()->labelsFont(),
+ QStringLiteral("..."),
+ axis()->labelsAngle());
+ width = boundingRect.width() + labelPadding() + base.width() + m_axis->size()
+ + colorScalePadding() + 1.0;
+ height = boundingRect.height() / 2.0;
+ sh = QSizeF(width, height);
+ break;
+ }
+ case Qt::PreferredSize: {
+ qreal labelWidth = 0.0;
+ qreal firstHeight = -1.0;
+ for (const QString &s : ticksList) {
+ QRectF rect = ChartPresenter::textBoundingRect(axis()->labelsFont(), s,
+ axis()->labelsAngle());
+ labelWidth = qMax(rect.width(), labelWidth);
+ height = rect.height();
+ if (firstHeight < 0.0)
+ firstHeight = height;
+ }
+ width = labelWidth + labelPadding() + base.width() + m_axis->size() + colorScalePadding()
+ + 2.0; // two pixels of tolerance
+ height = qMax(height, firstHeight) / 2.0;
+ sh = QSizeF(width, height);
+ break;
+ }
+ default:
+ break;
+ }
+
+ return sh;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_chartcoloraxisy_p.cpp"
diff --git a/src/charts/axis/coloraxis/chartcoloraxisy_p.h b/src/charts/axis/coloraxis/chartcoloraxisy_p.h
new file mode 100644
index 00000000..a253b7ed
--- /dev/null
+++ b/src/charts/axis/coloraxis/chartcoloraxisy_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CHARTCOLORAXISY_H
+#define CHARTCOLORAXISY_H
+
+#include <private/verticalaxis_p.h>
+#include <QtCharts/private/qchartglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QColorAxis;
+
+class Q_CHARTS_PRIVATE_EXPORT ChartColorAxisY : public VerticalAxis
+{
+ Q_OBJECT
+public:
+ ChartColorAxisY(QColorAxis *axis, QGraphicsItem* item = 0);
+ ~ChartColorAxisY();
+
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const override;
+
+protected:
+ QList<qreal> calculateLayout() const override;
+ void updateGeometry() override;
+
+private:
+ QColorAxis *m_axis;
+};
+
+QT_END_NAMESPACE
+
+#endif // CHARTCOLORAXISY_H
diff --git a/src/charts/axis/coloraxis/qcoloraxis.cpp b/src/charts/axis/coloraxis/qcoloraxis.cpp
new file mode 100644
index 00000000..27e0a8fa
--- /dev/null
+++ b/src/charts/axis/coloraxis/qcoloraxis.cpp
@@ -0,0 +1,399 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCharts/QColorAxis>
+#include <QtCharts/QXYSeries>
+#include <private/abstractdomain_p.h>
+#include <private/qcoloraxis_p.h>
+#include <private/qxyseries_p.h>
+#include <private/chartcoloraxisx_p.h>
+#include <private/chartcoloraxisy_p.h>
+#include <private/chartvalueaxisy_p.h>
+#include <private/charthelpers_p.h>
+
+#include <QtCharts/QChart>
+
+QT_BEGIN_NAMESPACE
+/*!
+ \class QColorAxis
+ \inmodule QtCharts
+ \brief The QColorAxis class displays a color scale as one of the chart's axes.
+ \since 6.2
+
+ A color axis can be set up to show a color scale based on the passed gradient.
+ The scale has tick marks with labels based on data passed in QXYSeries::colorby method.
+*/
+
+/*!
+ \property QColorAxis::min
+ \brief The minimum value on the axis.
+
+ When setting this property, the maximum value is adjusted if necessary, to ensure that
+ the range remains valid.
+*/
+
+/*!
+ \property QColorAxis::max
+ \brief The maximum value on the axis.
+
+ When setting this property, the minimum value is adjusted if necessary, to ensure that
+ the range remains valid.
+*/
+
+/*!
+ \property QColorAxis::tickCount
+ \brief The number of tick marks on the axis. This indicates how many grid lines are drawn on the
+ chart if QColorAxis::gridVisible is equal to \c true. The default value is 5, and the number
+ cannot be less than 2.
+
+ \note Grid lines are intentionally invisible by default in QColorAxis as this type of axis
+ does not represent geometric values.
+*/
+
+/*!
+ \property QColorAxis::size
+ \brief The size of the color scale.
+
+ Depending on the alignment the value indicates either width or height.
+*/
+
+/*!
+ \property QColorAxis::autoRange
+ \brief The property indicating if the range should be set from the list of values
+ passed in QXYSeries::colorBy method or rather taken from the axis itself.
+
+ The default value is \c true.
+*/
+
+/*!
+ \fn void QColorAxis::minChanged(qreal min)
+ This signal is emitted when the minimum value of the axis, specified by \a min, changes.
+*/
+
+/*!
+ \fn void QColorAxis::maxChanged(qreal max)
+ This signal is emitted when the maximum value of the axis, specified by \a max, changes.
+*/
+
+/*!
+ \fn void QColorAxis::tickCountChanged(int tickCount)
+ This signal is emitted when the number of tick marks on the axis, specified by \a tickCount,
+ changes.
+*/
+
+/*!
+ \fn void QColorAxis::sizeChanged(qreal size)
+ This signal is emitted when the size of the color scale, specified by \a size, changes.
+*/
+
+/*!
+ \fn void QColorAxis::autoRangeChanged(bool autoRange)
+ This signal is emitted when the auto range mode, specified by \a autoRange, changes.
+*/
+
+/*!
+ \fn void QColorAxis::rangeChanged(qreal min, qreal max)
+ This signal is emitted when the minimum or maximum value of the axis, specified by \a min
+ and \a max, changes.
+*/
+
+QColorAxis::QColorAxis(QObject *parent)
+ : QAbstractAxis(*new QColorAxisPrivate(this), parent)
+{
+ setGridLineVisible(false);
+ QPen linePen = QPen(Qt::black);
+ linePen.setWidthF(2.0);
+ setLinePen(linePen);
+}
+
+/*!
+ \internal
+*/
+QColorAxis::QColorAxis(QColorAxisPrivate &d, QObject *parent)
+ : QAbstractAxis(d, parent)
+{
+
+}
+
+/*!
+ Destroys the object.
+*/
+QColorAxis::~QColorAxis()
+{
+ Q_D(QColorAxis);
+ if (d->m_chart)
+ d->m_chart->removeAxis(this);
+}
+
+QAbstractAxis::AxisType QColorAxis::type() const
+{
+ return QAbstractAxis::AxisTypeColor;
+}
+
+void QColorAxis::setMin(qreal min)
+{
+ Q_D(QColorAxis);
+ setRange(min, qMax(d->m_max, min));
+}
+
+qreal QColorAxis::min() const
+{
+ Q_D(const QColorAxis);
+ return d->m_min;
+}
+
+void QColorAxis::setMax(qreal max)
+{
+ Q_D(QColorAxis);
+ setRange(qMin(d->m_min, max), max);
+}
+
+qreal QColorAxis::max() const
+{
+ Q_D(const QColorAxis);
+ return d->m_max;
+}
+
+void QColorAxis::setRange(qreal min, qreal max)
+{
+ Q_D(QColorAxis);
+ d->setRange(min, max);
+}
+
+void QColorAxis::setTickCount(int count)
+{
+ Q_D(QColorAxis);
+ if (d->m_tickCount != count && count >= 2) {
+ d->m_tickCount = count;
+ emit tickCountChanged(count);
+ }
+}
+
+int QColorAxis::tickCount() const
+{
+ Q_D(const QColorAxis);
+ return d->m_tickCount;
+}
+
+void QColorAxis::setSize(const qreal size)
+{
+ Q_D(QColorAxis);
+ if (d->m_size != size) {
+ d->m_size = size;
+ emit sizeChanged(size);
+ }
+}
+
+qreal QColorAxis::size() const
+{
+ Q_D(const QColorAxis);
+ return d->m_size;
+}
+
+/*!
+ Sets the gradient on the color scale to \a gradient.
+
+ \note If the axis is attached to a series, the gradient is also used
+ by the QXYSeries::colorBy method.
+ \sa gradient
+*/
+void QColorAxis::setGradient(const QLinearGradient &gradient)
+{
+ Q_D(QColorAxis);
+ if (d->m_gradient != gradient) {
+ d->m_gradient = gradient;
+ emit gradientChanged(gradient);
+ }
+}
+
+/*!
+ Returns the gradient currently used on the color scale.
+
+ \note If the axis is attached to a series, the gradient is also used
+ by the QXYSeries::colorBy method.
+ \sa setGradient
+*/
+QLinearGradient QColorAxis::gradient() const
+{
+ Q_D(const QColorAxis);
+ return d->m_gradient;
+}
+
+void QColorAxis::setAutoRange(bool autoRange)
+{
+ Q_D(QColorAxis);
+ if (d->m_autoRange != autoRange) {
+ d->m_autoRange = autoRange;
+ emit autoRangeChanged(d->m_autoRange);
+ }
+}
+
+bool QColorAxis::autoRange() const
+{
+ Q_D(const QColorAxis);
+ return d->m_autoRange;
+}
+
+QColorAxisPrivate::QColorAxisPrivate(QColorAxis *q)
+ : QAbstractAxisPrivate(q)
+ , m_min(0)
+ , m_max(1)
+ , m_tickCount(5)
+ , m_size(15)
+ , m_autoRange(true)
+{
+ m_gradient = QLinearGradient(QPointF(0, 0), QPointF(0, 100));
+ m_gradient.setColorAt(0, Qt::white);
+ m_gradient.setColorAt(1, Qt::black);
+}
+
+QColorAxisPrivate::~QColorAxisPrivate()
+{
+
+}
+
+void QColorAxisPrivate::initializeGraphics(QGraphicsItem *parent)
+{
+ Q_Q(QColorAxis);
+ ChartAxisElement *axis(0);
+ if (m_chart->chartType() == QChart::ChartTypeCartesian) {
+ if (orientation() == Qt::Vertical)
+ axis = new ChartColorAxisY(q, parent);
+ else if (orientation() == Qt::Horizontal)
+ axis = new ChartColorAxisX(q, parent);
+ }
+
+ if (m_chart->chartType() == QChart::ChartTypePolar)
+ qWarning() << "Polar chart is not supported by color axis.";
+
+ m_item.reset(axis);
+ QAbstractAxisPrivate::initializeGraphics(parent);
+}
+
+void QColorAxisPrivate::initializeDomain(AbstractDomain *domain)
+{
+ Q_UNUSED(domain);
+ if (orientation() == Qt::Vertical) {
+ if (m_autoRange)
+ updateSeries();
+ else
+ setRange(m_min, m_max);
+ }
+
+ if (orientation() == Qt::Horizontal) {
+ if (m_autoRange)
+ updateSeries();
+ else
+ setRange(m_min, m_max);
+ }
+}
+
+void QColorAxisPrivate::setRange(qreal min, qreal max)
+{
+ Q_Q(QColorAxis);
+ bool changed = false;
+
+ if (min > max)
+ return;
+
+ if (!isValidValue(min, max)) {
+ qWarning() << "Attempting to set invalid range for value axis: ["
+ << min << " - " << max << "]";
+ return;
+ }
+
+ if (m_min != min) {
+ m_min = min;
+ changed = true;
+ emit q->minChanged(min);
+ }
+
+ if (m_max != max) {
+ m_max = max;
+ changed = true;
+ emit q->maxChanged(max);
+ }
+
+ if (changed) {
+ emit rangeChanged(min,max);
+ emit q->rangeChanged(min, max);
+
+ if (!m_autoRange)
+ updateSeries();
+ }
+}
+
+void QColorAxisPrivate::updateSeries()
+{
+ const QList<QAbstractSeries *> series = m_series;
+ for (const auto &serie : series) {
+ if (serie->type() == QAbstractSeries::SeriesTypeLine
+ || serie->type() == QAbstractSeries::SeriesTypeSpline
+ || serie->type() == QAbstractSeries::SeriesTypeScatter) {
+ QXYSeries *xySeries = static_cast<QXYSeries *>(serie);
+ const auto &colorByData = xySeries->d_func()->colorByData();
+ if (!colorByData.isEmpty())
+ xySeries->colorBy(colorByData);
+ }
+ }
+}
+
+void QColorAxisPrivate::setMin(const QVariant &min)
+{
+ Q_Q(QColorAxis);
+ bool ok;
+ qreal value = min.toReal(&ok);
+ if (ok)
+ q->setMin(value);
+}
+
+void QColorAxisPrivate::setMax(const QVariant &max)
+{
+ Q_Q(QColorAxis);
+ bool ok;
+ qreal value = max.toReal(&ok);
+ if (ok)
+ q->setMax(value);
+}
+
+void QColorAxisPrivate::setRange(const QVariant &min, const QVariant &max)
+{
+ Q_Q(QColorAxis);
+ bool ok1;
+ bool ok2;
+ qreal value1 = min.toReal(&ok1);
+ qreal value2 = max.toReal(&ok2);
+ if (ok1 && ok2)
+ q->setRange(value1, value2);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qcoloraxis.cpp"
+#include "moc_qcoloraxis_p.cpp"
diff --git a/src/charts/axis/coloraxis/qcoloraxis.h b/src/charts/axis/coloraxis/qcoloraxis.h
new file mode 100644
index 00000000..78f50f2e
--- /dev/null
+++ b/src/charts/axis/coloraxis/qcoloraxis.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOLORAXIS_H
+#define QCOLORAXIS_H
+
+#include <QtCharts/QAbstractAxis>
+
+QT_BEGIN_NAMESPACE
+
+class QColorAxisPrivate;
+
+class Q_CHARTS_EXPORT QColorAxis : public QAbstractAxis
+{
+ Q_OBJECT
+ Q_PROPERTY(int tickCount READ tickCount WRITE setTickCount NOTIFY tickCountChanged)
+ Q_PROPERTY(qreal min READ min WRITE setMin NOTIFY minChanged)
+ Q_PROPERTY(qreal max READ max WRITE setMax NOTIFY maxChanged)
+ Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY sizeChanged)
+ Q_PROPERTY(bool autoRange READ autoRange WRITE setAutoRange NOTIFY autoRangeChanged)
+
+public:
+ explicit QColorAxis(QObject *parent = nullptr);
+ ~QColorAxis();
+
+ AxisType type() const override;
+
+ void setMin(qreal min);
+ qreal min() const;
+ void setMax(qreal max);
+ qreal max() const;
+ void setRange(qreal min, qreal max);
+
+ void setTickCount(int count);
+ int tickCount() const;
+
+ void setSize(const qreal size);
+ qreal size() const;
+
+ void setGradient(const QLinearGradient &gradient);
+ QLinearGradient gradient() const;
+
+ void setAutoRange(bool autoRange);
+ bool autoRange() const;
+
+Q_SIGNALS:
+ void minChanged(qreal min);
+ void maxChanged(qreal max);
+ void rangeChanged(qreal min, qreal max);
+ void tickCountChanged(int tickCount);
+ void gradientChanged(const QLinearGradient &gradient);
+ void sizeChanged(const qreal size);
+ void autoRangeChanged(bool autoRange);
+
+protected:
+ explicit QColorAxis(QColorAxisPrivate &d, QObject *parent = nullptr);
+
+private:
+ Q_DECLARE_PRIVATE(QColorAxis)
+ Q_DISABLE_COPY(QColorAxis)
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOLORAXIS_H
diff --git a/src/charts/axis/coloraxis/qcoloraxis_p.h b/src/charts/axis/coloraxis/qcoloraxis_p.h
new file mode 100644
index 00000000..e8da70bd
--- /dev/null
+++ b/src/charts/axis/coloraxis/qcoloraxis_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the Qt Charts module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef QCOLORAXIS_P_H
+#define QCOLORAXIS_P_H
+
+#include <QtCharts/QColorAxis>
+#include <private/qabstractaxis_p.h>
+#include <QtCharts/private/qchartglobal_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_CHARTS_PRIVATE_EXPORT QColorAxisPrivate : public QAbstractAxisPrivate
+{
+ Q_OBJECT
+public:
+ explicit QColorAxisPrivate(QColorAxis *q);
+ ~QColorAxisPrivate();
+
+ void initializeGraphics(QGraphicsItem *parent) override;
+ void initializeDomain(AbstractDomain *domain) override;
+
+ qreal min() override { return m_min; }
+ qreal max() override { return m_max; }
+ void setRange(qreal min,qreal max) override;
+
+ void updateSeries();
+
+protected:
+ void setMin(const QVariant &min) override;
+ void setMax(const QVariant &max) override;
+ void setRange(const QVariant &min, const QVariant &max) override;
+
+private:
+ qreal m_min;
+ qreal m_max;
+ int m_tickCount;
+ qreal m_size;
+ bool m_autoRange;
+ QLinearGradient m_gradient;
+ Q_DECLARE_PUBLIC(QColorAxis)
+};
+
+QT_END_NAMESPACE
+
+#endif // QCOLORAXIS_P_H
diff --git a/src/charts/axis/horizontalaxis.cpp b/src/charts/axis/horizontalaxis.cpp
index 8d7b0ec6..ac7d65dd 100644
--- a/src/charts/axis/horizontalaxis.cpp
+++ b/src/charts/axis/horizontalaxis.cpp
@@ -29,6 +29,7 @@
#include <QtCharts/qcategoryaxis.h>
#include <QtCharts/qlogvalueaxis.h>
+#include <QtCharts/qcoloraxis.h>
#include <QtCore/qmath.h>
#include <private/chartpresenter_p.h>
#include <private/horizontalaxis_p.h>
@@ -69,7 +70,6 @@ QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) co
default:
break;
}
-
return sh;
}
@@ -98,10 +98,13 @@ void HorizontalAxis::updateGeometry()
//arrow
QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
- if (axis()->alignment() == Qt::AlignTop)
- arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
- else if (axis()->alignment() == Qt::AlignBottom)
- arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
+ if (axis()->type() != QAbstractAxis::AxisTypeColor) {
+ if (axis()->alignment() == Qt::AlignTop)
+ arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(),
+ axisRect.bottom());
+ else if (axis()->alignment() == Qt::AlignBottom)
+ arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
+ }
const QLatin1String ellipsis("...");
@@ -114,6 +117,11 @@ void HorizontalAxis::updateGeometry()
qreal minimumLabelHeight = ChartPresenter::textBoundingRect(axis()->labelsFont(),
QStringLiteral("...")).height();
qreal titleSpace = availableSpace - minimumLabelHeight;
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ titleSpace -= colorAxis->size() + colorScalePadding();
+ }
+
title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(0.0),
gridRect.width(), titleSpace,
titleBoundingRect));
@@ -128,6 +136,10 @@ void HorizontalAxis::updateGeometry()
title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePadding());
availableSpace -= titleBoundingRect.height();
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ availableSpace -= colorAxis->size() + colorScalePadding();
+ }
}
QList<QGraphicsItem *> lines = gridItems();
@@ -194,40 +206,68 @@ void HorizontalAxis::updateGeometry()
//ticks and label position
QPointF labelPos;
if (axis()->alignment() == Qt::AlignTop) {
+ qreal tickStopY = axisRect.bottom();
+
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ QGraphicsPixmapItem *colorScale = colorScaleItem();
+
+ const qreal penWidth = axis()->linePen().widthF();
+ // penWidth / 2 is half of tick width
+ colorScale->setOffset(gridRect.left() - penWidth / 2,
+ axisRect.bottom() - colorScalePadding() - colorAxis->size());
+ prepareColorScale(gridRect.width() + penWidth + 1, colorAxis->size());
+
+ tickStopY = axisRect.bottom() - colorScalePadding() - colorAxis->size();
+ }
+
if (axis()->isReverse()) {
labelPos = QPointF(gridRect.right() - layout[layout.size() - i - 1]
- + gridRect.left() - center.x(),
- axisRect.bottom() - rect.height()
- + (heightDiff / 2.0) - labelPadding());
- tickItem->setLine(gridRect.right() + gridRect.left() - layout[i],
- axisRect.bottom(),
+ + gridRect.left() - center.x(),
+ tickStopY - rect.height() + (heightDiff / 2.0) - labelPadding());
+ tickItem->setLine(gridRect.right() + gridRect.left() - layout[i], tickStopY,
gridRect.right() + gridRect.left() - layout[i],
- axisRect.bottom() - labelPadding());
+ tickStopY - labelPadding());
} else {
- labelPos = QPointF(layout[i] - center.x(), axisRect.bottom() - rect.height()
- + (heightDiff / 2.0) - labelPadding());
- tickItem->setLine(layout[i], axisRect.bottom(),
- layout[i], axisRect.bottom() - labelPadding());
+ labelPos = QPointF(layout[i] - center.x(),
+ tickStopY - rect.height() + (heightDiff / 2.0) - labelPadding());
+ tickItem->setLine(layout[i], tickStopY, layout[i], tickStopY - labelPadding());
}
} else if (axis()->alignment() == Qt::AlignBottom) {
+
+ qreal tickStartY = axisRect.top();
+
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ QGraphicsPixmapItem *colorScale = colorScaleItem();
+
+ const qreal penWidth = axis()->linePen().widthF();
+ // penWidth / 2 is half of tick width
+ colorScale->setOffset(gridRect.left() - penWidth / 2,
+ axisRect.top() + colorScalePadding());
+ prepareColorScale(gridRect.width() + penWidth + 1, colorAxis->size());
+
+ tickStartY = axisRect.top() + colorScalePadding() + colorAxis->size();
+ }
+
if (axis()->isReverse()) {
labelPos = QPointF(gridRect.right() - layout[layout.size() - i - 1]
- + gridRect.left() - center.x(),
- axisRect.top() - (heightDiff / 2.0) + labelPadding());
- tickItem->setLine(gridRect.right() + gridRect.left() - layout[i], axisRect.top(),
+ + gridRect.left() - center.x(),
+ tickStartY - (heightDiff / 2.0) + labelPadding());
+ tickItem->setLine(gridRect.right() + gridRect.left() - layout[i], tickStartY,
gridRect.right() + gridRect.left() - layout[i],
- axisRect.top() + labelPadding());
+ tickStartY + labelPadding());
} else {
- labelPos = QPointF(layout[i] - center.x(), axisRect.top() - (heightDiff / 2.0)
- + labelPadding());
- tickItem->setLine(layout[i], axisRect.top(),
- layout[i], axisRect.top() + labelPadding());
+ labelPos = QPointF(layout[i] - center.x(),
+ tickStartY - (heightDiff / 2.0) + labelPadding());
+ tickItem->setLine(layout[i], tickStartY, layout[i], tickStartY + labelPadding());
}
}
//label in between
bool forceHide = false;
- if (intervalAxis() && (i + 1) != layout.size()) {
+ if (intervalAxis() && (i + 1) != layout.size()
+ && axis()->type() != QAbstractAxis::AxisTypeColor) {
qreal leftBound;
qreal rightBound;
if (axis()->isReverse()) {
@@ -269,12 +309,14 @@ void HorizontalAxis::updateGeometry()
// Round to full pixel via QPoint to avoid one pixel clipping on the edge in some cases
labelItem->setPos(labelPos.toPoint());
- //label overlap detection - compensate one pixel for rounding errors
+ // Label overlap detection - compensate one pixel for rounding errors.
+ // This is not needed for color axis as its labels don't collide with other labels
if ((labelItem->pos().x() < last_label_max_x && labelItem->toPlainText() == ellipsis)
|| forceHide
|| (labelItem->pos().x() + (widthDiff / 2.0)) < (axisRect.left() - 1.0)
|| (labelItem->pos().x() + (widthDiff / 2.0) - 1.0) > axisRect.right()) {
- labelItem->setVisible(false);
+ if (axis()->type() != QAbstractAxis::AxisTypeColor)
+ labelItem->setVisible(false);
} else {
labelItem->setVisible(true);
last_label_max_x = boundingRect.width() + labelItem->pos().x();
diff --git a/src/charts/axis/qabstractaxis.cpp b/src/charts/axis/qabstractaxis.cpp
index 3fea583b..6def930b 100644
--- a/src/charts/axis/qabstractaxis.cpp
+++ b/src/charts/axis/qabstractaxis.cpp
@@ -71,6 +71,7 @@ QT_BEGIN_NAMESPACE
\value AxisTypeCategory
\value AxisTypeDateTime
\value AxisTypeLogValue
+ \value AxisTypeColor
*/
/*!
diff --git a/src/charts/axis/qabstractaxis.h b/src/charts/axis/qabstractaxis.h
index 3f265e03..8972320e 100644
--- a/src/charts/axis/qabstractaxis.h
+++ b/src/charts/axis/qabstractaxis.h
@@ -88,7 +88,8 @@ public:
AxisTypeBarCategory = 0x2,
AxisTypeCategory = 0x4,
AxisTypeDateTime = 0x8,
- AxisTypeLogValue = 0x10
+ AxisTypeLogValue = 0x10,
+ AxisTypeColor = 0x12
};
Q_DECLARE_FLAGS(AxisTypes, AxisType)
diff --git a/src/charts/axis/qabstractaxis_p.h b/src/charts/axis/qabstractaxis_p.h
index 6b7da004..1249602e 100644
--- a/src/charts/axis/qabstractaxis_p.h
+++ b/src/charts/axis/qabstractaxis_p.h
@@ -141,6 +141,8 @@ private:
bool m_reverse = false;
Q_DECLARE_PUBLIC(QAbstractAxis);
+ friend class QAbstractAxis;
+ friend class QColorAxisPrivate;
friend class ChartDataSet;
friend class ChartPresenter;
};
diff --git a/src/charts/axis/verticalaxis.cpp b/src/charts/axis/verticalaxis.cpp
index 503213c8..627b3654 100644
--- a/src/charts/axis/verticalaxis.cpp
+++ b/src/charts/axis/verticalaxis.cpp
@@ -28,6 +28,7 @@
****************************************************************************/
#include <QtCharts/qcategoryaxis.h>
+#include <QtCharts/QColorAxis>
#include <QtCharts/qlogvalueaxis.h>
#include <QtCore/qmath.h>
#include <private/chartpresenter_p.h>
@@ -69,7 +70,6 @@ QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) cons
default:
break;
}
-
return sh;
}
@@ -101,10 +101,12 @@ void VerticalAxis::updateGeometry()
QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
//arrow position
- if (axis()->alignment() == Qt::AlignLeft)
- arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
- else if (axis()->alignment() == Qt::AlignRight)
- arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
+ if (axis()->type() != QAbstractAxis::AxisTypeColor) {
+ if (axis()->alignment() == Qt::AlignLeft)
+ arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
+ else if (axis()->alignment() == Qt::AlignRight)
+ arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
+ }
//title
QRectF titleBoundingRect;
@@ -112,13 +114,20 @@ void VerticalAxis::updateGeometry()
qreal labelAvailableSpace = axisRect.width();
if (!titleText.isEmpty() && titleItem()->isVisible()) {
const qreal titleAvailableSpace =
- axisRect.height() - labelPadding() - (titlePadding() * 2.0);
+ axisRect.width() - labelPadding() - (titlePadding() * 2.0);
qreal minimumLabelWidth = ChartPresenter::textBoundingRect(axis()->labelsFont(),
QStringLiteral("...")).width();
qreal titleSpace = titleAvailableSpace - minimumLabelWidth;
+
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ titleSpace -= colorAxis->size() + colorScalePadding();
+ }
+
title->setHtml(ChartPresenter::truncatedText(axis()->titleFont(), titleText, qreal(90.0),
titleSpace, gridRect.height(),
titleBoundingRect));
+
title->setTextWidth(titleBoundingRect.height());
titleBoundingRect = title->boundingRect();
@@ -135,6 +144,11 @@ void VerticalAxis::updateGeometry()
title->setTransformOriginPoint(titleBoundingRect.center());
title->setRotation(270);
labelAvailableSpace -= titleBoundingRect.height();
+
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ labelAvailableSpace -= colorAxis->size() + colorScalePadding();
+ }
}
QList<QGraphicsItem *> lines = gridItems();
@@ -198,43 +212,70 @@ void VerticalAxis::updateGeometry()
//ticks and label position
QPointF labelPos;
if (axis()->alignment() == Qt::AlignLeft) {
+
+ qreal tickStopX = axisRect.right();
+
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ QGraphicsPixmapItem *colorScale = colorScaleItem();
+
+ const qreal penWidth = axis()->linePen().widthF();
+ // penWidth / 2 is half of tick width
+ colorScale->setOffset(axisRect.right() - colorAxis->size() - colorScalePadding(),
+ layout[i] - penWidth / 2);
+ prepareColorScale(colorAxis->size(), gridRect.height() + penWidth);
+
+ tickStopX = axisRect.right() - colorAxis->size() - colorScalePadding();
+ }
+
if (axis()->isReverse()) {
- labelPos = QPointF(axisRect.right() - rect.width() + (widthDiff / 2.0)
- - labelPadding(),
- gridRect.top() + gridRect.bottom()
- - layout[layout.size() - i - 1] - center.y());
- tickItem->setLine(axisRect.right() - labelPadding(),
- gridRect.top() + gridRect.bottom() - layout[i],
- axisRect.right(),
+ labelPos = QPointF(tickStopX - rect.width() + (widthDiff / 2.0) - labelPadding(),
+ gridRect.top() + gridRect.bottom()
+ - layout[layout.size() - i - 1] - center.y());
+ tickItem->setLine(tickStopX - labelPadding(),
+ gridRect.top() + gridRect.bottom() - layout[i], tickStopX,
gridRect.top() + gridRect.bottom() - layout[i]);
} else {
- labelPos = QPointF(axisRect.right() - rect.width() + (widthDiff / 2.0)
- - labelPadding(),
- layout[i] - center.y());
- tickItem->setLine(axisRect.right() - labelPadding(), layout[i],
- axisRect.right(), layout[i]);
+ labelPos = QPointF(tickStopX - rect.width() + (widthDiff / 2.0) - labelPadding(),
+ layout[i] - center.y());
+ tickItem->setLine(tickStopX - labelPadding(), layout[i], tickStopX, layout[i]);
}
} else if (axis()->alignment() == Qt::AlignRight) {
+ qreal tickStartX = axisRect.left();
+
+ if (axis()->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis());
+ QGraphicsPixmapItem *colorScale = colorScaleItem();
+
+ const qreal penWidth = axis()->linePen().widthF();
+ // penWidth / 2 is half of tick width
+ colorScale->setOffset(axisRect.x() + colorScalePadding(), layout[i] - penWidth / 2);
+ prepareColorScale(colorAxis->size(), gridRect.height() + penWidth);
+
+ tickStartX = axisRect.x() + colorScalePadding() + colorAxis->size();
+ }
+
+
if (axis()->isReverse()) {
- tickItem->setLine(axisRect.left(),
- gridRect.top() + gridRect.bottom() - layout[i],
- axisRect.left() + labelPadding(),
+ tickItem->setLine(tickStartX, gridRect.top() + gridRect.bottom() - layout[i],
+ tickStartX + labelPadding(),
gridRect.top() + gridRect.bottom() - layout[i]);
- labelPos = QPointF(axisRect.left() + labelPadding() - (widthDiff / 2.0),
- gridRect.top() + gridRect.bottom()
- - layout[layout.size() - i - 1] - center.y());
+ labelPos = QPointF(tickStartX + labelPadding() - (widthDiff / 2.0),
+ gridRect.top() + gridRect.bottom()
+ - layout[layout.size() - i - 1] - center.y());
} else {
- labelPos = QPointF(axisRect.left() + labelPadding() - (widthDiff / 2.0),
- layout[i] - center.y());
- tickItem->setLine(axisRect.left(), layout[i],
- axisRect.left() + labelPadding(), layout[i]);
+
+ labelPos = QPointF(tickStartX + labelPadding() - (widthDiff / 2.0),
+ layout[i] - center.y());
+ tickItem->setLine(tickStartX, layout[i], tickStartX + labelPadding(), layout[i]);
}
}
//label in between
bool forceHide = false;
bool labelOnValue = false;
- if (intervalAxis() && (i + 1) != layout.size()) {
+ if (intervalAxis() && (i + 1) != layout.size()
+ && axis()->type() != QAbstractAxis::AxisTypeColor) {
qreal lowerBound;
qreal upperBound;
if (axis()->isReverse()) {
diff --git a/src/charts/chartdataset.cpp b/src/charts/chartdataset.cpp
index 1a1ba243..385e2a2d 100644
--- a/src/charts/chartdataset.cpp
+++ b/src/charts/chartdataset.cpp
@@ -35,6 +35,7 @@
#include <QtCharts/QBarCategoryAxis>
#include <private/qvalueaxis_p.h>
#include <QtCharts/QCategoryAxis>
+#include <QtCharts/QColorAxis>
#include <private/qabstractseries_p.h>
#include <QtCharts/QAbstractBarSeries>
#include <QtCharts/QStackedBarSeries>
@@ -365,6 +366,9 @@ void ChartDataSet::createAxes(QAbstractAxis::AxisTypes type, Qt::Orientation ori
case QAbstractAxis::AxisTypeCategory:
axis = new QCategoryAxis(this);
break;
+ case QAbstractAxis::AxisTypeColor:
+ axis = new QColorAxis(this);
+ break;
#if QT_CONFIG(charts_datetime_axis)
case QAbstractAxis::AxisTypeDateTime:
axis = new QDateTimeAxis(this);
@@ -575,6 +579,7 @@ AbstractDomain::DomainType ChartDataSet::selectDomain(const QList<QAbstractAxis
case QAbstractAxis::AxisTypeValue:
case QAbstractAxis::AxisTypeBarCategory:
case QAbstractAxis::AxisTypeCategory:
+ case QAbstractAxis::AxisTypeColor:
case QAbstractAxis::AxisTypeDateTime:
if (axis->orientation() == Qt::Horizontal)
horizontal |= ValueType;
diff --git a/src/charts/domain/abstractdomain.cpp b/src/charts/domain/abstractdomain.cpp
index 48014aa2..263c72a4 100644
--- a/src/charts/domain/abstractdomain.cpp
+++ b/src/charts/domain/abstractdomain.cpp
@@ -210,16 +210,26 @@ qreal AbstractDomain::niceNumber(qreal x, bool ceiling)
bool AbstractDomain::attachAxis(QAbstractAxis *axis)
{
if (axis->orientation() == Qt::Vertical) {
- QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleVerticalAxisRangeChanged(qreal,qreal)));
- QObject::connect(this, SIGNAL(rangeVerticalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal)));
+ // Color axis isn't connected to range-related slots/signals as it doesn't need
+ // geometry domain and it doesn't need to handle zooming or scrolling.
+ if (axis->type() != QAbstractAxis::AxisTypeColor) {
+ QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this,
+ SLOT(handleVerticalAxisRangeChanged(qreal, qreal)));
+ QObject::connect(this, SIGNAL(rangeVerticalChanged(qreal, qreal)), axis->d_ptr.data(),
+ SLOT(handleRangeChanged(qreal, qreal)));
+ }
QObject::connect(axis, &QAbstractAxis::reverseChanged,
this, &AbstractDomain::handleReverseYChanged);
m_reverseY = axis->isReverse();
}
if (axis->orientation() == Qt::Horizontal) {
- QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleHorizontalAxisRangeChanged(qreal,qreal)));
- QObject::connect(this, SIGNAL(rangeHorizontalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal)));
+ if (axis->type() != QAbstractAxis::AxisTypeColor) {
+ QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this,
+ SLOT(handleHorizontalAxisRangeChanged(qreal, qreal)));
+ QObject::connect(this, SIGNAL(rangeHorizontalChanged(qreal, qreal)), axis->d_ptr.data(),
+ SLOT(handleRangeChanged(qreal, qreal)));
+ }
QObject::connect(axis, &QAbstractAxis::reverseChanged,
this, &AbstractDomain::handleReverseXChanged);
m_reverseX = axis->isReverse();
diff --git a/src/charts/xychart/qxyseries.cpp b/src/charts/xychart/qxyseries.cpp
index a6b722b3..baadf2eb 100644
--- a/src/charts/xychart/qxyseries.cpp
+++ b/src/charts/xychart/qxyseries.cpp
@@ -28,6 +28,7 @@
****************************************************************************/
#include <QtCharts/QXYSeries>
+#include <QtCharts/QColorAxis>
#include <private/qxyseries_p.h>
#include <private/abstractdomain_p.h>
#include <QtCharts/QValueAxis>
@@ -36,6 +37,7 @@
#include <private/charthelpers_p.h>
#include <private/qchart_p.h>
#include <QtGui/QPainter>
+#include <QtMath>
QT_BEGIN_NAMESPACE
@@ -958,6 +960,82 @@ void QXYSeries::sizeBy(const QList<qreal> &sourceData, const qreal minSize, cons
}
/*!
+ Sets the points' color according to a passed list of values. Values from
+ \a sourceData are sorted and mapped to the \a gradient.
+
+ If the series has a QColorAxis attached, then a gradient from the axis
+ is going to be used.
+
+ \sa setPointConfiguration(), pointConfiguration(), QColorAxis
+ \since 6.2
+*/
+void QXYSeries::colorBy(const QList<qreal> &sourceData, const QLinearGradient &gradient)
+{
+ Q_D(QXYSeries);
+
+ d->m_colorByData = sourceData;
+ if (d->m_colorByData.isEmpty())
+ return;
+
+ const qreal imgSize = 100.0;
+
+ qreal min = std::numeric_limits<qreal>::max();
+ qreal max = std::numeric_limits<qreal>::min();
+ for (const auto &p : sourceData) {
+ min = qMin(min, p);
+ max = qMax(max, p);
+ }
+
+ qreal range = max - min;
+
+ QLinearGradient usedGradient = gradient;
+
+ // Gradient will be taked from the first attached color axis.
+ // If there are more color axis, they will have just changed range.
+ bool axisFound = false;
+ const auto axes = attachedAxes();
+ for (const auto &axis : axes) {
+ if (axis->type() == QAbstractAxis::AxisTypeColor) {
+ QColorAxis *colorAxis = static_cast<QColorAxis *>(axis);
+ if (!axisFound) {
+ usedGradient = QLinearGradient(QPointF(0,0), QPointF(0, imgSize));
+ const auto stops = colorAxis->gradient().stops();
+ for (const auto &stop : stops)
+ usedGradient.setColorAt(stop.first, stop.second);
+
+ if (!colorAxis->autoRange()) {
+ min = colorAxis->min();
+ max = colorAxis->max();
+ range = max - min;
+ }
+
+ axisFound = true;
+ }
+
+ if (colorAxis->autoRange())
+ colorAxis->setRange(min, max);
+ }
+ }
+
+ QImage image(imgSize, imgSize, QImage::Format_ARGB32);
+ QPainter painter(&image);
+ painter.fillRect(image.rect(), usedGradient);
+
+ // To ensure that negative values will be well handled, distance from min to 0
+ // will be added to min and every single value. This will move entire values
+ // list to positive only values.
+ const qreal diff = min < 0 ? qAbs(min) : 0;
+ min += diff;
+
+ for (int i = 0; i < sourceData.size() && i < d->m_points.size(); ++i) {
+ const qreal startValue = qMax(0.0, sourceData.at(i) + diff - min);
+ const qreal percentage = startValue / range;
+ QColor color = image.pixelColor(0, qMin(percentage * imgSize, imgSize - 1));
+ setPointConfiguration(i, QXYSeries::PointConfiguration::Color, color);
+ }
+}
+
+/*!
Returns true if point at given \a index is among selected points and false otherwise.
\note Selected points are drawn using the selected color if it was specified.
\sa selectedPoints(), setPointSelected(), setSelectedColor()
@@ -1887,6 +1965,11 @@ void QXYSeriesPrivate::setMarkerSize(qreal markerSize)
m_markerSize = markerSize;
}
+QList<qreal> QXYSeriesPrivate::colorByData() const
+{
+ return m_colorByData;
+}
+
QT_END_NAMESPACE
#include "moc_qxyseries.cpp"
diff --git a/src/charts/xychart/qxyseries.h b/src/charts/xychart/qxyseries.h
index f02caa5a..498f69a2 100644
--- a/src/charts/xychart/qxyseries.h
+++ b/src/charts/xychart/qxyseries.h
@@ -170,6 +170,7 @@ public:
QHash<int, QHash<PointConfiguration, QVariant>> pointsConfiguration() const;
void sizeBy(const QList<qreal> &sourceData, const qreal minSize, const qreal maxSize);
+ void colorBy(const QList<qreal> &sourceData, const QLinearGradient &gradient = QLinearGradient());
Q_SIGNALS:
void clicked(const QPointF &point);
@@ -205,6 +206,7 @@ private:
friend class QXYLegendMarkerPrivate;
friend class XYLegendMarker;
friend class XYChart;
+ friend class QColorAxisPrivate;
};
QT_END_NAMESPACE
diff --git a/src/charts/xychart/qxyseries_p.h b/src/charts/xychart/qxyseries_p.h
index 3846826e..4c4440b7 100644
--- a/src/charts/xychart/qxyseries_p.h
+++ b/src/charts/xychart/qxyseries_p.h
@@ -78,6 +78,8 @@ public:
bool isMarkerSizeDefault();
void setMarkerSize(qreal markerSize);
+ QList<qreal> colorByData() const;
+
Q_SIGNALS:
void seriesUpdated();
@@ -100,6 +102,7 @@ protected:
bool m_markerSizeDefault = true;
QHash<int, QHash<QXYSeries::PointConfiguration, QVariant>> m_pointsConfiguration;
+ QList<qreal> m_colorByData;
private:
Q_DECLARE_PUBLIC(QXYSeries)