qvaluesaxis.cpp
384 lines
| 8.8 KiB
| text/x-c
|
CppLexer
Michal Klocek
|
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$ | ||||
** | ||||
****************************************************************************/ | ||||
#include "qvaluesaxis.h" | ||||
#include "qvaluesaxis_p.h" | ||||
Marek Rosa
|
r1561 | #include "chartvaluesaxisx_p.h" | ||
#include "chartvaluesaxisy_p.h" | ||||
Michal Klocek
|
r1661 | #include "domain_p.h" | ||
Michal Klocek
|
r1725 | #include "chartdataset_p.h" | ||
#include <qmath.h> | ||||
Michal Klocek
|
r1540 | |||
QTCOMMERCIALCHART_BEGIN_NAMESPACE | ||||
Marek Rosa
|
r1547 | /*! | ||
\class QValuesAxis | ||||
\brief The QValuesAxis class is used for manipulating chart's axis. | ||||
\mainclass | ||||
sauimone
|
r1639 | ValuesAxis can be setup to show axis line with tick marks, grid lines and shades. | ||
Values of axis are drawn to position of ticks | ||||
Marek Rosa
|
r1547 | */ | ||
/*! | ||||
sauimone
|
r1639 | \qmlclass ValuesAxis QValuesAxis | ||
\brief The ValuesAxis element is used for manipulating chart's axes | ||||
Marek Rosa
|
r1547 | |||
sauimone
|
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 | ||||
Marek Rosa
|
r1547 | |||
To access Axes you can use ChartView API. For example: | ||||
\code | ||||
ChartView { | ||||
sauimone
|
r1639 | ValuesAxis { | ||
id: xAxis | ||||
min: 0 | ||||
max: 10 | ||||
} | ||||
// Add a few series... | ||||
Marek Rosa
|
r1547 | } | ||
\endcode | ||||
*/ | ||||
/*! | ||||
\property QValuesAxis::min | ||||
Defines the minimum value on the axis. | ||||
Marek Rosa
|
r1730 | When setting this property the max is adjusted if necessary, to ensure that the range remains valid. | ||
Marek Rosa
|
r1547 | */ | ||
/*! | ||||
sauimone
|
r1639 | \qmlproperty real ValuesAxis::min | ||
Marek Rosa
|
r1547 | Defines the minimum value on the axis. | ||
Marek Rosa
|
r1730 | When setting this property the max is adjusted if necessary, to ensure that the range remains valid. | ||
Marek Rosa
|
r1547 | */ | ||
/*! | ||||
\property QValuesAxis::max | ||||
Defines the maximum value on the axis. | ||||
Marek Rosa
|
r1730 | When setting this property the min is adjusted if necessary, to ensure that the range remains valid. | ||
Marek Rosa
|
r1547 | */ | ||
/*! | ||||
sauimone
|
r1639 | \qmlproperty real ValuesAxis::max | ||
Marek Rosa
|
r1547 | Defines the maximum value on the axis. | ||
Marek Rosa
|
r1730 | When setting this property the min is adjusted if necessary, to ensure that the range remains valid. | ||
Marek Rosa
|
r1547 | */ | ||
/*! | ||||
\fn void QValuesAxis::minChanged(qreal min) | ||||
Axis emits signal when \a min of axis has changed. | ||||
*/ | ||||
sauimone
|
r1654 | /*! | ||
\qmlsignal ValuesAxis::onMinChanged(real min) | ||||
Axis emits signal when \a min of axis has changed. | ||||
*/ | ||||
Marek Rosa
|
r1547 | |||
/*! | ||||
\fn void QValuesAxis::maxChanged(qreal max) | ||||
Axis emits signal when \a max of axis has changed. | ||||
*/ | ||||
sauimone
|
r1654 | /*! | ||
\qmlsignal ValuesAxis::onMaxChanged(real max) | ||||
Axis emits signal when \a max of axis has changed. | ||||
*/ | ||||
Marek Rosa
|
r1547 | |||
/*! | ||||
\fn void QValuesAxis::rangeChanged(qreal min, qreal max) | ||||
Axis emits signal when \a min or \a max of axis has changed. | ||||
*/ | ||||
Michal Klocek
|
r1540 | |||
sauimone
|
r1575 | /*! | ||
\property QValuesAxis::ticksCount | ||||
The number of tick marks for the axis. | ||||
*/ | ||||
/*! | ||||
sauimone
|
r1639 | \qmlproperty int ValuesAxis::ticksCount | ||
sauimone
|
r1575 | The number of tick marks for the axis. | ||
*/ | ||||
/*! | ||||
\property QValuesAxis::niceNumbersEnabled | ||||
Whether the nice numbers algorithm is enabled or not for the axis. | ||||
*/ | ||||
/*! | ||||
sauimone
|
r1639 | \qmlproperty bool ValuesAxis::niceNumbersEnabled | ||
sauimone
|
r1575 | Whether the nice numbers algorithm is enabled or not for the axis. | ||
*/ | ||||
Marek Rosa
|
r1636 | /*! | ||
Constructs an axis object which is a child of \a parent. | ||||
*/ | ||||
Michal Klocek
|
r1540 | QValuesAxis::QValuesAxis(QObject *parent) : | ||
QAbstractAxis(*new QValuesAxisPrivate(this),parent) | ||||
{ | ||||
} | ||||
Marek Rosa
|
r1638 | /*! | ||
\internal | ||||
*/ | ||||
Michal Klocek
|
r1540 | QValuesAxis::QValuesAxis(QValuesAxisPrivate &d,QObject *parent) : QAbstractAxis(d,parent) | ||
{ | ||||
} | ||||
Marek Rosa
|
r1638 | /*! | ||
Destroys the object | ||||
*/ | ||||
Michal Klocek
|
r1540 | QValuesAxis::~QValuesAxis() | ||
{ | ||||
Michal Klocek
|
r1725 | Q_D(QValuesAxis); | ||
if(d->m_dataset) { | ||||
d->m_dataset->removeAxis(this); | ||||
} | ||||
Michal Klocek
|
r1540 | } | ||
void QValuesAxis::setMin(qreal min) | ||||
{ | ||||
Q_D(QValuesAxis); | ||||
Marek Rosa
|
r1728 | setRange(min, qMax(d->m_max, min)); | ||
Michal Klocek
|
r1540 | } | ||
qreal QValuesAxis::min() const | ||||
{ | ||||
Q_D(const QValuesAxis); | ||||
return d->m_min; | ||||
} | ||||
void QValuesAxis::setMax(qreal max) | ||||
{ | ||||
Q_D(QValuesAxis); | ||||
Marek Rosa
|
r1728 | setRange(qMin(d->m_min, max), max); | ||
Michal Klocek
|
r1540 | } | ||
qreal QValuesAxis::max() const | ||||
{ | ||||
Q_D(const QValuesAxis); | ||||
return d->m_max; | ||||
} | ||||
/*! | ||||
Sets range from \a min to \a max on the axis. | ||||
Marek Rosa
|
r1730 | If min is greater than max then this function returns without making any changes. | ||
Michal Klocek
|
r1540 | */ | ||
void QValuesAxis::setRange(qreal min, qreal max) | ||||
{ | ||||
Q_D(QValuesAxis); | ||||
sauimone
|
r1578 | bool changed = false; | ||
Michal Klocek
|
r1698 | |||
Michal Klocek
|
r1738 | if (min > max) return; | ||
if(d->m_niceNumbers) { | ||||
int ticks = d->m_tickCount; | ||||
d->looseNiceNumbers(min, max, ticks); | ||||
if(ticks!=d->m_tickCount) setTicksCount(ticks); | ||||
} | ||||
Marek Rosa
|
r1728 | |||
sauimone
|
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) { | ||||
Michal Klocek
|
r1738 | emit rangeChanged(min,max); | ||
Michal Klocek
|
r1698 | d->emitUpdated(); | ||
sauimone
|
r1578 | } | ||
Michal Klocek
|
r1540 | } | ||
/*! | ||||
Sets \a count for ticks on the axis. | ||||
*/ | ||||
void QValuesAxis::setTicksCount(int count) | ||||
{ | ||||
Q_D(QValuesAxis); | ||||
Michal Klocek
|
r1700 | if (d->m_tickCount != count && count >=2) { | ||
Michal Klocek
|
r1698 | d->m_tickCount = count; | ||
d->emitUpdated(); | ||||
Michal Klocek
|
r1540 | } | ||
} | ||||
/*! | ||||
sauimone
|
r1575 | \fn int QValuesAxis::ticksCount() const | ||
Michal Klocek
|
r1540 | Return number of ticks on the axis | ||
*/ | ||||
int QValuesAxis::ticksCount() const | ||||
{ | ||||
Q_D(const QValuesAxis); | ||||
Michal Klocek
|
r1698 | return d->m_tickCount; | ||
Michal Klocek
|
r1540 | } | ||
void QValuesAxis::setNiceNumbersEnabled(bool enable) | ||||
{ | ||||
Q_D(QValuesAxis); | ||||
if (d->m_niceNumbers != enable){ | ||||
d->m_niceNumbers = enable; | ||||
Michal Klocek
|
r1738 | if(enable && !qFuzzyIsNull(d->m_max - d->m_min)) { | ||
setRange(d->m_min,d->m_max); | ||||
} | ||||
Michal Klocek
|
r1540 | } | ||
} | ||||
bool QValuesAxis::niceNumbersEnabled() const | ||||
{ | ||||
Q_D(const QValuesAxis); | ||||
return d->m_niceNumbers; | ||||
} | ||||
Marek Rosa
|
r1637 | /*! | ||
Returns the type of the axis | ||||
*/ | ||||
Michal Klocek
|
r1540 | QAbstractAxis::AxisType QValuesAxis::type() const | ||
{ | ||||
return AxisTypeValues; | ||||
} | ||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | ||||
QValuesAxisPrivate::QValuesAxisPrivate(QValuesAxis* q): | ||||
QAbstractAxisPrivate(q), | ||||
Michal Klocek
|
r1698 | m_min(0), | ||
m_max(0), | ||||
m_tickCount(5), | ||||
sauimone
|
r1566 | m_niceNumbers(false) | ||
Michal Klocek
|
r1540 | { | ||
} | ||||
QValuesAxisPrivate::~QValuesAxisPrivate() | ||||
{ | ||||
} | ||||
Michal Klocek
|
r1698 | void QValuesAxisPrivate::handleDomainUpdated() | ||
Michal Klocek
|
r1540 | { | ||
Q_Q(QValuesAxis); | ||||
Michal Klocek
|
r1698 | Domain* domain = qobject_cast<Domain*>(sender()); | ||
Q_ASSERT(domain); | ||||
if(orientation()==Qt::Horizontal){ | ||||
q->setRange(domain->minX(),domain->maxX()); | ||||
}else if(orientation()==Qt::Vertical){ | ||||
q->setRange(domain->minY(),domain->maxY()); | ||||
} | ||||
Michal Klocek
|
r1540 | } | ||
Michal Klocek
|
r1544 | |||
sauimone
|
r1578 | void QValuesAxisPrivate::setMin(const QVariant &min) | ||
Michal Klocek
|
r1544 | { | ||
sauimone
|
r1578 | Q_Q(QValuesAxis); | ||
bool ok; | ||||
qreal value = min.toReal(&ok); | ||||
if(ok) q->setMin(value); | ||||
Michal Klocek
|
r1544 | } | ||
sauimone
|
r1578 | void QValuesAxisPrivate::setMax(const QVariant &max) | ||
Michal Klocek
|
r1544 | { | ||
Michal Klocek
|
r1652 | |||
sauimone
|
r1578 | Q_Q(QValuesAxis); | ||
bool ok; | ||||
qreal value = max.toReal(&ok); | ||||
if(ok) q->setMax(value); | ||||
Michal Klocek
|
r1544 | } | ||
Michal Klocek
|
r1611 | void QValuesAxisPrivate::setRange(const QVariant &min, const QVariant &max) | ||
Michal Klocek
|
r1544 | { | ||
Q_Q(QValuesAxis); | ||||
sauimone
|
r1578 | bool ok1; | ||
bool ok2; | ||||
qreal value1 = min.toReal(&ok1); | ||||
qreal value2 = max.toReal(&ok2); | ||||
if(ok1&&ok2) q->setRange(value1,value2); | ||||
Michal Klocek
|
r1544 | } | ||
Michal Klocek
|
r1556 | ChartAxis* QValuesAxisPrivate::createGraphics(ChartPresenter* presenter) | ||
{ | ||||
Q_Q(QValuesAxis); | ||||
if(m_orientation == Qt::Vertical){ | ||||
Marek Rosa
|
r1561 | return new ChartValuesAxisY(q,presenter); | ||
Michal Klocek
|
r1556 | }else{ | ||
Marek Rosa
|
r1561 | return new ChartValuesAxisX(q,presenter); | ||
Michal Klocek
|
r1556 | } | ||
} | ||||
Michal Klocek
|
r1695 | void QValuesAxisPrivate::intializeDomain(Domain* domain) | ||
Michal Klocek
|
r1661 | { | ||
Michal Klocek
|
r1705 | Q_Q(QValuesAxis); | ||
sauimone
|
r1662 | if(qFuzzyCompare(m_max,m_min)) { | ||
Michal Klocek
|
r1661 | if(m_orientation==Qt::Vertical){ | ||
Michal Klocek
|
r1705 | q->setRange(domain->minY(),domain->maxY()); | ||
Michal Klocek
|
r1661 | }else{ | ||
Michal Klocek
|
r1705 | q->setRange(domain->minX(), domain->maxX()); | ||
Michal Klocek
|
r1661 | } | ||
Marek Rosa
|
r1703 | } else { | ||
if(m_orientation==Qt::Vertical){ | ||||
domain->setRangeY(m_min, m_max); | ||||
}else{ | ||||
domain->setRangeX(m_min, m_max); | ||||
} | ||||
Michal Klocek
|
r1661 | } | ||
} | ||||
Michal Klocek
|
r1698 | //algorithm defined by Paul S.Heckbert GraphicalGems I | ||
void QValuesAxisPrivate::looseNiceNumbers(qreal &min, qreal &max, int &ticksCount) const | ||||
{ | ||||
qreal range = niceNumber(max-min,true); //range with ceiling | ||||
qreal step = niceNumber(range/(ticksCount-1),false); | ||||
Michal Klocek
|
r1725 | min = qFloor(min/step); | ||
max = qCeil(max/step); | ||||
Michal Klocek
|
r1698 | ticksCount = int(max-min) +1; | ||
min*=step; | ||||
max*=step; | ||||
} | ||||
//nice numbers can be expressed as form of 1*10^n, 2* 10^n or 5*10^n | ||||
qreal QValuesAxisPrivate::niceNumber(qreal x,bool ceiling) const | ||||
{ | ||||
Michal Klocek
|
r1725 | qreal z = qPow(10,qFloor(log10(x))); //find corresponding number of the form of 10^n than is smaller than x | ||
Michal Klocek
|
r1698 | 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; | ||||
} | ||||
return q*z; | ||||
} | ||||
Michal Klocek
|
r1540 | #include "moc_qvaluesaxis.cpp" | ||
#include "moc_qvaluesaxis_p.cpp" | ||||
QTCOMMERCIALCHART_END_NAMESPACE | ||||