1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt Charts module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include <QtCharts/QValueAxis> |
31 | #include <private/qvalueaxis_p.h> |
32 | #include <private/chartvalueaxisx_p.h> |
33 | #include <private/chartvalueaxisy_p.h> |
34 | #include <private/abstractdomain_p.h> |
35 | #include <private/polarchartvalueaxisangular_p.h> |
36 | #include <private/polarchartvalueaxisradial_p.h> |
37 | #include <private/chartdataset_p.h> |
38 | #include <private/chartpresenter_p.h> |
39 | #include <private/charttheme_p.h> |
40 | #include <private/charthelpers_p.h> |
41 | |
42 | QT_CHARTS_BEGIN_NAMESPACE |
43 | /*! |
44 | \class QValueAxis |
45 | \inmodule QtCharts |
46 | \brief The QValueAxis class adds values to a chart's axes. |
47 | |
48 | A value axis can be set up to show an axis line with tick marks, grid lines, and shades. |
49 | The values on the axis are drawn at the positions of tick marks. |
50 | |
51 | The following example code illustrates how to use the QValueAxis class: |
52 | \code |
53 | QChartView *chartView = new QChartView; |
54 | QLineSeries *series = new QLineSeries; |
55 | // ... |
56 | chartView->chart()->addSeries(series); |
57 | |
58 | QValueAxis *axisX = new QValueAxis; |
59 | axisX->setRange(10, 20.5); |
60 | axisX->setTickCount(10); |
61 | axisX->setLabelFormat("%.2f"); |
62 | chartView->chart()->setAxisX(axisX, series); |
63 | \endcode |
64 | */ |
65 | /*! |
66 | \qmltype ValueAxis |
67 | \instantiates QValueAxis |
68 | \inqmlmodule QtCharts |
69 | |
70 | \inherits AbstractAxis |
71 | \brief Adds values to a chart's axes. |
72 | |
73 | The ValueAxis type can be set up to show an axis line with tick marks, grid lines, and shades. |
74 | The values on the axis are drawn at the positions of tick marks. |
75 | |
76 | The following example code illustrates how to use the ValueAxis type: |
77 | \code |
78 | ChartView { |
79 | ValueAxis { |
80 | id: xAxis |
81 | min: 0 |
82 | max: 10 |
83 | } |
84 | // Add a few series... |
85 | } |
86 | \endcode |
87 | */ |
88 | |
89 | /*! |
90 | \property QValueAxis::min |
91 | \brief The minimum value on the axis. |
92 | |
93 | When setting this property, the maximum value is adjusted if necessary, to ensure that |
94 | the range remains valid. |
95 | */ |
96 | /*! |
97 | \qmlproperty real ValueAxis::min |
98 | The minimum value on the axis. |
99 | |
100 | When setting this property, the maximum value is adjusted if necessary, to ensure that |
101 | the range remains valid. |
102 | */ |
103 | |
104 | /*! |
105 | \property QValueAxis::max |
106 | \brief The maximum value on the axis. |
107 | |
108 | When setting this property, the minimum value is adjusted if necessary, to ensure that |
109 | the range remains valid. |
110 | */ |
111 | /*! |
112 | \qmlproperty real ValueAxis::max |
113 | The maximum value on the axis. |
114 | |
115 | When setting this property, the minimum value is adjusted if necessary, to ensure that |
116 | the range remains valid. |
117 | */ |
118 | |
119 | /*! |
120 | \property QValueAxis::tickCount |
121 | \brief The number of tick marks on the axis. This indicates how many grid lines are drawn on the |
122 | chart. The default value is 5, and the number cannot be less than 2. |
123 | */ |
124 | /*! |
125 | \qmlproperty int ValueAxis::tickCount |
126 | The number of tick marks on the axis. This indicates how many grid lines are drawn on the |
127 | chart. The default value is 5, and the number cannot be less than 2. |
128 | */ |
129 | |
130 | /*! |
131 | \property QValueAxis::minorTickCount |
132 | \brief The number of minor tick marks on the axis. This indicates how many grid lines are drawn |
133 | between major ticks on the chart. Labels are not drawn for minor ticks. The default value is 0. |
134 | */ |
135 | /*! |
136 | \qmlproperty int ValueAxis::minorTickCount |
137 | The number of minor tick marks on the axis. This indicates how many grid lines are drawn |
138 | between major ticks on the chart. Labels are not drawn for minor ticks. The default value is 0. |
139 | */ |
140 | |
141 | /*! |
142 | \property QValueAxis::tickAnchor |
143 | \since 5.12 |
144 | \brief The base value where the dynamically placed tick marks and labels are started from. |
145 | */ |
146 | /*! |
147 | \qmlproperty real ValueAxis::tickAnchor |
148 | \since QtCharts 2.3 |
149 | The base value where the dynamically placed tick marks and labels are started from. |
150 | */ |
151 | |
152 | /*! |
153 | \property QValueAxis::tickInterval |
154 | \since 5.12 |
155 | \brief The interval between dynamically placed tick marks and labels. |
156 | */ |
157 | /*! |
158 | \qmlproperty real ValueAxis::tickInterval |
159 | \since QtCharts 2.3 |
160 | The interval between dynamically placed tick marks and labels. |
161 | */ |
162 | |
163 | /*! |
164 | \enum QValueAxis::TickType |
165 | |
166 | This enum describes how the ticks and labels are positioned on the axis. |
167 | |
168 | \value TicksDynamic Ticks are placed according to tickAnchor and tickInterval values. |
169 | \value TicksFixed Ticks are placed evenly across the axis range. The tickCount value |
170 | specifies the number of ticks. |
171 | */ |
172 | /*! |
173 | \property QValueAxis::tickType |
174 | \since 5.12 |
175 | \brief The positioning method of tick and labels. |
176 | */ |
177 | /*! |
178 | \qmlproperty enumeration ValueAxis::tickType |
179 | \since QtCharts 2.3 |
180 | |
181 | The positioning method of tick and labels. |
182 | |
183 | \value ValueAxis.TicksDynamic |
184 | Ticks are placed according to tickAnchor and tickInterval values. |
185 | \value ValueAxis.TicksFixed |
186 | Ticks are placed evenly across the axis range. The tickCount value specifies the number of ticks. |
187 | */ |
188 | |
189 | /*! |
190 | \property QValueAxis::labelFormat |
191 | \brief The label format of the axis. |
192 | |
193 | The format string supports the following conversion specifiers, length modifiers, and flags |
194 | provided by \c printf() in the standard C++ library: d, i, o, x, X, f, F, e, E, g, G, c. |
195 | |
196 | If QChart::localizeNumbers is \c true, the supported specifiers are limited to: |
197 | d, e, E, f, g, G, and i. Also, only the precision modifier is supported. The rest of the |
198 | formatting comes from the default QLocale of the application. |
199 | |
200 | \sa QString::asprintf() |
201 | */ |
202 | /*! |
203 | \qmlproperty string ValueAxis::labelFormat |
204 | |
205 | The format string supports the following conversion specifiers, length modifiers, and flags |
206 | provided by \c printf() in the standard C++ library: d, i, o, x, X, f, F, e, E, g, G, c. |
207 | |
208 | If \l{ChartView::localizeNumbers}{ChartView.localizeNumbers} is \c true, the supported |
209 | specifiers are limited to: d, e, E, f, g, G, and i. Also, only the precision modifier is |
210 | supported. The rest of the formatting comes from the default QLocale of the application. |
211 | |
212 | \sa QString::asprintf() |
213 | */ |
214 | |
215 | /*! |
216 | \fn void QValueAxis::minChanged(qreal min) |
217 | This signal is emitted when the minimum value of the axis, specified by \a min, changes. |
218 | */ |
219 | |
220 | /*! |
221 | \fn void QValueAxis::maxChanged(qreal max) |
222 | This signal is emitted when the maximum value of the axis, specified by \a max, changes. |
223 | */ |
224 | |
225 | /*! |
226 | \fn void QValueAxis::tickCountChanged(int tickCount) |
227 | This signal is emitted when the number of tick marks on the axis, specified by \a tickCount, |
228 | changes. |
229 | */ |
230 | |
231 | /*! |
232 | \fn void QValueAxis::minorTickCountChanged(int minorTickCount) |
233 | This signal is emitted when the number of minor tick marks on the axis, specified by |
234 | \a minorTickCount, changes. |
235 | */ |
236 | |
237 | /*! |
238 | \fn void QValueAxis::rangeChanged(qreal min, qreal max) |
239 | This signal is emitted when the minimum or maximum value of the axis, specified by \a min |
240 | and \a max, changes. |
241 | */ |
242 | |
243 | /*! |
244 | \qmlsignal ValueAxis::rangeChanged(string min, string max) |
245 | This signal is emitted when \a min or \a max value of the axis changes. |
246 | |
247 | The corresponding signal handler is \c onRangeChanged. |
248 | */ |
249 | |
250 | /*! |
251 | \fn void QValueAxis::labelFormatChanged(const QString &format) |
252 | This signal is emitted when the \a format of axis labels changes. |
253 | */ |
254 | |
255 | /*! |
256 | Constructs an axis object that is a child of \a parent. |
257 | */ |
258 | QValueAxis::QValueAxis(QObject *parent) : |
259 | QAbstractAxis(*new QValueAxisPrivate(this), parent) |
260 | { |
261 | |
262 | } |
263 | |
264 | /*! |
265 | \internal |
266 | */ |
267 | QValueAxis::QValueAxis(QValueAxisPrivate &d, QObject *parent) |
268 | : QAbstractAxis(d, parent) |
269 | { |
270 | |
271 | } |
272 | |
273 | /*! |
274 | Destroys the object. |
275 | */ |
276 | QValueAxis::~QValueAxis() |
277 | { |
278 | Q_D(QValueAxis); |
279 | if (d->m_chart) |
280 | d->m_chart->removeAxis(axis: this); |
281 | } |
282 | |
283 | void QValueAxis::setMin(qreal min) |
284 | { |
285 | Q_D(QValueAxis); |
286 | setRange(min, max: qMax(a: d->m_max, b: min)); |
287 | } |
288 | |
289 | qreal QValueAxis::min() const |
290 | { |
291 | Q_D(const QValueAxis); |
292 | return d->m_min; |
293 | } |
294 | |
295 | void QValueAxis::setMax(qreal max) |
296 | { |
297 | Q_D(QValueAxis); |
298 | setRange(min: qMin(a: d->m_min, b: max), max); |
299 | } |
300 | |
301 | qreal QValueAxis::max() const |
302 | { |
303 | Q_D(const QValueAxis); |
304 | return d->m_max; |
305 | } |
306 | |
307 | /*! |
308 | Sets the range from \a min to \a max on the axis. |
309 | If \a min is greater than \a max, this function returns without making any changes. |
310 | */ |
311 | void QValueAxis::setRange(qreal min, qreal max) |
312 | { |
313 | Q_D(QValueAxis); |
314 | d->setRange(min,max); |
315 | } |
316 | |
317 | void QValueAxis::setTickCount(int count) |
318 | { |
319 | Q_D(QValueAxis); |
320 | if (d->m_tickCount != count && count >= 2) { |
321 | d->m_tickCount = count; |
322 | emit tickCountChanged(tickCount: count); |
323 | } |
324 | } |
325 | |
326 | int QValueAxis::tickCount() const |
327 | { |
328 | Q_D(const QValueAxis); |
329 | return d->m_tickCount; |
330 | } |
331 | |
332 | void QValueAxis::setMinorTickCount(int count) |
333 | { |
334 | Q_D(QValueAxis); |
335 | if (d->m_minorTickCount != count && count >= 0) { |
336 | d->m_minorTickCount = count; |
337 | emit minorTickCountChanged(tickCount: count); |
338 | } |
339 | } |
340 | |
341 | int QValueAxis::minorTickCount() const |
342 | { |
343 | Q_D(const QValueAxis); |
344 | return d->m_minorTickCount; |
345 | } |
346 | |
347 | |
348 | void QValueAxis::setTickInterval(qreal interval) |
349 | { |
350 | Q_D(QValueAxis); |
351 | if (d->m_tickInterval != interval) { |
352 | d->m_tickInterval = interval; |
353 | emit tickIntervalChanged(interval); |
354 | } |
355 | } |
356 | |
357 | qreal QValueAxis::tickInterval() const |
358 | { |
359 | Q_D(const QValueAxis); |
360 | return d->m_tickInterval; |
361 | } |
362 | |
363 | void QValueAxis::setTickAnchor(qreal anchor) |
364 | { |
365 | Q_D(QValueAxis); |
366 | if (d->m_tickAnchor != anchor) { |
367 | d->m_tickAnchor = anchor; |
368 | emit tickAnchorChanged(anchor); |
369 | } |
370 | } |
371 | |
372 | qreal QValueAxis::tickAnchor() const |
373 | { |
374 | Q_D(const QValueAxis); |
375 | return d->m_tickAnchor; |
376 | } |
377 | |
378 | void QValueAxis::setTickType(QValueAxis::TickType type) |
379 | { |
380 | Q_D(QValueAxis); |
381 | if (d->m_tickType != type) { |
382 | d->m_tickType = type; |
383 | emit tickTypeChanged(type); |
384 | } |
385 | } |
386 | |
387 | QValueAxis::TickType QValueAxis::tickType() const |
388 | { |
389 | Q_D(const QValueAxis); |
390 | return d->m_tickType; |
391 | } |
392 | |
393 | void QValueAxis::setLabelFormat(const QString &format) |
394 | { |
395 | Q_D(QValueAxis); |
396 | d->m_format = format; |
397 | emit labelFormatChanged(format); |
398 | } |
399 | |
400 | QString QValueAxis::labelFormat() const |
401 | { |
402 | Q_D(const QValueAxis); |
403 | return d->m_format; |
404 | } |
405 | |
406 | /*! |
407 | Returns the type of the axis. |
408 | */ |
409 | QAbstractAxis::AxisType QValueAxis::type() const |
410 | { |
411 | return AxisTypeValue; |
412 | } |
413 | |
414 | /*! |
415 | \qmlmethod ValueAxis::applyNiceNumbers() |
416 | Modifies the current range and number of tick marks on the axis to look |
417 | \e nice. The algorithm considers numbers that can be expressed as a form of |
418 | 1*10^n, 2* 10^n, or 5*10^n to be nice numbers. These numbers are used for |
419 | setting spacing for the tick marks. |
420 | */ |
421 | |
422 | /*! |
423 | Modifies the current range and number of tick marks on the axis to look \e nice. The algorithm |
424 | considers numbers that can be expressed as a form of 1*10^n, 2* 10^n, or 5*10^n to be |
425 | nice numbers. These numbers are used for setting spacing for the tick marks. |
426 | |
427 | \sa setRange(), setTickCount() |
428 | */ |
429 | void QValueAxis::applyNiceNumbers() |
430 | { |
431 | Q_D(QValueAxis); |
432 | if(d->m_applying) return; |
433 | qreal min = d->m_min; |
434 | qreal max = d->m_max; |
435 | int ticks = d->m_tickCount; |
436 | AbstractDomain::looseNiceNumbers(min,max,ticksCount&: ticks); |
437 | d->m_applying=true; |
438 | d->setRange(min,max); |
439 | setTickCount(ticks); |
440 | d->m_applying=false; |
441 | } |
442 | |
443 | ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
444 | |
445 | QValueAxisPrivate::QValueAxisPrivate(QValueAxis *q) |
446 | : QAbstractAxisPrivate(q), |
447 | m_min(0), |
448 | m_max(0), |
449 | m_tickCount(5), |
450 | m_minorTickCount(0), |
451 | m_format(), |
452 | m_applying(false), |
453 | m_tickInterval(0.0), |
454 | m_tickAnchor(0.0), |
455 | m_tickType(QValueAxis::TicksFixed) |
456 | { |
457 | |
458 | } |
459 | |
460 | QValueAxisPrivate::~QValueAxisPrivate() |
461 | { |
462 | |
463 | } |
464 | |
465 | void QValueAxisPrivate::setMin(const QVariant &min) |
466 | { |
467 | Q_Q(QValueAxis); |
468 | bool ok; |
469 | qreal value = min.toReal(ok: &ok); |
470 | if (ok) |
471 | q->setMin(value); |
472 | } |
473 | |
474 | void QValueAxisPrivate::setMax(const QVariant &max) |
475 | { |
476 | Q_Q(QValueAxis); |
477 | bool ok; |
478 | qreal value = max.toReal(ok: &ok); |
479 | if (ok) |
480 | q->setMax(value); |
481 | } |
482 | |
483 | void QValueAxisPrivate::setRange(const QVariant &min, const QVariant &max) |
484 | { |
485 | Q_Q(QValueAxis); |
486 | bool ok1; |
487 | bool ok2; |
488 | qreal value1 = min.toReal(ok: &ok1); |
489 | qreal value2 = max.toReal(ok: &ok2); |
490 | if (ok1 && ok2) |
491 | q->setRange(min: value1, max: value2); |
492 | } |
493 | |
494 | void QValueAxisPrivate::setRange(qreal min, qreal max) |
495 | { |
496 | Q_Q(QValueAxis); |
497 | bool changed = false; |
498 | |
499 | if (min > max) |
500 | return; |
501 | |
502 | if (!isValidValue(x: min, y: max)) { |
503 | qWarning() << "Attempting to set invalid range for value axis: [" |
504 | << min << " - " << max << "]" ; |
505 | return; |
506 | } |
507 | |
508 | if (m_min != min) { |
509 | m_min = min; |
510 | changed = true; |
511 | emit q->minChanged(min); |
512 | } |
513 | |
514 | if (m_max != max) { |
515 | m_max = max; |
516 | changed = true; |
517 | emit q->maxChanged(max); |
518 | } |
519 | |
520 | if (changed) { |
521 | emit rangeChanged(min,max); |
522 | emit q->rangeChanged(min, max); |
523 | } |
524 | } |
525 | |
526 | void QValueAxisPrivate::initializeGraphics(QGraphicsItem *parent) |
527 | { |
528 | Q_Q(QValueAxis); |
529 | ChartAxisElement *axis(0); |
530 | |
531 | if (m_chart->chartType() == QChart::ChartTypeCartesian) { |
532 | if (orientation() == Qt::Vertical) |
533 | axis = new ChartValueAxisY(q,parent); |
534 | if (orientation() == Qt::Horizontal) |
535 | axis = new ChartValueAxisX(q,parent); |
536 | axis->setLabelsEditable(q->labelsEditable()); |
537 | } |
538 | |
539 | if (m_chart->chartType() == QChart::ChartTypePolar) { |
540 | if (orientation() == Qt::Vertical) |
541 | axis = new PolarChartValueAxisRadial(q, parent); |
542 | if (orientation() == Qt::Horizontal) |
543 | axis = new PolarChartValueAxisAngular(q, parent); |
544 | } |
545 | |
546 | m_item.reset(other: axis); |
547 | QAbstractAxisPrivate::initializeGraphics(parent); |
548 | } |
549 | |
550 | |
551 | void QValueAxisPrivate::initializeDomain(AbstractDomain *domain) |
552 | { |
553 | if (orientation() == Qt::Vertical) { |
554 | if (!qFuzzyIsNull(d: m_max - m_min)) |
555 | domain->setRangeY(min: m_min, max: m_max); |
556 | else |
557 | setRange(min: domain->minY(), max: domain->maxY()); |
558 | } |
559 | if (orientation() == Qt::Horizontal) { |
560 | if (!qFuzzyIsNull(d: m_max - m_min)) |
561 | domain->setRangeX(min: m_min, max: m_max); |
562 | else |
563 | setRange(min: domain->minX(), max: domain->maxX()); |
564 | } |
565 | } |
566 | |
567 | QT_CHARTS_END_NAMESPACE |
568 | |
569 | #include "moc_qvalueaxis.cpp" |
570 | #include "moc_qvalueaxis_p.cpp" |
571 | |