qvalueaxis.cpp
420 lines
| 9.7 KiB
| text/x-c
|
CppLexer
|
r1540 | /**************************************************************************** | ||
** | ||||
** Copyright (C) 2012 Digia Plc | ||||
** All rights reserved. | ||||
** For any questions to Digia, please use contact form at http://qt.digia.com | ||||
** | ||||
** This file is part of the Qt Commercial Charts Add-on. | ||||
** | ||||
** $QT_BEGIN_LICENSE$ | ||||
** Licensees holding valid Qt Commercial licenses may use this file in | ||||
** accordance with the Qt Commercial License Agreement provided with the | ||||
** Software or, alternatively, in accordance with the terms contained in | ||||
** a written agreement between you and Digia. | ||||
** | ||||
** If you have questions regarding the use of this file, please use | ||||
** contact form at http://qt.digia.com | ||||
** $QT_END_LICENSE$ | ||||
** | ||||
****************************************************************************/ | ||||
|
r1805 | #include "qvalueaxis.h" | ||
#include "qvalueaxis_p.h" | ||||
#include "chartvalueaxisx_p.h" | ||||
#include "chartvalueaxisy_p.h" | ||||
|
r1661 | #include "domain_p.h" | ||
|
r1725 | #include "chartdataset_p.h" | ||
#include <qmath.h> | ||||
|
r1540 | |||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
|
r1547 | /*! | ||
|
r1804 | \class QValueAxis | ||
\brief The QValueAxis class is used for manipulating chart's axis. | ||||
|
r1547 | \mainclass | ||
|
r1812 | ValueAxis can be setup to show axis line with tick marks, grid lines and shades. | ||
|
r1881 | Values of axis are drawn to position of ticks. | ||
Example code on how to use QValueAxis. | ||||
\code | ||||
QChartView *chartView = new QChartView; | ||||
QLineSeries *series = new QLineSeries; | ||||
// ... | ||||
|
r1882 | chartView->chart()->addSeries(series); | ||
|
r1881 | QValueAxis *axisX = new QValueAxis; | ||
axisX->setRange(10, 20.5); | ||||
axisX->setTickCount(10); | ||||
axisX->setLabelFormat("%.2f"); | ||||
|
r2108 | chartView->chart()->setAxisX(axisX, series); | ||
|
r1881 | \endcode | ||
|
r1547 | */ | ||
/*! | ||||
|
r1812 | \qmlclass ValueAxis QValueAxis | ||
|
r1869 | \inherits AbstractAxis | ||
|
r1812 | \brief The ValueAxis element is used for manipulating chart's axes | ||
|
r1547 | |||
|
r1639 | ValueAxis can be setup to show axis line with tick marks, grid lines and shades. | ||
Values of axis are drawn to position of ticks | ||||
|
r1547 | |||
To access Axes you can use ChartView API. For example: | ||||
\code | ||||
ChartView { | ||||
|
r1812 | ValueAxis { | ||
|
r1639 | id: xAxis | ||
min: 0 | ||||
max: 10 | ||||
} | ||||
// Add a few series... | ||||
|
r1547 | } | ||
\endcode | ||||
*/ | ||||
/*! | ||||
|
r1804 | \property QValueAxis::min | ||
|
r1547 | Defines the minimum value on the axis. | ||
|
r1730 | When setting this property the max is adjusted if necessary, to ensure that the range remains valid. | ||
|
r1547 | */ | ||
/*! | ||||
|
r1812 | \qmlproperty real ValueAxis::min | ||
|
r1547 | Defines the minimum value on the axis. | ||
|
r1730 | When setting this property the max is adjusted if necessary, to ensure that the range remains valid. | ||
|
r1547 | */ | ||
/*! | ||||
|
r1804 | \property QValueAxis::max | ||
|
r1547 | Defines the maximum value on the axis. | ||
|
r1730 | When setting this property the min is adjusted if necessary, to ensure that the range remains valid. | ||
|
r1547 | */ | ||
/*! | ||||
|
r1812 | \qmlproperty real ValueAxis::max | ||
|
r1547 | Defines the maximum value on the axis. | ||
|
r1730 | When setting this property the min is adjusted if necessary, to ensure that the range remains valid. | ||
|
r1547 | */ | ||
|
r1855 | /*! | ||
\property QValueAxis::labelFormat | ||||
Defines the label format for the axis. | ||||
See QString::sprintf() for the details. | ||||
*/ | ||||
/*! | ||||
\qmlproperty real ValueAxis::labelFormat | ||||
Defines the label format for the axis. | ||||
See QString::sprintf() for the details. | ||||
*/ | ||||
|
r1547 | /*! | ||
|
r1804 | \fn void QValueAxis::minChanged(qreal min) | ||
|
r1547 | Axis emits signal when \a min of axis has changed. | ||
*/ | ||||
|
r1654 | /*! | ||
|
r1812 | \qmlsignal ValueAxis::onMinChanged(real min) | ||
|
r1654 | Axis emits signal when \a min of axis has changed. | ||
*/ | ||||
|
r1547 | |||
/*! | ||||
|
r1804 | \fn void QValueAxis::maxChanged(qreal max) | ||
|
r1547 | Axis emits signal when \a max of axis has changed. | ||
*/ | ||||
|
r1654 | /*! | ||
|
r1812 | \qmlsignal ValueAxis::onMaxChanged(real max) | ||
|
r1654 | Axis emits signal when \a max of axis has changed. | ||
*/ | ||||
|
r1547 | |||
/*! | ||||
|
r1804 | \fn void QValueAxis::rangeChanged(qreal min, qreal max) | ||
|
r1547 | Axis emits signal when \a min or \a max of axis has changed. | ||
*/ | ||||
|
r1540 | |||
|
r1575 | /*! | ||
|
r1812 | \property QValueAxis::tickCount | ||
|
r1575 | The number of tick marks for the axis. | ||
*/ | ||||
/*! | ||||
|
r1812 | \qmlproperty int ValueAxis::tickCount | ||
|
r1575 | The number of tick marks for the axis. | ||
*/ | ||||
/*! | ||||
|
r1804 | \property QValueAxis::niceNumbersEnabled | ||
|
r1575 | Whether the nice numbers algorithm is enabled or not for the axis. | ||
*/ | ||||
/*! | ||||
|
r1812 | \qmlproperty bool ValueAxis::niceNumbersEnabled | ||
|
r1575 | Whether the nice numbers algorithm is enabled or not for the axis. | ||
*/ | ||||
|
r1636 | /*! | ||
Constructs an axis object which is a child of \a parent. | ||||
*/ | ||||
|
r1804 | QValueAxis::QValueAxis(QObject *parent) : | ||
|
r2097 | QAbstractAxis(*new QValueAxisPrivate(this), parent) | ||
|
r1540 | { | ||
} | ||||
|
r1638 | /*! | ||
\internal | ||||
*/ | ||||
|
r2097 | QValueAxis::QValueAxis(QValueAxisPrivate &d, QObject *parent) | ||
: QAbstractAxis(d, parent) | ||||
|
r1540 | { | ||
} | ||||
|
r1638 | /*! | ||
Destroys the object | ||||
*/ | ||||
|
r1804 | QValueAxis::~QValueAxis() | ||
|
r1540 | { | ||
|
r1804 | Q_D(QValueAxis); | ||
|
r2097 | if (d->m_dataset) | ||
|
r1725 | d->m_dataset->removeAxis(this); | ||
|
r1540 | } | ||
|
r1804 | void QValueAxis::setMin(qreal min) | ||
|
r1540 | { | ||
|
r1804 | Q_D(QValueAxis); | ||
|
r1728 | setRange(min, qMax(d->m_max, min)); | ||
|
r1540 | } | ||
|
r1804 | qreal QValueAxis::min() const | ||
|
r1540 | { | ||
|
r1804 | Q_D(const QValueAxis); | ||
|
r1540 | return d->m_min; | ||
} | ||||
|
r1804 | void QValueAxis::setMax(qreal max) | ||
|
r1540 | { | ||
|
r1804 | Q_D(QValueAxis); | ||
|
r1728 | setRange(qMin(d->m_min, max), max); | ||
|
r1540 | } | ||
|
r1804 | qreal QValueAxis::max() const | ||
|
r1540 | { | ||
|
r1804 | Q_D(const QValueAxis); | ||
|
r1540 | return d->m_max; | ||
} | ||||
/*! | ||||
Sets range from \a min to \a max on the axis. | ||||
|
r1730 | If min is greater than max then this function returns without making any changes. | ||
|
r1540 | */ | ||
|
r1804 | void QValueAxis::setRange(qreal min, qreal max) | ||
|
r1540 | { | ||
|
r1804 | Q_D(QValueAxis); | ||
|
r1578 | bool changed = false; | ||
|
r1698 | |||
|
r2097 | if (min > max) | ||
return; | ||||
|
r1738 | |||
|
r2097 | if (d->m_niceNumbers) { | ||
|
r1738 | int ticks = d->m_tickCount; | ||
d->looseNiceNumbers(min, max, ticks); | ||||
|
r2097 | if (ticks != d->m_tickCount) | ||
setTickCount(ticks); | ||||
|
r1738 | } | ||
|
r1728 | |||
|
r1578 | if (!qFuzzyIsNull(d->m_min - min)) { | ||
d->m_min = min; | ||||
changed = true; | ||||
emit minChanged(min); | ||||
} | ||||
if (!qFuzzyIsNull(d->m_max - max)) { | ||||
d->m_max = max; | ||||
changed = true; | ||||
emit maxChanged(max); | ||||
} | ||||
if (changed) { | ||||
|
r2097 | emit rangeChanged(min, max); | ||
|
r1698 | d->emitUpdated(); | ||
|
r1578 | } | ||
|
r1540 | } | ||
/*! | ||||
Sets \a count for ticks on the axis. | ||||
*/ | ||||
|
r1807 | void QValueAxis::setTickCount(int count) | ||
|
r1540 | { | ||
|
r1804 | Q_D(QValueAxis); | ||
|
r2097 | if (d->m_tickCount != count && count >= 2) { | ||
|
r1698 | d->m_tickCount = count; | ||
d->emitUpdated(); | ||||
|
r1540 | } | ||
} | ||||
/*! | ||||
|
r1812 | \fn int QValueAxis::tickCount() const | ||
|
r1540 | Return number of ticks on the axis | ||
*/ | ||||
|
r1807 | int QValueAxis::tickCount() const | ||
|
r1540 | { | ||
|
r1804 | Q_D(const QValueAxis); | ||
|
r1698 | return d->m_tickCount; | ||
|
r1540 | } | ||
|
r1804 | void QValueAxis::setNiceNumbersEnabled(bool enable) | ||
|
r1540 | { | ||
|
r1804 | Q_D(QValueAxis); | ||
|
r2097 | if (d->m_niceNumbers != enable) { | ||
|
r1540 | d->m_niceNumbers = enable; | ||
|
r2097 | if (enable && !qFuzzyIsNull(d->m_max - d->m_min)) | ||
setRange(d->m_min, d->m_max); | ||||
|
r1540 | } | ||
} | ||||
|
r1804 | bool QValueAxis::niceNumbersEnabled() const | ||
|
r1540 | { | ||
|
r1804 | Q_D(const QValueAxis); | ||
|
r1540 | return d->m_niceNumbers; | ||
} | ||||
|
r1854 | void QValueAxis::setLabelFormat(const QString &format) | ||
{ | ||||
Q_D(QValueAxis); | ||||
d->m_format = format; | ||||
} | ||||
QString QValueAxis::labelFormat() const | ||||
{ | ||||
Q_D(const QValueAxis); | ||||
return d->m_format; | ||||
} | ||||
|
r1637 | /*! | ||
Returns the type of the axis | ||||
*/ | ||||
|
r1804 | QAbstractAxis::AxisType QValueAxis::type() const | ||
|
r1540 | { | ||
|
r1818 | return AxisTypeValue; | ||
|
r1540 | } | ||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
|
r2104 | QValueAxisPrivate::QValueAxisPrivate(QValueAxis *q) | ||
: QAbstractAxisPrivate(q), | ||||
m_min(0), | ||||
m_max(0), | ||||
m_tickCount(5), | ||||
m_niceNumbers(false), | ||||
m_format(QString::null) | ||||
|
r1540 | { | ||
} | ||||
|
r1804 | QValueAxisPrivate::~QValueAxisPrivate() | ||
|
r1540 | { | ||
} | ||||
|
r1804 | void QValueAxisPrivate::handleDomainUpdated() | ||
|
r1540 | { | ||
|
r2097 | Q_Q(QValueAxis); | ||
|
r2104 | Domain *domain = qobject_cast<Domain *>(sender()); | ||
|
r2097 | Q_ASSERT(domain); | ||
if (orientation() == Qt::Horizontal) | ||||
q->setRange(domain->minX(), domain->maxX()); | ||||
else if (orientation() == Qt::Vertical) | ||||
q->setRange(domain->minY(), domain->maxY()); | ||||
|
r1540 | } | ||
|
r1544 | |||
|
r1804 | void QValueAxisPrivate::setMin(const QVariant &min) | ||
|
r1544 | { | ||
|
r1804 | Q_Q(QValueAxis); | ||
|
r1578 | bool ok; | ||
qreal value = min.toReal(&ok); | ||||
|
r2097 | if (ok) | ||
q->setMin(value); | ||||
|
r1544 | } | ||
|
r1804 | void QValueAxisPrivate::setMax(const QVariant &max) | ||
|
r1544 | { | ||
|
r1652 | |||
|
r1804 | Q_Q(QValueAxis); | ||
|
r1578 | bool ok; | ||
qreal value = max.toReal(&ok); | ||||
|
r2097 | if (ok) | ||
q->setMax(value); | ||||
|
r1544 | } | ||
|
r1804 | void QValueAxisPrivate::setRange(const QVariant &min, const QVariant &max) | ||
|
r1544 | { | ||
|
r1804 | Q_Q(QValueAxis); | ||
|
r1578 | bool ok1; | ||
bool ok2; | ||||
qreal value1 = min.toReal(&ok1); | ||||
qreal value2 = max.toReal(&ok2); | ||||
|
r2097 | if (ok1 && ok2) | ||
q->setRange(value1, value2); | ||||
|
r1544 | } | ||
|
r2104 | ChartAxis *QValueAxisPrivate::createGraphics(ChartPresenter *presenter) | ||
|
r1556 | { | ||
|
r1804 | Q_Q(QValueAxis); | ||
|
r2097 | if (m_orientation == Qt::Vertical) | ||
return new ChartValueAxisY(q, presenter); | ||||
return new ChartValueAxisX(q, presenter); | ||||
|
r1556 | } | ||
|
r2104 | void QValueAxisPrivate::intializeDomain(Domain *domain) | ||
|
r1661 | { | ||
|
r1804 | Q_Q(QValueAxis); | ||
|
r2097 | if (qFuzzyCompare(m_max, m_min)) { | ||
if (m_orientation == Qt::Vertical) | ||||
q->setRange(domain->minY(), domain->maxY()); | ||||
else | ||||
|
r1705 | q->setRange(domain->minX(), domain->maxX()); | ||
|
r1703 | } else { | ||
|
r2097 | if (m_orientation == Qt::Vertical) | ||
|
r1703 | domain->setRangeY(m_min, m_max); | ||
|
r2097 | else | ||
|
r1703 | domain->setRangeX(m_min, m_max); | ||
|
r1661 | } | ||
} | ||||
|
r1698 | //algorithm defined by Paul S.Heckbert GraphicalGems I | ||
|
r1804 | void QValueAxisPrivate::looseNiceNumbers(qreal &min, qreal &max, int &ticksCount) const | ||
|
r1698 | { | ||
|
r2097 | qreal range = niceNumber(max - min, true); //range with ceiling | ||
qreal step = niceNumber(range / (ticksCount - 1), false); | ||||
min = qFloor(min / step); | ||||
max = qCeil(max / step); | ||||
ticksCount = int(max - min) + 1; | ||||
min *= step; | ||||
max *= step; | ||||
|
r1698 | } | ||
//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n | ||||
|
r2097 | qreal QValueAxisPrivate::niceNumber(qreal x, bool ceiling) const | ||
|
r1698 | { | ||
|
r2097 | qreal z = qPow(10, qFloor(log10(x))); //find corresponding number of the form of 10^n than is smaller than x | ||
qreal q = x / z; //q<10 && q>=1; | ||||
if (ceiling) { | ||||
if (q <= 1.0) q = 1; | ||||
else if (q <= 2.0) q = 2; | ||||
else if (q <= 5.0) q = 5; | ||||
else q = 10; | ||||
} else { | ||||
if (q < 1.5) q = 1; | ||||
else if (q < 3.0) q = 2; | ||||
else if (q < 7.0) q = 5; | ||||
else q = 10; | ||||
|
r1698 | } | ||
|
r2097 | return q * z; | ||
|
r1698 | } | ||
|
r1805 | #include "moc_qvalueaxis.cpp" | ||
#include "moc_qvalueaxis_p.cpp" | ||||
|
r1540 | |||
QTCOMMERCIALCHART_END_NAMESPACE | ||||