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 <QtCore/qmath.h>
31#include <private/abstractdomain_p.h>
32#include <private/chartlogvalueaxisx_p.h>
33#include <private/chartlogvalueaxisy_p.h>
34#include <private/polarchartlogvalueaxisangular_p.h>
35#include <private/polarchartlogvalueaxisradial_p.h>
36#include <private/qlogvalueaxis_p.h>
37
38QT_CHARTS_BEGIN_NAMESPACE
39
40/*!
41 \class QLogValueAxis
42 \inmodule QtCharts
43 \brief The QLogValueAxis class adds a logarithmic scale to a chart's axis.
44
45 A logarithmic scale is a nonlinear scale that is based on orders of magnitude,
46 so that each tick mark on the axis is the previous tick mark multiplied by a value.
47
48 \note If QLogValueAxis is attached to a series with one or more points with
49 negative or zero values on the associated dimension, the series will not be
50 plotted at all. This is particularly relevant when XYModelMappers are used,
51 since empty cells in models typically contain zero values.
52*/
53
54/*!
55 \qmltype LogValueAxis
56 \instantiates QLogValueAxis
57 \inqmlmodule QtCharts
58
59 \brief Adds a logarithmic scale to a chart's axis.
60 \inherits AbstractAxis
61
62 A logarithmic scale is a nonlinear scale that is based on orders of magnitude,
63 so that each tick mark on the axis is the previous tick mark multiplied by a value.
64
65 \note If a LogValueAxis type is attached to a series with one or more points with
66 negative or zero values on the associated dimension, the series will not be
67 plotted at all. This is particularly relevant when XYModelMappers are used,
68 since empty cells in models typically contain zero values.
69*/
70
71/*!
72 \property QLogValueAxis::min
73 \brief The minimum value on the axis.
74
75 When setting this property, the maximum value is adjusted if necessary, to ensure that
76 the range remains valid.
77 The value has to be greater than 0.
78*/
79/*!
80 \qmlproperty real LogValueAxis::min
81 The minimum value on the axis.
82
83 When setting this property, the maximum value is adjusted if necessary, to ensure that
84 the range remains valid.
85 The value has to be greater than 0.
86*/
87
88/*!
89 \property QLogValueAxis::max
90 \brief The maximum value on the axis.
91
92 When setting this property, the minimum value is adjusted if necessary, to ensure that
93 the range remains valid.
94 The value has to be greater than 0.
95*/
96/*!
97 \qmlproperty real LogValueAxis::max
98 The maximum value on the axis.
99
100 When setting this property, the minimum value is adjusted if necessary, to ensure that
101 the range remains valid.
102 The value has to be greater than 0.
103*/
104
105/*!
106 \property QLogValueAxis::base
107 \brief The base of the logarithm.
108
109 The value has to be greater than 0 and cannot equal 1.
110*/
111/*!
112 \qmlproperty real LogValueAxis::base
113 The base of the logarithm.
114
115 The value has to be greater than 0 and cannot equal 1.
116*/
117
118/*!
119 \property QLogValueAxis::tickCount
120 \brief The number of tick marks on the axis. This indicates how many grid lines are drawn on the
121 chart. This value is read-only.
122*/
123/*!
124 \qmlproperty int LogValueAxis::tickCount
125 The number of tick marks on the axis. This indicates how many grid lines are drawn on the
126 chart. This value is read-only.
127*/
128
129/*!
130 \property QLogValueAxis::minorTickCount
131 \brief The number of minor tick marks on the axis. This indicates how many grid lines are drawn
132 between major ticks on the chart. Labels are not drawn for minor ticks. The default value is 0.
133 Set the value to -1 and the number of grid lines between major ticks will be calculated
134 automatically.
135*/
136/*!
137 \qmlproperty int LogValueAxis::minorTickCount
138 The number of minor tick marks on the axis. This indicates how many grid lines are drawn between
139 major ticks on the chart. Labels are not drawn for minor ticks. The default value is 0. Set the
140 value to -1 and the number of grid lines between major ticks will be calculated automatically.
141*/
142
143/*!
144 \property QLogValueAxis::labelFormat
145 \brief The label format of the axis.
146
147 The format string supports the following conversion specifiers, length modifiers, and flags
148 provided by \c printf() in the standard C++ library: d, i, o, x, X, f, F, e, E, g, G, c.
149
150 If QChart::localizeNumbers is \c true, the supported specifiers are limited to:
151 d, e, E, f, g, G, and i. Also, only the precision modifier is supported. The rest of the
152 formatting comes from the default QLocale of the application.
153
154 \sa QString::asprintf()
155*/
156/*!
157 \qmlproperty real LogValueAxis::labelFormat
158 The label format of the axis.
159
160 The format string supports the following conversion specifiers, length modifiers, and flags
161 provided by \c printf() in the standard C++ library: d, i, o, x, X, f, F, e, E, g, G, c.
162
163 If \l{ChartView::localizeNumbers}{ChartView.localizeNumbers} is \c true, the supported
164 specifiers are limited to: d, e, E, f, g, G, and i. Also, only the precision modifier is
165 supported. The rest of the formatting comes from the default QLocale of the application.
166
167 \sa QString::asprintf()
168*/
169
170/*!
171 \fn void QLogValueAxis::minChanged(qreal min)
172 This signal is emitted when the minimum value of the axis, specified by \a min, changes.
173*/
174
175/*!
176 \fn void QLogValueAxis::maxChanged(qreal max)
177 This signal is emitted when the maximum value of the axis, specified by \a max, changes.
178*/
179
180/*!
181 \fn void QLogValueAxis::rangeChanged(qreal min, qreal max)
182 This signal is emitted when the minimum or maximum value of the axis, specified by \a min
183 and \a max, changes.
184*/
185
186/*!
187 \fn void QLogValueAxis::tickCountChanged(int tickCount)
188 This signal is emitted when the number of tick marks on the axis, specified by \a tickCount,
189 changes.
190*/
191/*!
192 \qmlsignal LogValueAxis::tickCountChanged(int tickCount)
193 This signal is emitted when the number of tick marks on the axis, specified by \a tickCount,
194 changes.
195*/
196
197/*!
198 \fn void QLogValueAxis::minorTickCountChanged(int minorTickCount)
199 This signal is emitted when the number of minor tick marks on the axis, specified by
200 \a minorTickCount, changes.
201*/
202/*!
203 \qmlsignal LogValueAxis::minorTickCountChanged(int minorTickCount)
204 This signal is emitted when the number of minor tick marks on the axis, specified by
205 \a minorTickCount, changes.
206*/
207
208/*!
209 \fn void QLogValueAxis::labelFormatChanged(const QString &format)
210 This signal is emitted when the \a format of axis labels changes.
211*/
212
213/*!
214 \fn void QLogValueAxis::baseChanged(qreal base)
215 This signal is emitted when the \a base of the logarithm of the axis changes.
216*/
217
218/*!
219 Constructs an axis object that is a child of \a parent.
220*/
221QLogValueAxis::QLogValueAxis(QObject *parent) :
222 QAbstractAxis(*new QLogValueAxisPrivate(this), parent)
223{
224
225}
226
227/*!
228 \internal
229*/
230QLogValueAxis::QLogValueAxis(QLogValueAxisPrivate &d, QObject *parent) : QAbstractAxis(d, parent)
231{
232
233}
234
235/*!
236 Destroys the object.
237*/
238QLogValueAxis::~QLogValueAxis()
239{
240 Q_D(QLogValueAxis);
241 if (d->m_chart)
242 d->m_chart->removeAxis(axis: this);
243}
244
245void QLogValueAxis::setMin(qreal min)
246{
247 Q_D(QLogValueAxis);
248 setRange(min, max: qMax(a: d->m_max, b: min));
249}
250
251qreal QLogValueAxis::min() const
252{
253 Q_D(const QLogValueAxis);
254 return d->m_min;
255}
256
257void QLogValueAxis::setMax(qreal max)
258{
259 Q_D(QLogValueAxis);
260 setRange(min: qMin(a: d->m_min, b: max), max);
261}
262
263qreal QLogValueAxis::max() const
264{
265 Q_D(const QLogValueAxis);
266 return d->m_max;
267}
268
269/*!
270 Sets the range from \a min to \a max on the axis.
271 If \a min is greater than \a max, this function returns without making any changes.
272*/
273void QLogValueAxis::setRange(qreal min, qreal max)
274{
275 Q_D(QLogValueAxis);
276
277 if (min > max)
278 return;
279
280 if (min > 0) {
281 bool changed = false;
282
283 if (!qFuzzyCompare(p1: d->m_min, p2: min)) {
284 d->m_min = min;
285 changed = true;
286 emit minChanged(min);
287 }
288
289 if (!qFuzzyCompare(p1: d->m_max, p2: max)) {
290 d->m_max = max;
291 changed = true;
292 emit maxChanged(max);
293 }
294
295 if (changed) {
296 d->updateTickCount();
297 emit rangeChanged(min, max);
298 emit d->rangeChanged(min,max);
299 }
300 }
301}
302
303void QLogValueAxis::setLabelFormat(const QString &format)
304{
305 Q_D(QLogValueAxis);
306
307 if (d->m_labelFormat == format)
308 return;
309
310 d->m_labelFormat = format;
311 emit labelFormatChanged(format: d->m_labelFormat);
312}
313
314QString QLogValueAxis::labelFormat() const
315{
316 Q_D(const QLogValueAxis);
317 return d->m_labelFormat;
318}
319
320void QLogValueAxis::setBase(qreal base)
321{
322 Q_D(QLogValueAxis);
323
324 if (base < 0.0 || qFuzzyIsNull(d: base) || qFuzzyCompare(p1: base, p2: 1.0) // check if base is correct
325 || qFuzzyCompare(p1: d->m_base, p2: base)) {
326 return;
327 }
328
329 d->m_base = base;
330 d->updateTickCount();
331 emit baseChanged(base: d->m_base);
332}
333
334qreal QLogValueAxis::base() const
335{
336 Q_D(const QLogValueAxis);
337 return d->m_base;
338}
339
340int QLogValueAxis::tickCount() const
341{
342 Q_D(const QLogValueAxis);
343 return d->m_tickCount;
344}
345
346void QLogValueAxis::setMinorTickCount(int minorTickCount)
347{
348 Q_D(QLogValueAxis);
349
350 if (minorTickCount < 0)
351 minorTickCount = -1;
352
353 if (d->m_minorTickCount == minorTickCount)
354 return;
355
356 d->m_minorTickCount = minorTickCount;
357 emit minorTickCountChanged(minorTickCount);
358}
359
360int QLogValueAxis::minorTickCount() const
361{
362 Q_D(const QLogValueAxis);
363 return d->m_minorTickCount;
364}
365
366/*!
367 Returns the type of the axis.
368*/
369QAbstractAxis::AxisType QLogValueAxis::type() const
370{
371 return AxisTypeLogValue;
372}
373
374////////////////////////////////////////////////////////////////////////////////////////////////////
375
376QLogValueAxisPrivate::QLogValueAxisPrivate(QLogValueAxis *q)
377 : QAbstractAxisPrivate(q),
378 m_min(1),
379 m_max(1),
380 m_base(10),
381 m_tickCount(0),
382 m_minorTickCount(0),
383 m_labelFormat()
384{
385}
386
387QLogValueAxisPrivate::~QLogValueAxisPrivate()
388{
389}
390
391void QLogValueAxisPrivate::setMin(const QVariant &min)
392{
393 Q_Q(QLogValueAxis);
394 bool ok;
395 qreal value = min.toReal(ok: &ok);
396 if (ok)
397 q->setMin(value);
398}
399
400void QLogValueAxisPrivate::setMax(const QVariant &max)
401{
402
403 Q_Q(QLogValueAxis);
404 bool ok;
405 qreal value = max.toReal(ok: &ok);
406 if (ok)
407 q->setMax(value);
408}
409
410void QLogValueAxisPrivate::setRange(const QVariant &min, const QVariant &max)
411{
412 Q_Q(QLogValueAxis);
413 bool ok1;
414 bool ok2;
415 qreal value1 = min.toReal(ok: &ok1);
416 qreal value2 = max.toReal(ok: &ok2);
417 if (ok1 && ok2)
418 q->setRange(min: value1, max: value2);
419}
420
421void QLogValueAxisPrivate::setRange(qreal min, qreal max)
422{
423 Q_Q(QLogValueAxis);
424
425 if (min > max)
426 return;
427
428 if (min > 0) {
429 bool changed = false;
430
431 if (!qFuzzyCompare(p1: m_min, p2: min)) {
432 m_min = min;
433 changed = true;
434 emit q->minChanged(min);
435 }
436
437 if (!qFuzzyCompare(p1: m_max, p2: max)) {
438 m_max = max;
439 changed = true;
440 emit q->maxChanged(max);
441 }
442
443 if (changed) {
444 updateTickCount();
445 emit rangeChanged(min,max);
446 emit q->rangeChanged(min, max);
447 }
448 }
449}
450
451void QLogValueAxisPrivate::updateTickCount()
452{
453 Q_Q(QLogValueAxis);
454
455 const qreal logMax = qLn(v: m_max) / qLn(v: m_base);
456 const qreal logMin = qLn(v: m_min) / qLn(v: m_base);
457 int tickCount = qAbs(t: qCeil(v: logMax) - qCeil(v: logMin));
458
459 // If the high edge sits exactly on the tick value, add a tick
460 qreal highValue = logMin < logMax ? logMax : logMin;
461 if (qFuzzyCompare(p1: highValue, p2: qreal(qCeil(v: highValue))))
462 ++tickCount;
463
464 if (m_tickCount == tickCount)
465 return;
466
467 m_tickCount = tickCount;
468 emit q->tickCountChanged(tickCount: m_tickCount);
469}
470
471void QLogValueAxisPrivate::initializeGraphics(QGraphicsItem *parent)
472{
473 Q_Q(QLogValueAxis);
474 ChartAxisElement *axis(0);
475
476 if (m_chart->chartType() == QChart::ChartTypeCartesian) {
477 if (orientation() == Qt::Vertical)
478 axis = new ChartLogValueAxisY(q,parent);
479 if (orientation() == Qt::Horizontal)
480 axis = new ChartLogValueAxisX(q,parent);
481 }
482
483 if (m_chart->chartType() == QChart::ChartTypePolar) {
484 if (orientation() == Qt::Vertical)
485 axis = new PolarChartLogValueAxisRadial(q, parent);
486 if (orientation() == Qt::Horizontal)
487 axis = new PolarChartLogValueAxisAngular(q, parent);
488 }
489
490 m_item.reset(other: axis);
491 QAbstractAxisPrivate::initializeGraphics(parent);
492}
493
494
495void QLogValueAxisPrivate::initializeDomain(AbstractDomain *domain)
496{
497 if (orientation() == Qt::Vertical) {
498 if (!qFuzzyCompare(p1: m_max, p2: m_min)) {
499 domain->setRangeY(min: m_min, max: m_max);
500 } else if ( domain->minY() > 0) {
501 setRange(min: domain->minY(), max: domain->maxY());
502 } else if (domain->maxY() > 0) {
503 domain->setRangeY(min: m_min, max: domain->maxY());
504 } else {
505 domain->setRangeY(min: 1, max: 10);
506 }
507 }
508 if (orientation() == Qt::Horizontal) {
509 if (!qFuzzyCompare(p1: m_max, p2: m_min)) {
510 domain->setRangeX(min: m_min, max: m_max);
511 } else if (domain->minX() > 0){
512 setRange(min: domain->minX(), max: domain->maxX());
513 } else if (domain->maxX() > 0) {
514 domain->setRangeX(min: m_min, max: domain->maxX());
515 } else {
516 domain->setRangeX(min: 1, max: 10);
517 }
518 }
519}
520
521QT_CHARTS_END_NAMESPACE
522
523#include "moc_qlogvalueaxis.cpp"
524#include "moc_qlogvalueaxis_p.cpp"
525

source code of qtcharts/src/charts/axis/logvalueaxis/qlogvalueaxis.cpp