1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtCharts/QColorAxis> |
5 | #include <QtCharts/QXYSeries> |
6 | #include <private/abstractdomain_p.h> |
7 | #include <private/qcoloraxis_p.h> |
8 | #include <private/qxyseries_p.h> |
9 | #include <private/chartcoloraxisx_p.h> |
10 | #include <private/chartcoloraxisy_p.h> |
11 | #include <private/chartvalueaxisy_p.h> |
12 | #include <private/charthelpers_p.h> |
13 | |
14 | #include <QtCharts/QChart> |
15 | |
16 | QT_BEGIN_NAMESPACE |
17 | /*! |
18 | \class QColorAxis |
19 | \inmodule QtCharts |
20 | \brief The QColorAxis class displays a color scale as one of the chart's axes. |
21 | \since 6.2 |
22 | |
23 | A color axis can be set up to show a color scale based on the passed gradient. |
24 | The scale has tick marks with labels based on data passed in QXYSeries::colorby method. |
25 | */ |
26 | |
27 | /*! |
28 | \property QColorAxis::min |
29 | \brief The minimum value on the axis. |
30 | |
31 | When setting this property, the maximum value is adjusted if necessary, to ensure that |
32 | the range remains valid. |
33 | */ |
34 | |
35 | /*! |
36 | \property QColorAxis::max |
37 | \brief The maximum value on the axis. |
38 | |
39 | When setting this property, the minimum value is adjusted if necessary, to ensure that |
40 | the range remains valid. |
41 | */ |
42 | |
43 | /*! |
44 | \property QColorAxis::tickCount |
45 | \brief The number of tick marks on the axis. This indicates how many grid lines are drawn on the |
46 | chart if QColorAxis::gridVisible is equal to \c true. The default value is 5, and the number |
47 | cannot be less than 2. |
48 | |
49 | \note Grid lines are intentionally invisible by default in QColorAxis as this type of axis |
50 | does not represent geometric values. |
51 | */ |
52 | |
53 | /*! |
54 | \property QColorAxis::size |
55 | \brief The size of the color scale. |
56 | |
57 | Depending on the alignment the value indicates either width or height. |
58 | */ |
59 | |
60 | /*! |
61 | \property QColorAxis::autoRange |
62 | \brief The property indicating if the range should be set from the list of values |
63 | passed in QXYSeries::colorBy method or rather taken from the axis itself. |
64 | |
65 | The default value is \c true. |
66 | */ |
67 | |
68 | /*! |
69 | \fn void QColorAxis::minChanged(qreal min) |
70 | This signal is emitted when the minimum value of the axis, specified by \a min, changes. |
71 | */ |
72 | |
73 | /*! |
74 | \fn void QColorAxis::maxChanged(qreal max) |
75 | This signal is emitted when the maximum value of the axis, specified by \a max, changes. |
76 | */ |
77 | |
78 | /*! |
79 | \fn void QColorAxis::tickCountChanged(int tickCount) |
80 | This signal is emitted when the number of tick marks on the axis, specified by \a tickCount, |
81 | changes. |
82 | */ |
83 | |
84 | /*! |
85 | \fn void QColorAxis::sizeChanged(qreal size) |
86 | This signal is emitted when the size of the color scale, specified by \a size, changes. |
87 | */ |
88 | |
89 | /*! |
90 | \fn void QColorAxis::autoRangeChanged(bool autoRange) |
91 | This signal is emitted when the auto range mode, specified by \a autoRange, changes. |
92 | */ |
93 | |
94 | /*! |
95 | \fn void QColorAxis::rangeChanged(qreal min, qreal max) |
96 | This signal is emitted when the minimum or maximum value of the axis, specified by \a min |
97 | and \a max, changes. |
98 | */ |
99 | |
100 | QColorAxis::QColorAxis(QObject *parent) |
101 | : QAbstractAxis(*new QColorAxisPrivate(this), parent) |
102 | { |
103 | setGridLineVisible(false); |
104 | QPen linePen = QPen(Qt::black); |
105 | linePen.setWidthF(2.0); |
106 | setLinePen(linePen); |
107 | } |
108 | |
109 | /*! |
110 | \internal |
111 | */ |
112 | QColorAxis::QColorAxis(QColorAxisPrivate &d, QObject *parent) |
113 | : QAbstractAxis(d, parent) |
114 | { |
115 | |
116 | } |
117 | |
118 | /*! |
119 | Destroys the object. |
120 | */ |
121 | QColorAxis::~QColorAxis() |
122 | { |
123 | Q_D(QColorAxis); |
124 | if (d->m_chart) |
125 | d->m_chart->removeAxis(axis: this); |
126 | } |
127 | |
128 | QAbstractAxis::AxisType QColorAxis::type() const |
129 | { |
130 | return QAbstractAxis::AxisTypeColor; |
131 | } |
132 | |
133 | void QColorAxis::setMin(qreal min) |
134 | { |
135 | Q_D(QColorAxis); |
136 | setRange(min, max: qMax(a: d->m_max, b: min)); |
137 | } |
138 | |
139 | qreal QColorAxis::min() const |
140 | { |
141 | Q_D(const QColorAxis); |
142 | return d->m_min; |
143 | } |
144 | |
145 | void QColorAxis::setMax(qreal max) |
146 | { |
147 | Q_D(QColorAxis); |
148 | setRange(min: qMin(a: d->m_min, b: max), max); |
149 | } |
150 | |
151 | qreal QColorAxis::max() const |
152 | { |
153 | Q_D(const QColorAxis); |
154 | return d->m_max; |
155 | } |
156 | |
157 | void QColorAxis::setRange(qreal min, qreal max) |
158 | { |
159 | Q_D(QColorAxis); |
160 | d->setRange(min, max); |
161 | } |
162 | |
163 | void QColorAxis::setTickCount(int count) |
164 | { |
165 | Q_D(QColorAxis); |
166 | if (d->m_tickCount != count && count >= 2) { |
167 | d->m_tickCount = count; |
168 | emit tickCountChanged(tickCount: count); |
169 | } |
170 | } |
171 | |
172 | int QColorAxis::tickCount() const |
173 | { |
174 | Q_D(const QColorAxis); |
175 | return d->m_tickCount; |
176 | } |
177 | |
178 | void QColorAxis::setSize(const qreal size) |
179 | { |
180 | Q_D(QColorAxis); |
181 | if (d->m_size != size) { |
182 | d->m_size = size; |
183 | emit sizeChanged(size); |
184 | } |
185 | } |
186 | |
187 | qreal QColorAxis::size() const |
188 | { |
189 | Q_D(const QColorAxis); |
190 | return d->m_size; |
191 | } |
192 | |
193 | /*! |
194 | Sets the gradient on the color scale to \a gradient. |
195 | |
196 | \note If the axis is attached to a series, the gradient is also used |
197 | by the QXYSeries::colorBy method. |
198 | \sa gradient |
199 | */ |
200 | void QColorAxis::setGradient(const QLinearGradient &gradient) |
201 | { |
202 | Q_D(QColorAxis); |
203 | if (d->m_gradient != gradient) { |
204 | d->m_gradient = gradient; |
205 | emit gradientChanged(gradient); |
206 | } |
207 | } |
208 | |
209 | /*! |
210 | Returns the gradient currently used on the color scale. |
211 | |
212 | \note If the axis is attached to a series, the gradient is also used |
213 | by the QXYSeries::colorBy method. |
214 | \sa setGradient |
215 | */ |
216 | QLinearGradient QColorAxis::gradient() const |
217 | { |
218 | Q_D(const QColorAxis); |
219 | return d->m_gradient; |
220 | } |
221 | |
222 | void QColorAxis::setAutoRange(bool autoRange) |
223 | { |
224 | Q_D(QColorAxis); |
225 | if (d->m_autoRange != autoRange) { |
226 | d->m_autoRange = autoRange; |
227 | emit autoRangeChanged(autoRange: d->m_autoRange); |
228 | } |
229 | } |
230 | |
231 | bool QColorAxis::autoRange() const |
232 | { |
233 | Q_D(const QColorAxis); |
234 | return d->m_autoRange; |
235 | } |
236 | |
237 | QColorAxisPrivate::QColorAxisPrivate(QColorAxis *q) |
238 | : QAbstractAxisPrivate(q) |
239 | , m_min(0) |
240 | , m_max(1) |
241 | , m_tickCount(5) |
242 | , m_size(15) |
243 | , m_autoRange(true) |
244 | { |
245 | m_gradient = QLinearGradient(QPointF(0, 0), QPointF(0, 100)); |
246 | m_gradient.setColorAt(pos: 0, color: Qt::white); |
247 | m_gradient.setColorAt(pos: 1, color: Qt::black); |
248 | } |
249 | |
250 | QColorAxisPrivate::~QColorAxisPrivate() |
251 | { |
252 | |
253 | } |
254 | |
255 | void QColorAxisPrivate::initializeGraphics(QGraphicsItem *parent) |
256 | { |
257 | Q_Q(QColorAxis); |
258 | ChartAxisElement *axis(0); |
259 | if (m_chart->chartType() == QChart::ChartTypeCartesian) { |
260 | if (orientation() == Qt::Vertical) |
261 | axis = new ChartColorAxisY(q, parent); |
262 | else if (orientation() == Qt::Horizontal) |
263 | axis = new ChartColorAxisX(q, parent); |
264 | } |
265 | |
266 | if (m_chart->chartType() == QChart::ChartTypePolar) |
267 | qWarning() << "Polar chart is not supported by color axis." ; |
268 | |
269 | m_item.reset(p: axis); |
270 | QAbstractAxisPrivate::initializeGraphics(parent); |
271 | } |
272 | |
273 | void QColorAxisPrivate::initializeDomain(AbstractDomain *domain) |
274 | { |
275 | Q_UNUSED(domain); |
276 | if (orientation() == Qt::Vertical) { |
277 | if (m_autoRange) |
278 | updateSeries(); |
279 | else |
280 | setRange(min: m_min, max: m_max); |
281 | } |
282 | |
283 | if (orientation() == Qt::Horizontal) { |
284 | if (m_autoRange) |
285 | updateSeries(); |
286 | else |
287 | setRange(min: m_min, max: m_max); |
288 | } |
289 | } |
290 | |
291 | void QColorAxisPrivate::setRange(qreal min, qreal max) |
292 | { |
293 | Q_Q(QColorAxis); |
294 | bool changed = false; |
295 | |
296 | if (min > max) |
297 | return; |
298 | |
299 | if (!isValidValue(x: min, y: max)) { |
300 | qWarning() << "Attempting to set invalid range for value axis: [" |
301 | << min << " - " << max << "]" ; |
302 | return; |
303 | } |
304 | |
305 | if (m_min != min) { |
306 | m_min = min; |
307 | changed = true; |
308 | emit q->minChanged(min); |
309 | } |
310 | |
311 | if (m_max != max) { |
312 | m_max = max; |
313 | changed = true; |
314 | emit q->maxChanged(max); |
315 | } |
316 | |
317 | if (changed) { |
318 | emit rangeChanged(min,max); |
319 | emit q->rangeChanged(min, max); |
320 | |
321 | if (!m_autoRange) |
322 | updateSeries(); |
323 | } |
324 | } |
325 | |
326 | void QColorAxisPrivate::updateSeries() |
327 | { |
328 | const QList<QAbstractSeries *> series = m_series; |
329 | for (const auto &serie : series) { |
330 | if (serie->type() == QAbstractSeries::SeriesTypeLine |
331 | || serie->type() == QAbstractSeries::SeriesTypeSpline |
332 | || serie->type() == QAbstractSeries::SeriesTypeScatter) { |
333 | QXYSeries *xySeries = static_cast<QXYSeries *>(serie); |
334 | const auto &colorByData = xySeries->d_func()->colorByData(); |
335 | if (!colorByData.isEmpty()) |
336 | xySeries->colorBy(sourceData: colorByData); |
337 | } |
338 | } |
339 | } |
340 | |
341 | void QColorAxisPrivate::setMin(const QVariant &min) |
342 | { |
343 | Q_Q(QColorAxis); |
344 | bool ok; |
345 | qreal value = min.toReal(ok: &ok); |
346 | if (ok) |
347 | q->setMin(value); |
348 | } |
349 | |
350 | void QColorAxisPrivate::setMax(const QVariant &max) |
351 | { |
352 | Q_Q(QColorAxis); |
353 | bool ok; |
354 | qreal value = max.toReal(ok: &ok); |
355 | if (ok) |
356 | q->setMax(value); |
357 | } |
358 | |
359 | void QColorAxisPrivate::setRange(const QVariant &min, const QVariant &max) |
360 | { |
361 | Q_Q(QColorAxis); |
362 | bool ok1; |
363 | bool ok2; |
364 | qreal value1 = min.toReal(ok: &ok1); |
365 | qreal value2 = max.toReal(ok: &ok2); |
366 | if (ok1 && ok2) |
367 | q->setRange(min: value1, max: value2); |
368 | } |
369 | |
370 | QT_END_NAMESPACE |
371 | |
372 | #include "moc_qcoloraxis.cpp" |
373 | #include "moc_qcoloraxis_p.cpp" |
374 | |