summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@digia.com>2013-04-16 10:07:13 +0300
committerMiikka Heikkinen <miikka.heikkinen@digia.com>2013-04-17 10:14:43 +0300
commitf494279b6366b06e3eeeb4f8c006ce76b08f10d7 (patch)
tree26951efa14e26eb0791d13ea32624e9afcf48851 /src
parent56fd46a395765db6818f890676e42cc59a9f4a81 (diff)
Add Polar chart support
This commit also heavily refactors things as polar chart needs separate implementation of various classes that previously only needed one, such as ChartAxis and ChartLayout. Task-number: QTRD-1757 Change-Id: I3d3db23920314987ceef3ae92879960b833b7136 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@digia.com>
Diffstat (limited to 'src')
-rw-r--r--src/animations/axisanimation.cpp13
-rw-r--r--src/animations/axisanimation_p.h6
-rw-r--r--src/areachart/areachartitem.cpp24
-rw-r--r--src/areachart/areachartitem_p.h10
-rw-r--r--src/axis/axis.pri38
-rw-r--r--src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp6
-rw-r--r--src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp6
-rw-r--r--src/axis/barcategoryaxis/qbarcategoryaxis.cpp4
-rw-r--r--src/axis/cartesianchartaxis.cpp197
-rw-r--r--src/axis/cartesianchartaxis_p.h79
-rw-r--r--src/axis/categoryaxis/chartcategoryaxisx.cpp17
-rw-r--r--src/axis/categoryaxis/chartcategoryaxisx_p.h8
-rw-r--r--src/axis/categoryaxis/chartcategoryaxisy.cpp17
-rw-r--r--src/axis/categoryaxis/chartcategoryaxisy_p.h8
-rw-r--r--src/axis/categoryaxis/polarchartcategoryaxisangular.cpp80
-rw-r--r--src/axis/categoryaxis/polarchartcategoryaxisangular_p.h56
-rw-r--r--src/axis/categoryaxis/polarchartcategoryaxisradial.cpp79
-rw-r--r--src/axis/categoryaxis/polarchartcategoryaxisradial_p.h56
-rw-r--r--src/axis/categoryaxis/qcategoryaxis.cpp40
-rw-r--r--src/axis/categoryaxis/qcategoryaxis.h3
-rw-r--r--src/axis/categoryaxis/qcategoryaxis_p.h3
-rw-r--r--src/axis/chartaxis.cpp547
-rw-r--r--src/axis/chartaxis_p.h201
-rw-r--r--src/axis/chartaxiselement.cpp349
-rw-r--r--src/axis/chartaxiselement_p.h151
-rw-r--r--src/axis/datetimeaxis/chartdatetimeaxisx.cpp24
-rw-r--r--src/axis/datetimeaxis/chartdatetimeaxisx_p.h1
-rw-r--r--src/axis/datetimeaxis/chartdatetimeaxisy.cpp22
-rw-r--r--src/axis/datetimeaxis/chartdatetimeaxisy_p.h1
-rw-r--r--src/axis/datetimeaxis/polarchartdatetimeaxisangular.cpp80
-rw-r--r--src/axis/datetimeaxis/polarchartdatetimeaxisangular_p.h56
-rw-r--r--src/axis/datetimeaxis/polarchartdatetimeaxisradial.cpp79
-rw-r--r--src/axis/datetimeaxis/polarchartdatetimeaxisradial_p.h56
-rw-r--r--src/axis/datetimeaxis/qdatetimeaxis.cpp21
-rw-r--r--src/axis/horizontalaxis.cpp42
-rw-r--r--src/axis/horizontalaxis_p.h6
-rw-r--r--src/axis/linearrowitem_p.h76
-rw-r--r--src/axis/logvalueaxis/chartlogvalueaxisx.cpp14
-rw-r--r--src/axis/logvalueaxis/chartlogvalueaxisx_p.h4
-rw-r--r--src/axis/logvalueaxis/chartlogvalueaxisy.cpp14
-rw-r--r--src/axis/logvalueaxis/chartlogvalueaxisy_p.h4
-rw-r--r--src/axis/logvalueaxis/polarchartlogvalueaxisangular.cpp90
-rw-r--r--src/axis/logvalueaxis/polarchartlogvalueaxisangular_p.h57
-rw-r--r--src/axis/logvalueaxis/polarchartlogvalueaxisradial.cpp95
-rw-r--r--src/axis/logvalueaxis/polarchartlogvalueaxisradial_p.h57
-rw-r--r--src/axis/logvalueaxis/qlogvalueaxis.cpp28
-rw-r--r--src/axis/polarchartaxis.cpp120
-rw-r--r--src/axis/polarchartaxis_p.h70
-rw-r--r--src/axis/polarchartaxisangular.cpp428
-rw-r--r--src/axis/polarchartaxisangular_p.h63
-rw-r--r--src/axis/polarchartaxisradial.cpp301
-rw-r--r--src/axis/polarchartaxisradial_p.h60
-rw-r--r--src/axis/qabstractaxis.cpp10
-rw-r--r--src/axis/qabstractaxis.h25
-rw-r--r--src/axis/qabstractaxis_p.h8
-rw-r--r--src/axis/valueaxis/chartvalueaxisx.cpp14
-rw-r--r--src/axis/valueaxis/chartvalueaxisx_p.h3
-rw-r--r--src/axis/valueaxis/chartvalueaxisy.cpp12
-rw-r--r--src/axis/valueaxis/chartvalueaxisy_p.h3
-rw-r--r--src/axis/valueaxis/polarchartvalueaxisangular.cpp80
-rw-r--r--src/axis/valueaxis/polarchartvalueaxisangular_p.h56
-rw-r--r--src/axis/valueaxis/polarchartvalueaxisradial.cpp79
-rw-r--r--src/axis/valueaxis/polarchartvalueaxisradial_p.h56
-rw-r--r--src/axis/valueaxis/qvalueaxis.cpp36
-rw-r--r--src/axis/verticalaxis.cpp56
-rw-r--r--src/axis/verticalaxis_p.h6
-rw-r--r--src/chartdataset.cpp207
-rw-r--r--src/chartpresenter.cpp38
-rw-r--r--src/chartpresenter_p.h19
-rw-r--r--src/domain/abstractdomain.cpp37
-rw-r--r--src/domain/abstractdomain_p.h20
-rw-r--r--src/domain/domain.pri14
-rw-r--r--src/domain/logxlogydomain.cpp31
-rw-r--r--src/domain/logxlogydomain_p.h6
-rw-r--r--src/domain/logxlogypolardomain.cpp267
-rw-r--r--src/domain/logxlogypolardomain_p.h81
-rw-r--r--src/domain/logxydomain.cpp26
-rw-r--r--src/domain/logxydomain_p.h6
-rw-r--r--src/domain/logxypolardomain.cpp236
-rw-r--r--src/domain/logxypolardomain_p.h77
-rw-r--r--src/domain/polardomain.cpp91
-rw-r--r--src/domain/polardomain_p.h62
-rw-r--r--src/domain/xlogydomain.cpp26
-rw-r--r--src/domain/xlogydomain_p.h6
-rw-r--r--src/domain/xlogypolardomain.cpp231
-rw-r--r--src/domain/xlogypolardomain_p.h77
-rw-r--r--src/domain/xydomain.cpp10
-rw-r--r--src/domain/xydomain_p.h2
-rw-r--r--src/domain/xypolardomain.cpp178
-rw-r--r--src/domain/xypolardomain_p.h65
-rw-r--r--src/layout/abstractchartlayout.cpp197
-rw-r--r--src/layout/abstractchartlayout_p.h (renamed from src/chartlayout_p.h)49
-rw-r--r--src/layout/cartesianchartlayout.cpp (renamed from src/chartlayout.cpp)188
-rw-r--r--src/layout/cartesianchartlayout_p.h50
-rw-r--r--src/layout/layout.pri12
-rw-r--r--src/layout/polarchartlayout.cpp83
-rw-r--r--src/layout/polarchartlayout_p.h50
-rw-r--r--src/legend/legendlayout.cpp2
-rw-r--r--src/legend/qlegend.cpp2
-rw-r--r--src/linechart/linechartitem.cpp249
-rw-r--r--src/linechart/linechartitem_p.h13
-rw-r--r--src/qchart.cpp71
-rw-r--r--src/qchart.h13
-rw-r--r--src/qchart_p.h6
-rw-r--r--src/qpolarchart.cpp126
-rw-r--r--src/qpolarchart.h60
-rw-r--r--src/scatterchart/scatterchartitem.cpp14
-rw-r--r--src/scatterchart/scatterchartitem_p.h2
-rw-r--r--src/splinechart/splinechartitem.cpp212
-rw-r--r--src/splinechart/splinechartitem_p.h6
-rw-r--r--src/src.pro9
-rw-r--r--src/xychart/qxyseries.cpp21
-rw-r--r--src/xychart/qxyseries.h1
-rw-r--r--src/xychart/xychart.cpp31
-rw-r--r--src/xychart/xychart_p.h7
115 files changed, 6189 insertions, 1409 deletions
diff --git a/src/animations/axisanimation.cpp b/src/animations/axisanimation.cpp
index e59d9aae..fab017e1 100644
--- a/src/animations/axisanimation.cpp
+++ b/src/animations/axisanimation.cpp
@@ -19,14 +19,15 @@
****************************************************************************/
#include "axisanimation_p.h"
-#include "chartaxis_p.h"
+#include "chartaxiselement_p.h"
+#include "qabstractaxis_p.h"
Q_DECLARE_METATYPE(QVector<qreal>)
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-AxisAnimation::AxisAnimation(ChartAxis *axis)
+AxisAnimation::AxisAnimation(ChartAxisElement *axis)
: ChartAnimation(axis),
m_axis(axis),
m_type(DefaultAnimation)
@@ -68,13 +69,13 @@ void AxisAnimation::setValues(QVector<qreal> &oldLayout, QVector<qreal> &newLayo
oldLayout.resize(newLayout.count());
for (int i = 0, j = oldLayout.count() - 1; i < (oldLayout.count() + 1) / 2; ++i, --j) {
- oldLayout[i] = m_axis->orientation() == Qt::Horizontal ? rect.left() : rect.bottom();
- oldLayout[j] = m_axis->orientation() == Qt::Horizontal ? rect.right() : rect.top();
+ oldLayout[i] = m_axis->axis()->orientation() == Qt::Horizontal ? rect.left() : rect.bottom();
+ oldLayout[j] = m_axis->axis()->orientation() == Qt::Horizontal ? rect.right() : rect.top();
}
}
break;
case ZoomInAnimation: {
- int index = qMin(oldLayout.count() * (m_axis->orientation() == Qt::Horizontal ? m_point.x() : (1 - m_point.y())), newLayout.count() - (qreal)1.0);
+ int index = qMin(oldLayout.count() * (m_axis->axis()->orientation() == Qt::Horizontal ? m_point.x() : (1 - m_point.y())), newLayout.count() - (qreal)1.0);
oldLayout.resize(newLayout.count());
for (int i = 0; i < oldLayout.count(); i++)
@@ -99,7 +100,7 @@ void AxisAnimation::setValues(QVector<qreal> &oldLayout, QVector<qreal> &newLayo
oldLayout.resize(newLayout.count());
QRectF rect = m_axis->gridGeometry();
for (int i = 0, j = oldLayout.count() - 1; i < oldLayout.count(); ++i, --j)
- oldLayout[i] = m_axis->orientation() == Qt::Horizontal ? rect.left() : rect.top();
+ oldLayout[i] = m_axis->axis()->orientation() == Qt::Horizontal ? rect.left() : rect.top();
}
break;
}
diff --git a/src/animations/axisanimation_p.h b/src/animations/axisanimation_p.h
index 6a213eae..d25cceda 100644
--- a/src/animations/axisanimation_p.h
+++ b/src/animations/axisanimation_p.h
@@ -35,13 +35,13 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-class ChartAxis;
+class ChartAxisElement;
class AxisAnimation: public ChartAnimation
{
public:
enum Animation { DefaultAnimation, ZoomOutAnimation, ZoomInAnimation, MoveForwardAnimation, MoveBackwordAnimation};
- AxisAnimation(ChartAxis *axis);
+ AxisAnimation(ChartAxisElement *axis);
~AxisAnimation();
void setAnimationType(Animation type);
void setAnimationPoint(const QPointF &point);
@@ -50,7 +50,7 @@ protected:
QVariant interpolated(const QVariant &from, const QVariant &to, qreal progress) const;
void updateCurrentValue(const QVariant &value);
private:
- ChartAxis *m_axis;
+ ChartAxisElement *m_axis;
Animation m_type;
QPointF m_point;
};
diff --git a/src/areachart/areachartitem.cpp b/src/areachart/areachartitem.cpp
index 92f89999..10adfa6f 100644
--- a/src/areachart/areachartitem.cpp
+++ b/src/areachart/areachartitem.cpp
@@ -88,12 +88,26 @@ void AreaChartItem::updatePath()
path = m_upper->path();
if (m_lower) {
+ // Note: Polarcharts always draw area correctly only when both series have equal width or are
+ // fully displayed. If one series is partally off-chart, the connecting line between
+ // the series does not attach to the end of the partially hidden series but to the point
+ // where it intersects the axis line. The problem is especially noticeable when one of the series
+ // is entirely off-chart, in which case the connecting line connects two ends of the
+ // visible series.
+ // This happens because we get the paths from linechart, which omits off-chart segments.
+ // To properly fix, linechart would need to provide true full path, in right, left, and the rest
+ // portions to enable proper clipping. However, combining those to single visually unified area
+ // would be a nightmare, since they would have to be painted separately.
path.connectPath(m_lower->path().toReversed());
} else {
QPointF first = path.pointAtPercent(0);
QPointF last = path.pointAtPercent(1);
- path.lineTo(last.x(), rect.bottom());
- path.lineTo(first.x(), rect.bottom());
+ if (presenter()->chartType() == QChart::ChartTypeCartesian) {
+ path.lineTo(last.x(), rect.bottom());
+ path.lineTo(first.x(), rect.bottom());
+ } else { // polar
+ path.lineTo(rect.center());
+ }
}
path.closeSubpath();
prepareGeometryChange();
@@ -137,7 +151,11 @@ void AreaChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
painter->save();
painter->setPen(m_linePen);
painter->setBrush(m_brush);
- painter->setClipRect(QRectF(QPointF(0,0),domain()->size()));
+ QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
+ if (presenter()->chartType() == QChart::ChartTypePolar)
+ painter->setClipRegion(QRegion(clipRect.toRect(), QRegion::Ellipse));
+ else
+ painter->setClipRect(clipRect);
painter->drawPath(m_path);
if (m_pointsVisible) {
painter->setPen(m_pointPen);
diff --git a/src/areachart/areachartitem_p.h b/src/areachart/areachartitem_p.h
index 0c09bade..60d3e07f 100644
--- a/src/areachart/areachartitem_p.h
+++ b/src/areachart/areachartitem_p.h
@@ -32,11 +32,11 @@
#include "qchartglobal.h"
#include "linechartitem_p.h"
+#include "qareaseries.h"
#include <QPen>
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-class QAreaSeries;
class AreaChartItem;
class AreaChartItem : public ChartItem
@@ -57,6 +57,8 @@ public:
void updatePath();
void setPresenter(ChartPresenter *presenter);
+ QAreaSeries *series() const { return m_series; }
+
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event);
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
@@ -89,6 +91,9 @@ public:
AreaBoundItem(AreaChartItem *area, QLineSeries *lineSeries,QGraphicsItem* item = 0)
: LineChartItem(lineSeries, item), m_item(area)
{
+ // We do not actually want to draw anything from LineChartItem.
+ // Drawing is done in AreaChartItem only.
+ setVisible(false);
}
~AreaBoundItem() {}
@@ -97,6 +102,9 @@ public:
// Turn off points drawing from component line chart item, as that
// messes up the fill for area series.
suppressPoints();
+ // Component lineseries are not necessarily themselves on the chart,
+ // so get the chart type for them from area chart.
+ forceChartType(m_item->series()->chart()->chartType());
LineChartItem::updateGeometry();
m_item->updatePath();
}
diff --git a/src/axis/axis.pri b/src/axis/axis.pri
index 264ed896..6f706aac 100644
--- a/src/axis/axis.pri
+++ b/src/axis/axis.pri
@@ -13,7 +13,8 @@ DEPENDPATH += $$PWD \
$$PWD/logvalueaxis
SOURCES += \
- $$PWD/chartaxis.cpp \
+ $$PWD/chartaxiselement.cpp \
+ $$PWD/cartesianchartaxis.cpp \
$$PWD/qabstractaxis.cpp \
$$PWD/verticalaxis.cpp \
$$PWD/horizontalaxis.cpp \
@@ -31,10 +32,12 @@ SOURCES += \
$$PWD/logvalueaxis/qlogvalueaxis.cpp
PRIVATE_HEADERS += \
- $$PWD/chartaxis_p.h \
+ $$PWD/chartaxiselement_p.h \
+ $$PWD/cartesianchartaxis_p.h \
$$PWD/qabstractaxis_p.h \
$$PWD/verticalaxis_p.h \
$$PWD/horizontalaxis_p.h \
+ $$PWD/linearrowitem_p.h \
$$PWD/valueaxis/chartvalueaxisx_p.h \
$$PWD/valueaxis/chartvalueaxisy_p.h \
$$PWD/valueaxis/qvalueaxis_p.h \
@@ -55,6 +58,29 @@ PUBLIC_HEADERS += \
$$PWD/categoryaxis/qcategoryaxis.h \
$$PWD/logvalueaxis/qlogvalueaxis.h \
+# polar
+SOURCES += \
+ $$PWD/polarchartaxis.cpp \
+ $$PWD/polarchartaxisangular.cpp \
+ $$PWD/polarchartaxisradial.cpp \
+ $$PWD/valueaxis/polarchartvalueaxisangular.cpp \
+ $$PWD/valueaxis/polarchartvalueaxisradial.cpp \
+ $$PWD/logvalueaxis/polarchartlogvalueaxisangular.cpp \
+ $$PWD/logvalueaxis/polarchartlogvalueaxisradial.cpp \
+ $$PWD/categoryaxis/polarchartcategoryaxisangular.cpp \
+ $$PWD/categoryaxis/polarchartcategoryaxisradial.cpp
+
+PRIVATE_HEADERS += \
+ $$PWD/polarchartaxis_p.h \
+ $$PWD/polarchartaxisangular_p.h \
+ $$PWD/polarchartaxisradial_p.h \
+ $$PWD/valueaxis/polarchartvalueaxisangular_p.h \
+ $$PWD/valueaxis/polarchartvalueaxisradial_p.h \
+ $$PWD/logvalueaxis/polarchartlogvalueaxisangular_p.h \
+ $$PWD/logvalueaxis/polarchartlogvalueaxisradial_p.h \
+ $$PWD/categoryaxis/polarchartcategoryaxisangular_p.h \
+ $$PWD/categoryaxis/polarchartcategoryaxisradial_p.h
+
!linux-arm*: {
INCLUDEPATH += \
$$PWD/datetimeaxis
@@ -65,12 +91,16 @@ DEPENDPATH += \
SOURCES += \
$$PWD/datetimeaxis/chartdatetimeaxisx.cpp \
$$PWD/datetimeaxis/chartdatetimeaxisy.cpp \
- $$PWD/datetimeaxis/qdatetimeaxis.cpp
+ $$PWD/datetimeaxis/qdatetimeaxis.cpp \
+ $$PWD/datetimeaxis/polarchartdatetimeaxisangular.cpp \
+ $$PWD/datetimeaxis/polarchartdatetimeaxisradial.cpp
PRIVATE_HEADERS += \
$$PWD/datetimeaxis/chartdatetimeaxisx_p.h \
$$PWD/datetimeaxis/chartdatetimeaxisy_p.h \
- $$PWD/datetimeaxis/qdatetimeaxis_p.h
+ $$PWD/datetimeaxis/qdatetimeaxis_p.h \
+ $$PWD/datetimeaxis/polarchartdatetimeaxisangular_p.h \
+ $$PWD/datetimeaxis/polarchartdatetimeaxisradial_p.h
PUBLIC_HEADERS += \
$$PWD/datetimeaxis/qdatetimeaxis.h
diff --git a/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp b/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp
index 8d86b120..9d09aebf 100644
--- a/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp
+++ b/src/axis/barcategoryaxis/chartbarcategoryaxisx.cpp
@@ -21,7 +21,7 @@
#include "chartbarcategoryaxisx_p.h"
#include "chartpresenter_p.h"
#include "qbarcategoryaxis_p.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <QFontMetrics>
#include <QDebug>
#include <qmath.h>
@@ -87,7 +87,7 @@ QStringList ChartBarCategoryAxisX::createCategoryLabels(const QVector<qreal>& la
void ChartBarCategoryAxisX::updateGeometry()
{
- const QVector<qreal>& layout = ChartAxis::layout();
+ const QVector<qreal>& layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
setLabels(createCategoryLabels(layout));
@@ -104,7 +104,7 @@ QSizeF ChartBarCategoryAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constra
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = HorizontalAxis::sizeHint(which, constraint);
QStringList ticksList = m_categoriesAxis->categories();
diff --git a/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp b/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp
index 0ca8116c..20194bbc 100644
--- a/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp
+++ b/src/axis/barcategoryaxis/chartbarcategoryaxisy.cpp
@@ -21,7 +21,7 @@
#include "chartbarcategoryaxisy_p.h"
#include "chartpresenter_p.h"
#include "qbarcategoryaxis_p.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <qmath.h>
#include <QFontMetrics>
#include <QDebug>
@@ -86,7 +86,7 @@ QStringList ChartBarCategoryAxisY::createCategoryLabels(const QVector<qreal>& la
void ChartBarCategoryAxisY::updateGeometry()
{
- const QVector<qreal>& layout = ChartAxis::layout();
+ const QVector<qreal>& layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
setLabels(createCategoryLabels(layout));
@@ -103,7 +103,7 @@ QSizeF ChartBarCategoryAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constra
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = VerticalAxis::sizeHint(which, constraint);
QStringList ticksList = m_categoriesAxis->categories();
diff --git a/src/axis/barcategoryaxis/qbarcategoryaxis.cpp b/src/axis/barcategoryaxis/qbarcategoryaxis.cpp
index 0dffff0d..0dfbea1f 100644
--- a/src/axis/barcategoryaxis/qbarcategoryaxis.cpp
+++ b/src/axis/barcategoryaxis/qbarcategoryaxis.cpp
@@ -111,7 +111,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
/*!
\fn void QBarCategoryAxis::categoriesChanged()
- Axis emits signal when the categories of the axis has changed.
+ Axis emits signal when the categories of the axis have changed.
*/
/*!
@@ -550,7 +550,7 @@ void QBarCategoryAxisPrivate::setRange(const QString &minCategory, const QStrin
void QBarCategoryAxisPrivate::initializeGraphics(QGraphicsItem* parent)
{
Q_Q(QBarCategoryAxis);
- ChartAxis* axis(0);
+ ChartAxisElement* axis(0);
if (orientation() == Qt::Vertical)
axis = new ChartBarCategoryAxisY(q,parent);
if (orientation() == Qt::Horizontal)
diff --git a/src/axis/cartesianchartaxis.cpp b/src/axis/cartesianchartaxis.cpp
new file mode 100644
index 00000000..85978202
--- /dev/null
+++ b/src/axis/cartesianchartaxis.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "cartesianchartaxis_p.h"
+#include "qabstractaxis.h"
+#include "qabstractaxis_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "abstractdomain_p.h"
+#include "linearrowitem_p.h"
+#include <QValueAxis>
+#include <QLogValueAxis>
+#include <QGraphicsLayout>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+CartesianChartAxis::CartesianChartAxis(QAbstractAxis *axis, QGraphicsItem *item , bool intervalAxis)
+ : ChartAxisElement(axis, item, intervalAxis)
+{
+ Q_ASSERT(item);
+}
+
+
+CartesianChartAxis::~CartesianChartAxis()
+{
+}
+
+void CartesianChartAxis::createItems(int count)
+{
+ if (arrowItems().size() == 0) {
+ QGraphicsLineItem *arrow = new LineArrowItem(this, this);
+ arrow->setPen(axis()->linePen());
+ arrowGroup()->addToGroup(arrow);
+ }
+
+ if (intervalAxis() && gridItems().size() == 0) {
+ for (int i = 0 ; i < 2 ; i ++){
+ QGraphicsLineItem *item = new QGraphicsLineItem(this);
+ item->setPen(axis()->gridLinePen());
+ gridGroup()->addToGroup(item);
+ }
+ }
+
+ for (int i = 0; i < count; ++i) {
+ QGraphicsLineItem *arrow = new QGraphicsLineItem(this);
+ QGraphicsLineItem *grid = new QGraphicsLineItem(this);
+ QGraphicsSimpleTextItem *label = new QGraphicsSimpleTextItem(this);
+ QGraphicsSimpleTextItem *title = titleItem();
+ arrow->setPen(axis()->linePen());
+ grid->setPen(axis()->gridLinePen());
+ label->setFont(axis()->labelsFont());
+ label->setPen(axis()->labelsPen());
+ label->setBrush(axis()->labelsBrush());
+ label->setRotation(axis()->labelsAngle());
+ title->setFont(axis()->titleFont());
+ title->setPen(axis()->titlePen());
+ title->setBrush(axis()->titleBrush());
+ title->setText(axis()->titleText());
+ arrowGroup()->addToGroup(arrow);
+ gridGroup()->addToGroup(grid);
+ labelGroup()->addToGroup(label);
+
+ if ((gridItems().size()) % 2 && gridItems().size() > 2) {
+ QGraphicsRectItem* shades = new QGraphicsRectItem(this);
+ shades->setPen(axis()->shadesPen());
+ shades->setBrush(axis()->shadesBrush());
+ shadeGroup()->addToGroup(shades);
+ }
+ }
+
+}
+
+void CartesianChartAxis::deleteItems(int count)
+{
+ QList<QGraphicsItem *> lines = gridItems();
+ QList<QGraphicsItem *> labels = labelItems();
+ QList<QGraphicsItem *> shades = shadeItems();
+ QList<QGraphicsItem *> axis = arrowItems();
+
+ for (int i = 0; i < count; ++i) {
+ if (lines.size() % 2 && lines.size() > 1)
+ delete(shades.takeLast());
+ delete(lines.takeLast());
+ delete(labels.takeLast());
+ delete(axis.takeLast());
+ }
+}
+
+void CartesianChartAxis::updateLayout(QVector<qreal> &layout)
+{
+ int diff = ChartAxisElement::layout().size() - layout.size();
+
+ if (diff > 0)
+ deleteItems(diff);
+ else if (diff < 0)
+ createItems(-diff);
+
+ if (animation()) {
+ switch (presenter()->state()) {
+ case ChartPresenter::ZoomInState:
+ animation()->setAnimationType(AxisAnimation::ZoomInAnimation);
+ animation()->setAnimationPoint(presenter()->statePoint());
+ break;
+ case ChartPresenter::ZoomOutState:
+ animation()->setAnimationType(AxisAnimation::ZoomOutAnimation);
+ animation()->setAnimationPoint(presenter()->statePoint());
+ break;
+ case ChartPresenter::ScrollUpState:
+ case ChartPresenter::ScrollLeftState:
+ animation()->setAnimationType(AxisAnimation::MoveBackwordAnimation);
+ break;
+ case ChartPresenter::ScrollDownState:
+ case ChartPresenter::ScrollRightState:
+ animation()->setAnimationType(AxisAnimation::MoveForwardAnimation);
+ break;
+ case ChartPresenter::ShowState:
+ animation()->setAnimationType(AxisAnimation::DefaultAnimation);
+ break;
+ }
+ animation()->setValues(ChartAxisElement::layout(), layout);
+ presenter()->startAnimation(animation());
+ } else {
+ setLayout(layout);
+ updateGeometry();
+ }
+}
+
+bool CartesianChartAxis::isEmpty()
+{
+ return axisGeometry().isEmpty()
+ || gridGeometry().isEmpty()
+ || qFuzzyCompare(min(), max());
+}
+
+void CartesianChartAxis::setGeometry(const QRectF &axis, const QRectF &grid)
+{
+ m_gridRect = grid;
+ setAxisGeometry(axis);
+
+ if (isEmpty())
+ return;
+
+ QVector<qreal> layout = calculateLayout();
+ updateLayout(layout);
+}
+
+QSizeF CartesianChartAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_UNUSED(which);
+ Q_UNUSED(constraint);
+ return QSizeF();
+}
+
+void CartesianChartAxis::handleArrowPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, arrowItems())
+ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
+}
+
+void CartesianChartAxis::handleGridPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, gridItems())
+ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
+}
+
+void CartesianChartAxis::handleShadesBrushChanged(const QBrush &brush)
+{
+ foreach (QGraphicsItem *item, shadeItems())
+ static_cast<QGraphicsRectItem *>(item)->setBrush(brush);
+}
+
+void CartesianChartAxis::handleShadesPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, shadeItems())
+ static_cast<QGraphicsRectItem *>(item)->setPen(pen);
+}
+
+#include "moc_cartesianchartaxis_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/cartesianchartaxis_p.h b/src/axis/cartesianchartaxis_p.h
new file mode 100644
index 00000000..51ed1326
--- /dev/null
+++ b/src/axis/cartesianchartaxis_p.h
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CARTESIANCHARTAXIS_H
+#define CARTESIANCHARTAXIS_H
+
+#include "qchartglobal.h"
+#include "chartaxiselement_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QAbstractAxis;
+
+class CartesianChartAxis : public ChartAxisElement
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsLayoutItem)
+public:
+
+ CartesianChartAxis(QAbstractAxis *axis, QGraphicsItem *item = 0, bool intervalAxis = false);
+ ~CartesianChartAxis();
+
+ void setGeometry(const QRectF &axis, const QRectF &grid);
+ QRectF gridGeometry() const { return m_gridRect; }
+ bool isEmpty();
+
+ virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+protected:
+ void setGeometry(const QRectF &size) { Q_UNUSED(size);}
+ virtual void updateGeometry() = 0;
+ void updateLayout(QVector<qreal> &layout);
+
+public Q_SLOTS:
+ virtual void handleArrowPenChanged(const QPen &pen);
+ virtual void handleGridPenChanged(const QPen &pen);
+ virtual void handleShadesBrushChanged(const QBrush &brush);
+ virtual void handleShadesPenChanged(const QPen &pen);
+
+private:
+ void createItems(int count);
+ void deleteItems(int count);
+
+private:
+ QRectF m_gridRect;
+
+ friend class AxisAnimation;
+ friend class LineArrowItem;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif /* CARTESIANCHARTAXIS_H */
diff --git a/src/axis/categoryaxis/chartcategoryaxisx.cpp b/src/axis/categoryaxis/chartcategoryaxisx.cpp
index 9c9813c4..cb1ede68 100644
--- a/src/axis/categoryaxis/chartcategoryaxisx.cpp
+++ b/src/axis/categoryaxis/chartcategoryaxisx.cpp
@@ -22,6 +22,7 @@
#include "qcategoryaxis.h"
#include "qabstractaxis.h"
#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QFontMetrics>
#include <qmath.h>
@@ -32,6 +33,7 @@ ChartCategoryAxisX::ChartCategoryAxisX(QCategoryAxis *axis, QGraphicsItem* item)
: HorizontalAxis(axis, item, true),
m_axis(axis)
{
+ QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged()));
}
ChartCategoryAxisX::~ChartCategoryAxisX()
@@ -72,16 +74,11 @@ void ChartCategoryAxisX::updateGeometry()
HorizontalAxis::updateGeometry();
}
-void ChartCategoryAxisX::handleAxisUpdated()
-{
- updateGeometry();
-}
-
QSizeF ChartCategoryAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = HorizontalAxis::sizeHint(which, constraint);
QStringList ticksList = m_axis->categoriesLabels();
@@ -114,4 +111,12 @@ QSizeF ChartCategoryAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint
return sh;
}
+void ChartCategoryAxisX::handleCategoriesChanged()
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_chartcategoryaxisx_p.cpp"
+
QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/categoryaxis/chartcategoryaxisx_p.h b/src/axis/categoryaxis/chartcategoryaxisx_p.h
index df338cc5..2fced9cf 100644
--- a/src/axis/categoryaxis/chartcategoryaxisx_p.h
+++ b/src/axis/categoryaxis/chartcategoryaxisx_p.h
@@ -35,23 +35,23 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QCategoryAxis;
-class ChartPresenter;
class ChartCategoryAxisX : public HorizontalAxis
{
+ Q_OBJECT
public:
ChartCategoryAxisX(QCategoryAxis *axis, QGraphicsItem* item = 0);
~ChartCategoryAxisX();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
+public Q_SLOTS:
+ void handleCategoriesChanged();
+
protected:
QVector<qreal> calculateLayout() const;
void updateGeometry();
-public Q_SLOTS:
- void handleAxisUpdated();
-
private:
QCategoryAxis *m_axis;
};
diff --git a/src/axis/categoryaxis/chartcategoryaxisy.cpp b/src/axis/categoryaxis/chartcategoryaxisy.cpp
index ea86b561..96f5a2d8 100644
--- a/src/axis/categoryaxis/chartcategoryaxisy.cpp
+++ b/src/axis/categoryaxis/chartcategoryaxisy.cpp
@@ -22,6 +22,7 @@
#include "qcategoryaxis.h"
#include "qabstractaxis.h"
#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QFontMetrics>
#include <qmath.h>
@@ -33,6 +34,7 @@ ChartCategoryAxisY::ChartCategoryAxisY(QCategoryAxis *axis, QGraphicsItem* item)
: VerticalAxis(axis, item, true),
m_axis(axis)
{
+ QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged()));
}
ChartCategoryAxisY::~ChartCategoryAxisY()
@@ -72,16 +74,11 @@ void ChartCategoryAxisY::updateGeometry()
VerticalAxis::updateGeometry();
}
-void ChartCategoryAxisY::handleAxisUpdated()
-{
- updateGeometry();
-}
-
QSizeF ChartCategoryAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = VerticalAxis::sizeHint(which, constraint);
QStringList ticksList = m_axis->categoriesLabels();
@@ -113,4 +110,12 @@ QSizeF ChartCategoryAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint
return sh;
}
+void ChartCategoryAxisY::handleCategoriesChanged()
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_chartcategoryaxisy_p.cpp"
+
QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/categoryaxis/chartcategoryaxisy_p.h b/src/axis/categoryaxis/chartcategoryaxisy_p.h
index a9dcbd81..20760b82 100644
--- a/src/axis/categoryaxis/chartcategoryaxisy_p.h
+++ b/src/axis/categoryaxis/chartcategoryaxisy_p.h
@@ -35,23 +35,23 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QCategoryAxis;
-class ChartPresenter;
class ChartCategoryAxisY : public VerticalAxis
{
+ Q_OBJECT
public:
ChartCategoryAxisY(QCategoryAxis *axis, QGraphicsItem* item = 0);
~ChartCategoryAxisY();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
+public Q_SLOTS:
+ void handleCategoriesChanged();
+
protected:
QVector<qreal> calculateLayout() const;
void updateGeometry();
-public Q_SLOTS:
- void handleAxisUpdated();
-
private:
QCategoryAxis *m_axis;
};
diff --git a/src/axis/categoryaxis/polarchartcategoryaxisangular.cpp b/src/axis/categoryaxis/polarchartcategoryaxisangular.cpp
new file mode 100644
index 00000000..ead087f8
--- /dev/null
+++ b/src/axis/categoryaxis/polarchartcategoryaxisangular.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartcategoryaxisangular_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "qcategoryaxis.h"
+#include <QDebug>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartCategoryAxisAngular::PolarChartCategoryAxisAngular(QCategoryAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisAngular(axis, item, true)
+{
+ QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged()));
+}
+
+PolarChartCategoryAxisAngular::~PolarChartCategoryAxisAngular()
+{
+}
+
+QVector<qreal> PolarChartCategoryAxisAngular::calculateLayout() const
+{
+ QCategoryAxis *catAxis = static_cast<QCategoryAxis *>(axis());
+ int tickCount = catAxis->categoriesLabels().count() + 1;
+ QVector<qreal> points;
+
+ if (tickCount < 2)
+ return points;
+
+ qreal range = max() - min();
+ if (range > 0) {
+ points.resize(tickCount);
+ qreal scale = 360.0 / range;
+ qreal angle;
+ for (int i = 0; i < tickCount; ++i) {
+ if (i < tickCount - 1)
+ angle = (catAxis->startValue(catAxis->categoriesLabels().at(i)) - min()) * scale;
+ else
+ angle = (catAxis->endValue(catAxis->categoriesLabels().at(i - 1)) - min()) * scale;
+ points[i] = angle;
+ }
+ }
+
+ return points;
+}
+
+void PolarChartCategoryAxisAngular::createAxisLabels(const QVector<qreal> &layout)
+{
+ Q_UNUSED(layout);
+ setLabels(static_cast<QCategoryAxis *>(axis())->categoriesLabels() << "");
+}
+
+void PolarChartCategoryAxisAngular::handleCategoriesChanged()
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+
+#include "moc_polarchartcategoryaxisangular_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/categoryaxis/polarchartcategoryaxisangular_p.h b/src/axis/categoryaxis/polarchartcategoryaxisangular_p.h
new file mode 100644
index 00000000..40d8d923
--- /dev/null
+++ b/src/axis/categoryaxis/polarchartcategoryaxisangular_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTCATEGORYAXISANGULAR_P_H
+#define POLARCHARTCATEGORYAXISANGULAR_P_H
+
+#include "polarchartaxisangular_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QCategoryAxis;
+
+class PolarChartCategoryAxisAngular : public PolarChartAxisAngular
+{
+ Q_OBJECT
+
+public:
+ PolarChartCategoryAxisAngular(QCategoryAxis *axis, QGraphicsItem *item);
+ ~PolarChartCategoryAxisAngular();
+
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+public Q_SLOTS:
+ void handleCategoriesChanged();
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTCATEGORYAXISANGULAR_P_H
diff --git a/src/axis/categoryaxis/polarchartcategoryaxisradial.cpp b/src/axis/categoryaxis/polarchartcategoryaxisradial.cpp
new file mode 100644
index 00000000..f4fe3b7b
--- /dev/null
+++ b/src/axis/categoryaxis/polarchartcategoryaxisradial.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartcategoryaxisradial_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "qcategoryaxis.h"
+#include <QDebug>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartCategoryAxisRadial::PolarChartCategoryAxisRadial(QCategoryAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisRadial(axis, item, true)
+{
+ QObject::connect(axis, SIGNAL(categoriesChanged()), this, SLOT(handleCategoriesChanged()));
+}
+
+PolarChartCategoryAxisRadial::~PolarChartCategoryAxisRadial()
+{
+}
+
+QVector<qreal> PolarChartCategoryAxisRadial::calculateLayout() const
+{
+ QCategoryAxis *catAxis = static_cast<QCategoryAxis *>(axis());
+ int tickCount = catAxis->categoriesLabels().count() + 1;
+ QVector<qreal> points;
+
+ if (tickCount < 2)
+ return points;
+
+ qreal range = max() - min();
+ if (range > 0) {
+ points.resize(tickCount);
+ qreal scale = (axisGeometry().width() / 2) / range;
+ qreal angle;
+ for (int i = 0; i < tickCount; ++i) {
+ if (i < tickCount - 1)
+ angle = (catAxis->startValue(catAxis->categoriesLabels().at(i)) - min()) * scale;
+ else
+ angle = (catAxis->endValue(catAxis->categoriesLabels().at(i - 1)) - min()) * scale;
+ points[i] = angle;
+ }
+ }
+
+ return points;
+}
+
+void PolarChartCategoryAxisRadial::createAxisLabels(const QVector<qreal> &layout)
+{
+ Q_UNUSED(layout);
+ setLabels(static_cast<QCategoryAxis *>(axis())->categoriesLabels() << "");
+}
+
+void PolarChartCategoryAxisRadial::handleCategoriesChanged()
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_polarchartcategoryaxisradial_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/categoryaxis/polarchartcategoryaxisradial_p.h b/src/axis/categoryaxis/polarchartcategoryaxisradial_p.h
new file mode 100644
index 00000000..83be8d8a
--- /dev/null
+++ b/src/axis/categoryaxis/polarchartcategoryaxisradial_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTCATEGORYAXISRADIAL_P_H
+#define POLARCHARTCATEGORYAXISRADIAL_P_H
+
+#include "polarchartaxisradial_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QCategoryAxis;
+
+class PolarChartCategoryAxisRadial : public PolarChartAxisRadial
+{
+ Q_OBJECT
+
+public:
+ PolarChartCategoryAxisRadial(QCategoryAxis *axis, QGraphicsItem *item);
+ ~PolarChartCategoryAxisRadial();
+
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+public Q_SLOTS:
+ void handleCategoriesChanged();
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTCATEGORYAXISRADIAL_P_H
diff --git a/src/axis/categoryaxis/qcategoryaxis.cpp b/src/axis/categoryaxis/qcategoryaxis.cpp
index 40d8cc25..d187da84 100644
--- a/src/axis/categoryaxis/qcategoryaxis.cpp
+++ b/src/axis/categoryaxis/qcategoryaxis.cpp
@@ -22,6 +22,8 @@
#include "qcategoryaxis_p.h"
#include "chartcategoryaxisx_p.h"
#include "chartcategoryaxisy_p.h"
+#include "polarchartcategoryaxisangular_p.h"
+#include "polarchartcategoryaxisradial_p.h"
#include "qchart.h"
#include <qmath.h>
#include <QDebug>
@@ -103,6 +105,12 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
*/
/*!
+ \fn void QCategoryAxis::categoriesChanged()
+ Axis emits signal when the categories of the axis have changed.
+*/
+
+
+/*!
Constructs an axis object which is a child of \a parent.
*/
QCategoryAxis::QCategoryAxis(QObject *parent):
@@ -151,10 +159,12 @@ void QCategoryAxis::append(const QString &categoryLabel, qreal categoryEndValue)
Range range(d->m_categoryMinimum, categoryEndValue);
d->m_categoriesMap.insert(categoryLabel, range);
d->m_categories.append(categoryLabel);
+ emit categoriesChanged();
} else if (categoryEndValue > endValue(d->m_categories.last())) {
Range previousRange = d->m_categoriesMap.value(d->m_categories.last());
d->m_categoriesMap.insert(categoryLabel, Range(previousRange.second, categoryEndValue));
d->m_categories.append(categoryLabel);
+ emit categoriesChanged();
}
}
}
@@ -169,10 +179,13 @@ void QCategoryAxis::setStartValue(qreal min)
Q_D(QCategoryAxis);
if (d->m_categories.isEmpty()) {
d->m_categoryMinimum = min;
+ emit categoriesChanged();
} else {
Range range = d->m_categoriesMap.value(d->m_categories.first());
- if (min < range.second)
+ if (min < range.second) {
d->m_categoriesMap.insert(d->m_categories.first(), Range(min, range.second));
+ emit categoriesChanged();
+ }
}
}
@@ -227,7 +240,7 @@ void QCategoryAxis::remove(const QString &categoryLabel)
d->m_categoriesMap.insert(label, range);
}
}
- //TODO:: d->emitUpdated();
+ emit categoriesChanged();
}
}
@@ -251,7 +264,7 @@ void QCategoryAxis::replaceLabel(const QString &oldLabel, const QString &newLabe
Range range = d->m_categoriesMap.value(oldLabel);
d->m_categoriesMap.remove(oldLabel);
d->m_categoriesMap.insert(newLabel, range);
- //TODO:: d->emitUpdated();
+ emit categoriesChanged();
}
}
@@ -300,14 +313,23 @@ int QCategoryAxisPrivate::ticksCount() const
return m_categories.count() + 1;
}
-void QCategoryAxisPrivate::initializeGraphics(QGraphicsItem* parent)
+void QCategoryAxisPrivate::initializeGraphics(QGraphicsItem *parent)
{
Q_Q(QCategoryAxis);
- ChartAxis* axis(0);
- if (orientation() == Qt::Vertical)
- axis = new ChartCategoryAxisY(q,parent);
- else if(orientation() == Qt::Horizontal)
- axis = new ChartCategoryAxisX(q,parent);
+ ChartAxisElement *axis(0);
+ if (m_chart->chartType() == QChart::ChartTypeCartesian) {
+ if (orientation() == Qt::Vertical)
+ axis = new ChartCategoryAxisY(q,parent);
+ else if (orientation() == Qt::Horizontal)
+ axis = new ChartCategoryAxisX(q,parent);
+ }
+
+ if (m_chart->chartType() == QChart::ChartTypePolar) {
+ if (orientation() == Qt::Vertical)
+ axis = new PolarChartCategoryAxisRadial(q, parent);
+ if (orientation() == Qt::Horizontal)
+ axis = new PolarChartCategoryAxisAngular(q, parent);
+ }
m_item.reset(axis);
QAbstractAxisPrivate::initializeGraphics(parent);
diff --git a/src/axis/categoryaxis/qcategoryaxis.h b/src/axis/categoryaxis/qcategoryaxis.h
index a7789275..73a33e21 100644
--- a/src/axis/categoryaxis/qcategoryaxis.h
+++ b/src/axis/categoryaxis/qcategoryaxis.h
@@ -57,6 +57,9 @@ public:
QStringList categoriesLabels();
int count() const;
+Q_SIGNALS:
+ void categoriesChanged();
+
private:
Q_DECLARE_PRIVATE(QCategoryAxis)
Q_DISABLE_COPY(QCategoryAxis)
diff --git a/src/axis/categoryaxis/qcategoryaxis_p.h b/src/axis/categoryaxis/qcategoryaxis_p.h
index 09d80a57..466deaef 100644
--- a/src/axis/categoryaxis/qcategoryaxis_p.h
+++ b/src/axis/categoryaxis/qcategoryaxis_p.h
@@ -48,9 +48,6 @@ public:
void initializeGraphics(QGraphicsItem* parent);
int ticksCount() const;
-Q_SIGNALS:
- void changed(qreal min, qreal max, int tickCount, bool niceNumbers);
-
private:
QMap<QString , Range> m_categoriesMap;
QStringList m_categories;
diff --git a/src/axis/chartaxis.cpp b/src/axis/chartaxis.cpp
deleted file mode 100644
index 7e565acc..00000000
--- a/src/axis/chartaxis.cpp
+++ /dev/null
@@ -1,547 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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 "chartaxis_p.h"
-#include "qabstractaxis.h"
-#include "qabstractaxis_p.h"
-#include "chartpresenter_p.h"
-#include "chartlayout_p.h"
-#include "abstractdomain_p.h"
-#include <qmath.h>
-#include <QDateTime>
-#include <QValueAxis>
-#include <QLogValueAxis>
-#include <QGraphicsLayout>
-#include <QFontMetrics>
-
-QTCOMMERCIALCHART_BEGIN_NAMESPACE
-
-ChartAxis::ChartAxis(QAbstractAxis *axis, QGraphicsItem* item , bool intervalAxis)
- : ChartElement(item),
- m_axis(axis),
- m_labelsAngle(axis->labelsAngle()),
- m_grid(new QGraphicsItemGroup(item)),
- m_arrow(new QGraphicsItemGroup(item)),
- m_shades(new QGraphicsItemGroup(item)),
- m_labels(new QGraphicsItemGroup(item)),
- m_title(new QGraphicsSimpleTextItem(item)),
- m_animation(0),
- m_labelPadding(5),
- m_intervalAxis(intervalAxis),
- m_titlePadding(3)
-{
- Q_ASSERT(item);
- //initial initialization
- m_arrow->setHandlesChildEvents(false);
- m_arrow->setZValue(ChartPresenter::AxisZValue);
- m_labels->setZValue(ChartPresenter::AxisZValue);
- m_shades->setZValue(ChartPresenter::ShadesZValue);
- m_grid->setZValue(ChartPresenter::GridZValue);
- m_title->setZValue(ChartPresenter::GridZValue);
- handleVisibleChanged(m_axis->isVisible());
- connectSlots();
-
- setFlag(QGraphicsItem::ItemHasNoContents,true);
-}
-
-void ChartAxis::connectSlots()
-{
- QObject::connect(m_axis,SIGNAL(visibleChanged(bool)),this,SLOT(handleVisibleChanged(bool)));
- QObject::connect(m_axis,SIGNAL(lineVisibleChanged(bool)),this,SLOT(handleArrowVisibleChanged(bool)));
- QObject::connect(m_axis,SIGNAL(gridVisibleChanged(bool)),this,SLOT(handleGridVisibleChanged(bool)));
- QObject::connect(m_axis,SIGNAL(labelsVisibleChanged(bool)),this,SLOT(handleLabelsVisibleChanged(bool)));
- QObject::connect(m_axis,SIGNAL(shadesVisibleChanged(bool)),this,SLOT(handleShadesVisibleChanged(bool)));
- QObject::connect(m_axis,SIGNAL(labelsAngleChanged(int)),this,SLOT(handleLabelsAngleChanged(int)));
- QObject::connect(m_axis,SIGNAL(linePenChanged(const QPen&)),this,SLOT(handleArrowPenChanged(const QPen&)));
- QObject::connect(m_axis,SIGNAL(labelsPenChanged(const QPen&)),this,SLOT(handleLabelsPenChanged(const QPen&)));
- QObject::connect(m_axis,SIGNAL(labelsBrushChanged(const QBrush&)),this,SLOT(handleLabelsBrushChanged(const QBrush&)));
- QObject::connect(m_axis,SIGNAL(labelsFontChanged(const QFont&)),this,SLOT(handleLabelsFontChanged(const QFont&)));
- QObject::connect(m_axis,SIGNAL(gridLinePenChanged(const QPen&)),this,SLOT(handleGridPenChanged(const QPen&)));
- QObject::connect(m_axis,SIGNAL(shadesPenChanged(const QPen&)),this,SLOT(handleShadesPenChanged(const QPen&)));
- QObject::connect(m_axis,SIGNAL(shadesBrushChanged(const QBrush&)),this,SLOT(handleShadesBrushChanged(const QBrush&)));
- QObject::connect(m_axis,SIGNAL(titleTextChanged(const QString&)),this,SLOT(handleTitleTextChanged(const QString&)));
- QObject::connect(m_axis,SIGNAL(titleFontChanged(const QFont&)),this,SLOT(handleTitleFontChanged(const QFont&)));
- QObject::connect(m_axis,SIGNAL(titlePenChanged(const QPen&)),this,SLOT(handleTitlePenChanged(const QPen&)));
- QObject::connect(m_axis,SIGNAL(titleBrushChanged(const QBrush&)),this,SLOT(handleTitleBrushChanged(const QBrush&)));
- QObject::connect(m_axis,SIGNAL(titleVisibleChanged(bool)),this,SLOT(handleTitleVisibleChanged(bool)));
- QObject::connect(m_axis->d_ptr.data(),SIGNAL(rangeChanged(qreal,qreal)),this,SLOT(handleRangeChanged(qreal,qreal)));
-}
-
-ChartAxis::~ChartAxis()
-{
-}
-
-void ChartAxis::setAnimation(AxisAnimation *animation)
-{
- m_animation = animation;
-}
-
-void ChartAxis::setLayout(QVector<qreal> &layout)
-{
- m_layoutVector = layout;
-}
-
-void ChartAxis::createItems(int count)
-{
- if (m_arrow->childItems().size() == 0){
- QGraphicsLineItem* arrow = new ArrowItem(this, this);
- arrow->setPen(m_axis->linePen());
- m_arrow->addToGroup(arrow);
- }
-
- if (m_intervalAxis && m_grid->childItems().size() == 0) {
- for (int i = 0 ; i < 2 ; i ++){
- QGraphicsLineItem* item = new QGraphicsLineItem(this);
- item->setPen(m_axis->gridLinePen());
- m_grid->addToGroup(item);
- }
- }
-
- for (int i = 0; i < count; ++i) {
- QGraphicsLineItem* arrow = new QGraphicsLineItem(this);
- arrow->setPen(m_axis->linePen());
- QGraphicsLineItem* grid = new QGraphicsLineItem(this);
- grid->setPen(m_axis->gridLinePen());
- QGraphicsSimpleTextItem* label = new QGraphicsSimpleTextItem(this);
- label->setFont(m_axis->labelsFont());
- label->setPen(m_axis->labelsPen());
- label->setBrush(m_axis->labelsBrush());
- label->setRotation(m_labelsAngle);
- m_arrow->addToGroup(arrow);
- m_grid->addToGroup(grid);
- m_labels->addToGroup(label);
-
- if ((m_grid->childItems().size()) % 2 && m_grid->childItems().size() > 2){
- QGraphicsRectItem* shades = new QGraphicsRectItem(this);
- shades->setPen(m_axis->shadesPen());
- shades->setBrush(m_axis->shadesBrush());
- m_shades->addToGroup(shades);
- }
- }
-
-}
-
-void ChartAxis::deleteItems(int count)
-{
- QList<QGraphicsItem *> lines = m_grid->childItems();
- QList<QGraphicsItem *> labels = m_labels->childItems();
- QList<QGraphicsItem *> shades = m_shades->childItems();
- QList<QGraphicsItem *> axis = m_arrow->childItems();
-
- for (int i = 0; i < count; ++i) {
- if (lines.size() % 2 && lines.size() > 1)
- delete(shades.takeLast());
- delete(lines.takeLast());
- delete(labels.takeLast());
- delete(axis.takeLast());
- }
-}
-
-void ChartAxis::updateLayout(QVector<qreal> &layout)
-{
- int diff = m_layoutVector.size() - layout.size();
-
- if (diff > 0)
- deleteItems(diff);
- else if (diff < 0)
- createItems(-diff);
-
- if (m_animation) {
- switch (presenter()->state()) {
- case ChartPresenter::ZoomInState:
- m_animation->setAnimationType(AxisAnimation::ZoomInAnimation);
- m_animation->setAnimationPoint(presenter()->statePoint());
- break;
- case ChartPresenter::ZoomOutState:
- m_animation->setAnimationType(AxisAnimation::ZoomOutAnimation);
- m_animation->setAnimationPoint(presenter()->statePoint());
- break;
- case ChartPresenter::ScrollUpState:
- case ChartPresenter::ScrollLeftState:
- m_animation->setAnimationType(AxisAnimation::MoveBackwordAnimation);
- break;
- case ChartPresenter::ScrollDownState:
- case ChartPresenter::ScrollRightState:
- m_animation->setAnimationType(AxisAnimation::MoveForwardAnimation);
- break;
- case ChartPresenter::ShowState:
- m_animation->setAnimationType(AxisAnimation::DefaultAnimation);
- break;
- }
- m_animation->setValues(m_layoutVector, layout);
- presenter()->startAnimation(m_animation);
- } else {
- setLayout(layout);
- updateGeometry();
- }
-}
-
-void ChartAxis::setLabelPadding(int padding)
-{
- m_labelPadding = padding;
-}
-
-void ChartAxis::setTitlePadding(int padding)
-{
- m_titlePadding = padding;
-}
-
-bool ChartAxis::isEmpty()
-{
- return m_axisRect.isEmpty() || m_gridRect.isEmpty() || qFuzzyCompare(min(),max());
-}
-
-void ChartAxis::setGeometry(const QRectF &axis, const QRectF &grid)
-{
- m_gridRect = grid;
- m_axisRect = axis;
-
- if (isEmpty())
- return;
-
- QVector<qreal> layout = calculateLayout();
- updateLayout(layout);
-}
-
-qreal ChartAxis::min() const
-{
- return m_axis->d_ptr->min();
-}
-
-qreal ChartAxis::max() const
-{
- return m_axis->d_ptr->max();
-}
-
-QFont ChartAxis::font() const
-{
- return m_axis->labelsFont();
-}
-
-QFont ChartAxis::titleFont() const
-{
- return m_axis->titleFont();
-}
-
-QString ChartAxis::titleText() const
-{
- return m_axis->titleText();
-}
-
-void ChartAxis::axisSelected()
-{
- emit clicked();
-}
-
-Qt::Orientation ChartAxis::orientation() const
-{
- return m_axis->orientation();
-}
-
-Qt::Alignment ChartAxis::alignment() const
-{
- return m_axis->alignment();
-}
-
-void ChartAxis::setLabels(const QStringList &labels)
-{
- m_labelsList = labels;
-}
-
-QSizeF ChartAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
-{
- Q_UNUSED(which);
- Q_UNUSED(constraint);
- return QSizeF();
-}
-
-//handlers
-
-void ChartAxis::handleArrowVisibleChanged(bool visible)
-{
- m_arrow->setVisible(visible);
-}
-
-void ChartAxis::handleGridVisibleChanged(bool visible)
-{
- m_grid->setVisible(visible);
-}
-
-void ChartAxis::handleLabelsVisibleChanged(bool visible)
-{
- m_labels->setVisible(visible);
-}
-
-void ChartAxis::handleShadesVisibleChanged(bool visible)
-{
- m_shades->setVisible(visible);
-}
-
-void ChartAxis::handleTitleVisibleChanged(bool visible)
-{
- QGraphicsLayoutItem::updateGeometry();
- presenter()->layout()->invalidate();
- m_title->setVisible(visible);
-}
-
-void ChartAxis::handleLabelsAngleChanged(int angle)
-{
- foreach (QGraphicsItem *item, m_labels->childItems())
- item->setRotation(angle);
-
- m_labelsAngle = angle;
-}
-
-void ChartAxis::handleLabelsPenChanged(const QPen &pen)
-{
- foreach (QGraphicsItem *item , m_labels->childItems())
- static_cast<QGraphicsSimpleTextItem *>(item)->setPen(pen);
-}
-
-void ChartAxis::handleLabelsBrushChanged(const QBrush &brush)
-{
- foreach (QGraphicsItem *item , m_labels->childItems())
- static_cast<QGraphicsSimpleTextItem *>(item)->setBrush(brush);
-}
-
-void ChartAxis::handleLabelsFontChanged(const QFont &font)
-{
- foreach (QGraphicsItem *item , m_labels->childItems())
- static_cast<QGraphicsSimpleTextItem *>(item)->setFont(font);
- QGraphicsLayoutItem::updateGeometry();
- presenter()->layout()->invalidate();
-}
-
-void ChartAxis::handleShadesBrushChanged(const QBrush &brush)
-{
- foreach (QGraphicsItem *item , m_shades->childItems())
- static_cast<QGraphicsRectItem *>(item)->setBrush(brush);
-}
-
-void ChartAxis::handleShadesPenChanged(const QPen &pen)
-{
- foreach (QGraphicsItem *item , m_shades->childItems())
- static_cast<QGraphicsRectItem *>(item)->setPen(pen);
-}
-
-void ChartAxis::handleArrowPenChanged(const QPen &pen)
-{
- foreach (QGraphicsItem *item , m_arrow->childItems())
- static_cast<QGraphicsLineItem *>(item)->setPen(pen);
-}
-
-void ChartAxis::handleGridPenChanged(const QPen &pen)
-{
- foreach (QGraphicsItem *item , m_grid->childItems())
- static_cast<QGraphicsLineItem *>(item)->setPen(pen);
-}
-
-void ChartAxis::handleTitleTextChanged(const QString &title)
-{
- QGraphicsLayoutItem::updateGeometry();
- presenter()->layout()->invalidate();
- m_title->setText(title);
-}
-
-
-void ChartAxis::handleTitlePenChanged(const QPen &pen)
-{
- m_title->setPen(pen);
-}
-
-void ChartAxis::handleTitleBrushChanged(const QBrush &brush)
-{
- m_title->setBrush(brush);
-}
-
-void ChartAxis::handleTitleFontChanged(const QFont &font)
-{
- if(m_title->font() != font){
- m_title->setFont(font);
- QGraphicsLayoutItem::updateGeometry();
- presenter()->layout()->invalidate();
- }
-}
-
-void ChartAxis::handleVisibleChanged(bool visible)
-{
- setVisible(visible);
- if(!visible) {
- m_grid->setVisible(visible);
- m_arrow->setVisible(visible);
- m_shades->setVisible(visible);
- m_labels->setVisible(visible);
- m_title->setVisible(visible);
- }else {
- m_grid->setVisible(m_axis->isGridLineVisible());
- m_arrow->setVisible(m_axis->isLineVisible());
- m_shades->setVisible(m_axis->shadesVisible());
- m_labels->setVisible(m_axis->labelsVisible());
- m_title->setVisible(m_axis->isTitleVisible());
- }
-
- if(presenter()) presenter()->layout()->invalidate();
-}
-
-void ChartAxis::handleRangeChanged(qreal min, qreal max)
-{
- Q_UNUSED(min);
- Q_UNUSED(max);
-
- if (!isEmpty()) {
-
- QVector<qreal> layout = calculateLayout();
- updateLayout(layout);
- QSizeF before = effectiveSizeHint(Qt::PreferredSize);
- QSizeF after = sizeHint(Qt::PreferredSize);
-
- if (before != after) {
- QGraphicsLayoutItem::updateGeometry();
- //we don't want to call invalidate on layout, since it will change minimum size of component,
- //which we would like to avoid since it causes nasty flips when scrolling or zooming,
- //instead recalculate layout and use plotArea for extra space.
- presenter()->layout()->setGeometry(presenter()->layout()->geometry());
- }
- }
-
-}
-
-//helpers
-
-QStringList ChartAxis::createValueLabels(qreal min, qreal max, int ticks,const QString& format)
-{
- QStringList labels;
-
- if (max <= min || ticks < 1)
- return labels;
-
- int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
- n++;
-
- if (format.isNull()) {
- for (int i = 0; i < ticks; i++) {
- qreal value = min + (i * (max - min) / (ticks - 1));
- labels << QString::number(value, 'f', n);
- }
- } else {
- QByteArray array = format.toLatin1();
- for (int i = 0; i < ticks; i++) {
- qreal value = min + (i * (max - min) / (ticks - 1));
- if (format.contains("d")
- || format.contains("i")
- || format.contains("c"))
- labels << QString().sprintf(array, (qint64)value);
- else if (format.contains("u")
- || format.contains("o")
- || format.contains("x", Qt::CaseInsensitive))
- labels << QString().sprintf(array, (quint64)value);
- else if (format.contains("f", Qt::CaseInsensitive)
- || format.contains("e", Qt::CaseInsensitive)
- || format.contains("g", Qt::CaseInsensitive))
- labels << QString().sprintf(array, value);
- else
- labels << QString();
- }
- }
-
- return labels;
-}
-
-QStringList ChartAxis::createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString& format)
-{
-// Q_ASSERT(m_max > m_min);
- // Q_ASSERT(ticks > 1);
-
- QStringList labels;
-
- int n = 0;
- if (ticks > 1)
- n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
- n++;
-
- int firstTick;
- if (base > 1)
- firstTick = ceil(log10(min) / log10(base));
- else
- firstTick = ceil(log10(max) / log10(base));
-
- if (format.isNull()) {
- for (int i = firstTick; i < ticks + firstTick; i++) {
- qreal value = qPow(base, i);
- labels << QString::number(value, 'f', n);
- }
- } else {
- QByteArray array = format.toLatin1();
- for (int i = firstTick; i < ticks + firstTick; i++) {
- qreal value = qPow(base, i);
- if (format.contains("d")
- || format.contains("i")
- || format.contains("c"))
- labels << QString().sprintf(array, (qint64)value);
- else if (format.contains("u")
- || format.contains("o")
- || format.contains("x", Qt::CaseInsensitive))
- labels << QString().sprintf(array, (quint64)value);
- else if (format.contains("f", Qt::CaseInsensitive)
- || format.contains("e", Qt::CaseInsensitive)
- || format.contains("g", Qt::CaseInsensitive))
- labels << QString().sprintf(array, value);
- else
- labels << QString();
- }
- }
-
- return labels;
-}
-
-QStringList ChartAxis::createDateTimeLabels(qreal min, qreal max,int ticks,const QString& format)
-{
- QStringList labels;
-
- if (max <= min || ticks < 1) {
- return labels;
- }
-
- int n = qMax(int(-floor(log10((max - min) / (ticks - 1)))), 0);
- n++;
- for (int i = 0; i < ticks; i++) {
- qreal value = min + (i * (max - min) / (ticks - 1));
- labels << QDateTime::fromMSecsSinceEpoch(value).toString(format);
- }
- return labels;
-}
-
-QRect ChartAxis::labelBoundingRect(const QFontMetrics &fn, const QString &label) const
-{
- QRect boundingRect = fn.boundingRect(label);
-
- // Take label rotation into account
- if (m_labelsAngle) {
- QTransform transform;
- transform.rotate(m_labelsAngle);
- boundingRect = transform.mapRect(boundingRect);
- }
-
- return boundingRect;
-}
-
-#include "moc_chartaxis_p.cpp"
-
-QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/chartaxis_p.h b/src/axis/chartaxis_p.h
deleted file mode 100644
index 681613f8..00000000
--- a/src/axis/chartaxis_p.h
+++ /dev/null
@@ -1,201 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2013 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$
-**
-****************************************************************************/
-
-// W A R N I N G
-// -------------
-//
-// This file is not part of the QtCommercial Chart API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-
-#ifndef CHARTAXIS_H
-#define CHARTAXIS_H
-
-#include "qchartglobal.h"
-#include "chartelement_p.h"
-#include "axisanimation_p.h"
-#include <QGraphicsItem>
-#include <QGraphicsLayoutItem>
-#include <QFont>
-
-QTCOMMERCIALCHART_BEGIN_NAMESPACE
-
-class QAbstractAxis;
-class ChartPresenter;
-
-class ChartAxis : public ChartElement, public QGraphicsLayoutItem
-{
- Q_OBJECT
- Q_INTERFACES(QGraphicsLayoutItem)
-public:
-
- ChartAxis(QAbstractAxis *axis, QGraphicsItem* item = 0, bool intervalAxis = false);
- ~ChartAxis();
-
- QAbstractAxis* axis() const { return m_axis; }
-
- void setLabelPadding(int padding);
- int labelPadding() const { return m_labelPadding;};
-
- void setTitlePadding(int padding);
- int titlePadding() const { return m_titlePadding;};
-
- QFont titleFont() const;
- QString titleText() const;
-
- void setLayout(QVector<qreal> &layout);
- QVector<qreal> layout() const { return m_layoutVector; }
-
- void setAnimation(AxisAnimation *animation);
- ChartAnimation *animation() const { return m_animation; };
-
- Qt::Orientation orientation() const;
- Qt::Alignment alignment() const;
-
- void setGeometry(const QRectF &axis, const QRectF &grid);
- QRectF axisGeometry() const { return m_axisRect; }
- QRectF gridGeometry() const { return m_gridRect; }
-
- void setLabels(const QStringList &labels);
- QStringList labels() const { return m_labelsList; }
-
- //this flag indicates that axis is used to show intervals it means labels are in between ticks
- bool intervalAxis() const { return m_intervalAxis; }
-
- virtual QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
-
-
- QRectF boundingRect() const{
- return QRectF();
- }
-
- void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
- {
-
- }
-
-//helpers
- static QStringList createValueLabels(qreal max, qreal min, int ticks, const QString &format);
- static QStringList createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString& format);
- static QStringList createDateTimeLabels(qreal max, qreal min, int ticks, const QString &format);
-
-protected:
- void setGeometry(const QRectF &size) { Q_UNUSED(size);};
- virtual void updateGeometry() = 0;
- virtual QVector<qreal> calculateLayout() const = 0;
-
- QList<QGraphicsItem *> lineItems() { return m_grid->childItems(); };
- QList<QGraphicsItem *> labelItems() { return m_labels->childItems();};
- QList<QGraphicsItem *> shadeItems() { return m_shades->childItems();};
- QList<QGraphicsItem *> arrowItems() { return m_arrow->childItems();};
- QGraphicsSimpleTextItem* titleItem() const { return m_title.data();}
-
- QFont font() const;
- qreal min() const;
- qreal max() const;
- QRect labelBoundingRect(const QFontMetrics &fn, const QString &label) const;
-
-//handlers
-public Q_SLOTS:
- void handleVisibleChanged(bool visible);
- void handleArrowVisibleChanged(bool visible);
- void handleGridVisibleChanged(bool visible);
- void handleLabelsVisibleChanged(bool visible);
- void handleShadesVisibleChanged(bool visible);
- void handleLabelsAngleChanged(int angle);
- void handleShadesBrushChanged(const QBrush &brush);
- void handleShadesPenChanged(const QPen &pen);
- void handleArrowPenChanged(const QPen &pen);
- void handleGridPenChanged(const QPen &pen);
- void handleLabelsPenChanged(const QPen &pen);
- void handleLabelsBrushChanged(const QBrush &brush);
- void handleLabelsFontChanged(const QFont &font);
- void handleTitlePenChanged(const QPen &pen);
- void handleTitleBrushChanged(const QBrush &brush);
- void handleTitleFontChanged(const QFont &font);
- void handleTitleTextChanged(const QString &title);
- void handleTitleVisibleChanged(bool visible);
- void handleRangeChanged(qreal min , qreal max);
-
-Q_SIGNALS:
- void clicked();
-
-private:
- inline bool isEmpty();
- void createItems(int count);
- void deleteItems(int count);
- void updateLayout(QVector<qreal> &layout);
- void axisSelected();
- void connectSlots();
-
-private:
- QAbstractAxis *m_axis;
- int m_labelsAngle;
- QRectF m_axisRect;
- QRectF m_gridRect;
- QScopedPointer<QGraphicsItemGroup> m_grid;
- QScopedPointer<QGraphicsItemGroup> m_arrow;
- QScopedPointer<QGraphicsItemGroup> m_shades;
- QScopedPointer<QGraphicsItemGroup> m_labels;
- QScopedPointer<QGraphicsSimpleTextItem> m_title;
- QVector<qreal> m_layoutVector;
- AxisAnimation *m_animation;
- int m_labelPadding;
- QStringList m_labelsList;
- bool m_intervalAxis;
- int m_titlePadding;
-
- friend class AxisAnimation;
- friend class ArrowItem;
-
-};
-
-class ArrowItem: public QGraphicsLineItem
-{
-
-public:
- explicit ArrowItem(ChartAxis *axis, QGraphicsItem *parent = 0) : QGraphicsLineItem(parent), m_axis(axis) {}
-
-protected:
- void mousePressEvent(QGraphicsSceneMouseEvent *event) {
- Q_UNUSED(event)
- m_axis->axisSelected();
- }
-
- QRectF boundingRect() const {
- return shape().boundingRect();
- }
-
- QPainterPath shape() const {
- QPainterPath path = QGraphicsLineItem::shape();
- QRectF rect = path.boundingRect();
- path.addRect(rect.adjusted(0, 0, m_axis->orientation() != Qt::Horizontal ? 8 : 0, m_axis->orientation() != Qt::Vertical ? 8 : 0));
- return path;
- }
-
-private:
- ChartAxis *m_axis;
-};
-
-QTCOMMERCIALCHART_END_NAMESPACE
-
-#endif /* CHARTAXI_H */
diff --git a/src/axis/chartaxiselement.cpp b/src/axis/chartaxiselement.cpp
new file mode 100644
index 00000000..19fa8e17
--- /dev/null
+++ b/src/axis/chartaxiselement.cpp
@@ -0,0 +1,349 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "chartaxiselement_p.h"
+#include "qabstractaxis_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include <qmath.h>
+#include <QDateTime>
+#include <QFontMetrics>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+ChartAxisElement::ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
+ : ChartElement(item),
+ m_axis(axis),
+ m_animation(0),
+ m_grid(new QGraphicsItemGroup(item)),
+ m_arrow(new QGraphicsItemGroup(item)),
+ m_shades(new QGraphicsItemGroup(item)),
+ m_labels(new QGraphicsItemGroup(item)),
+ m_title(new QGraphicsSimpleTextItem(item)),
+ m_intervalAxis(intervalAxis)
+
+{
+ //initial initialization
+ m_arrow->setHandlesChildEvents(false);
+ m_arrow->setZValue(ChartPresenter::AxisZValue);
+ m_labels->setZValue(ChartPresenter::AxisZValue);
+ m_shades->setZValue(ChartPresenter::ShadesZValue);
+ m_grid->setZValue(ChartPresenter::GridZValue);
+ m_title->setZValue(ChartPresenter::GridZValue);
+ handleVisibleChanged(axis->isVisible());
+ connectSlots();
+
+ setFlag(QGraphicsItem::ItemHasNoContents, true);
+}
+
+ChartAxisElement::~ChartAxisElement()
+{
+}
+
+void ChartAxisElement::connectSlots()
+{
+ QObject::connect(axis(), SIGNAL(visibleChanged(bool)), this, SLOT(handleVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(lineVisibleChanged(bool)), this, SLOT(handleArrowVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(gridVisibleChanged(bool)), this, SLOT(handleGridVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(labelsVisibleChanged(bool)), this, SLOT(handleLabelsVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(shadesVisibleChanged(bool)), this, SLOT(handleShadesVisibleChanged(bool)));
+ QObject::connect(axis(), SIGNAL(labelsAngleChanged(int)), this, SLOT(handleLabelsAngleChanged(int)));
+ QObject::connect(axis(), SIGNAL(linePenChanged(const QPen&)), this, SLOT(handleArrowPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(labelsPenChanged(const QPen&)), this, SLOT(handleLabelsPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(labelsBrushChanged(const QBrush&)), this, SLOT(handleLabelsBrushChanged(const QBrush&)));
+ QObject::connect(axis(), SIGNAL(labelsFontChanged(const QFont&)), this, SLOT(handleLabelsFontChanged(const QFont&)));
+ QObject::connect(axis(), SIGNAL(gridLinePenChanged(const QPen&)), this, SLOT(handleGridPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(shadesPenChanged(const QPen&)), this, SLOT(handleShadesPenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(shadesBrushChanged(const QBrush&)), this, SLOT(handleShadesBrushChanged(const QBrush&)));
+ QObject::connect(axis(), SIGNAL(titleTextChanged(const QString&)), this, SLOT(handleTitleTextChanged(const QString&)));
+ QObject::connect(axis(), SIGNAL(titleFontChanged(const QFont&)), this, SLOT(handleTitleFontChanged(const QFont&)));
+ QObject::connect(axis(), SIGNAL(titlePenChanged(const QPen&)), this, SLOT(handleTitlePenChanged(const QPen&)));
+ QObject::connect(axis(), SIGNAL(titleBrushChanged(const QBrush&)), this, SLOT(handleTitleBrushChanged(const QBrush&)));
+ QObject::connect(axis(), SIGNAL(titleVisibleChanged(bool)), this, SLOT(handleTitleVisibleChanged(bool)));
+ QObject::connect(axis()->d_ptr.data(), SIGNAL(rangeChanged(qreal, qreal)), this, SLOT(handleRangeChanged(qreal, qreal)));
+}
+
+void ChartAxisElement::handleArrowVisibleChanged(bool visible)
+{
+ m_arrow->setVisible(visible);
+}
+
+void ChartAxisElement::handleGridVisibleChanged(bool visible)
+{
+ m_grid->setVisible(visible);
+}
+
+void ChartAxisElement::handleLabelsVisibleChanged(bool visible)
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ m_labels->setVisible(visible);
+}
+
+void ChartAxisElement::handleShadesVisibleChanged(bool visible)
+{
+ m_shades->setVisible(visible);
+}
+
+void ChartAxisElement::handleTitleVisibleChanged(bool visible)
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ m_title->setVisible(visible);
+}
+
+void ChartAxisElement::handleLabelsAngleChanged(int angle)
+{
+ foreach (QGraphicsItem *item, m_labels->childItems())
+ item->setRotation(angle);
+
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+void ChartAxisElement::handleLabelsPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, m_labels->childItems())
+ static_cast<QGraphicsSimpleTextItem *>(item)->setPen(pen);
+}
+
+void ChartAxisElement::handleLabelsBrushChanged(const QBrush &brush)
+{
+ foreach (QGraphicsItem *item, m_labels->childItems())
+ static_cast<QGraphicsSimpleTextItem *>(item)->setBrush(brush);
+}
+
+void ChartAxisElement::handleLabelsFontChanged(const QFont &font)
+{
+ foreach (QGraphicsItem *item, m_labels->childItems())
+ static_cast<QGraphicsSimpleTextItem *>(item)->setFont(font);
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+}
+
+void ChartAxisElement::handleTitleTextChanged(const QString &title)
+{
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ m_title->setText(title);
+}
+
+void ChartAxisElement::handleTitlePenChanged(const QPen &pen)
+{
+ m_title->setPen(pen);
+}
+
+void ChartAxisElement::handleTitleBrushChanged(const QBrush &brush)
+{
+ m_title->setBrush(brush);
+}
+
+void ChartAxisElement::handleTitleFontChanged(const QFont &font)
+{
+ if (m_title->font() != font) {
+ m_title->setFont(font);
+ QGraphicsLayoutItem::updateGeometry();
+ presenter()->layout()->invalidate();
+ }
+}
+
+void ChartAxisElement::handleVisibleChanged(bool visible)
+{
+ setVisible(visible);
+ if (!visible) {
+ m_grid->setVisible(visible);
+ m_arrow->setVisible(visible);
+ m_shades->setVisible(visible);
+ m_labels->setVisible(visible);
+ m_title->setVisible(visible);
+ } else {
+ m_grid->setVisible(axis()->isGridLineVisible());
+ m_arrow->setVisible(axis()->isLineVisible());
+ m_shades->setVisible(axis()->shadesVisible());
+ m_labels->setVisible(axis()->labelsVisible());
+ m_title->setVisible(axis()->isTitleVisible());
+ }
+
+ if (presenter()) presenter()->layout()->invalidate();
+}
+
+QRect ChartAxisElement::labelBoundingRect(const QFontMetrics &fn, const QString &label) const
+{
+ QRect boundingRect = fn.boundingRect(label);
+ // Take label rotation into account
+ if (axis()->labelsAngle()) {
+ QTransform transform;
+ transform.rotate(axis()->labelsAngle());
+ boundingRect = transform.mapRect(boundingRect);
+ }
+
+ return boundingRect;
+}
+
+void ChartAxisElement::handleRangeChanged(qreal min, qreal max)
+{
+ Q_UNUSED(min);
+ Q_UNUSED(max);
+
+ if (!isEmpty()) {
+ QVector<qreal> layout = calculateLayout();
+ updateLayout(layout);
+ QSizeF before = effectiveSizeHint(Qt::PreferredSize);
+ QSizeF after = sizeHint(Qt::PreferredSize);
+
+ if (before != after) {
+ QGraphicsLayoutItem::updateGeometry();
+ // We don't want to call invalidate on layout, since it will change minimum size of
+ // component, which we would like to avoid since it causes nasty flips when scrolling
+ // or zooming, instead recalculate layout and use plotArea for extra space.
+ presenter()->layout()->setGeometry(presenter()->layout()->geometry());
+ }
+ }
+}
+
+bool ChartAxisElement::isEmpty()
+{
+ return axisGeometry().isEmpty()
+ || gridGeometry().isEmpty()
+ || qFuzzyCompare(min(), max());
+}
+
+qreal ChartAxisElement::min() const
+{
+ return m_axis->d_ptr->min();
+}
+
+qreal ChartAxisElement::max() const
+{
+ return m_axis->d_ptr->max();
+}
+
+QStringList ChartAxisElement::createValueLabels(qreal min, qreal max, int ticks, const QString &format)
+{
+ QStringList labels;
+
+ if (max <= min || ticks < 1)
+ return labels;
+
+ int n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
+ n++;
+
+ if (format.isNull()) {
+ for (int i = 0; i < ticks; i++) {
+ qreal value = min + (i * (max - min) / (ticks - 1));
+ labels << QString::number(value, 'f', n);
+ }
+ } else {
+ QByteArray array = format.toLatin1();
+ for (int i = 0; i < ticks; i++) {
+ qreal value = min + (i * (max - min) / (ticks - 1));
+ if (format.contains("d")
+ || format.contains("i")
+ || format.contains("c")) {
+ labels << QString().sprintf(array, (qint64)value);
+ } else if (format.contains("u")
+ || format.contains("o")
+ || format.contains("x", Qt::CaseInsensitive)) {
+ labels << QString().sprintf(array, (quint64)value);
+ } else if (format.contains("f", Qt::CaseInsensitive)
+ || format.contains("e", Qt::CaseInsensitive)
+ || format.contains("g", Qt::CaseInsensitive)) {
+ labels << QString().sprintf(array, value);
+ } else {
+ labels << QString();
+ }
+ }
+ }
+
+ return labels;
+}
+
+QStringList ChartAxisElement::createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format)
+{
+ QStringList labels;
+
+ if (max <= min || ticks < 1)
+ return labels;
+
+ int n = 0;
+ if (ticks > 1)
+ n = qMax(int(-qFloor(log10((max - min) / (ticks - 1)))), 0);
+ n++;
+
+ int firstTick;
+ if (base > 1)
+ firstTick = ceil(log10(min) / log10(base));
+ else
+ firstTick = ceil(log10(max) / log10(base));
+
+ if (format.isNull()) {
+ for (int i = firstTick; i < ticks + firstTick; i++) {
+ qreal value = qPow(base, i);
+ labels << QString::number(value, 'f', n);
+ }
+ } else {
+ QByteArray array = format.toLatin1();
+ for (int i = firstTick; i < ticks + firstTick; i++) {
+ qreal value = qPow(base, i);
+ if (format.contains("d")
+ || format.contains("i")
+ || format.contains("c")) {
+ labels << QString().sprintf(array, (qint64)value);
+ } else if (format.contains("u")
+ || format.contains("o")
+ || format.contains("x", Qt::CaseInsensitive)) {
+ labels << QString().sprintf(array, (quint64)value);
+ } else if (format.contains("f", Qt::CaseInsensitive)
+ || format.contains("e", Qt::CaseInsensitive)
+ || format.contains("g", Qt::CaseInsensitive)) {
+ labels << QString().sprintf(array, value);
+ } else {
+ labels << QString();
+ }
+ }
+ }
+
+ return labels;
+}
+
+QStringList ChartAxisElement::createDateTimeLabels(qreal min, qreal max,int ticks,const QString &format)
+{
+ QStringList labels;
+
+ if (max <= min || ticks < 1)
+ return labels;
+
+ int n = qMax(int(-floor(log10((max - min) / (ticks - 1)))), 0);
+ n++;
+ for (int i = 0; i < ticks; i++) {
+ qreal value = min + (i * (max - min) / (ticks - 1));
+ labels << QDateTime::fromMSecsSinceEpoch(value).toString(format);
+ }
+ return labels;
+}
+
+void ChartAxisElement::axisSelected()
+{
+ emit clicked();
+}
+
+#include "moc_chartaxiselement_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/chartaxiselement_p.h b/src/axis/chartaxiselement_p.h
new file mode 100644
index 00000000..0fdd207d
--- /dev/null
+++ b/src/axis/chartaxiselement_p.h
@@ -0,0 +1,151 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CHARTAXISELEMENT_H
+#define CHARTAXISELEMENT_H
+
+#include "qchartglobal.h"
+#include "chartelement_p.h"
+#include "axisanimation_p.h"
+#include <QGraphicsItem>
+#include <QGraphicsLayoutItem>
+#include <QFont>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class ChartPresenter;
+class QAbstractAxis;
+
+class ChartAxisElement : public ChartElement, public QGraphicsLayoutItem
+{
+ Q_OBJECT
+public:
+ ChartAxisElement(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false);
+ ~ChartAxisElement();
+
+ virtual QRectF gridGeometry() const = 0;
+ virtual void setGeometry(const QRectF &axis, const QRectF &grid) = 0;
+ virtual bool isEmpty() = 0;
+
+ void setAnimation(AxisAnimation *animation) { m_animation = animation; }
+ AxisAnimation *animation() const { return m_animation; }
+
+ QAbstractAxis *axis() const { return m_axis; }
+ void setLayout(QVector<qreal> &layout) { m_layout = layout; }
+ QVector<qreal> &layout() { return m_layout; } // Modifiable reference
+ int labelPadding() const { return 5; }
+ int titlePadding() const { return 3; }
+ void setLabels(const QStringList &labels) { m_labelsList = labels; }
+ QStringList labels() const { return m_labelsList; }
+
+ qreal min() const;
+ qreal max() const;
+
+ QRectF axisGeometry() const { return m_axisRect; }
+ void setAxisGeometry(const QRectF &axisGeometry) { m_axisRect = axisGeometry; }
+
+ QRect labelBoundingRect(const QFontMetrics &fn, const QString &label) const;
+
+ void axisSelected();
+
+ //this flag indicates that axis is used to show intervals it means labels are in between ticks
+ bool intervalAxis() const { return m_intervalAxis; }
+
+ static QStringList createValueLabels(qreal max, qreal min, int ticks, const QString &format);
+ static QStringList createLogValueLabels(qreal min, qreal max, qreal base, int ticks, const QString &format);
+ static QStringList createDateTimeLabels(qreal max, qreal min, int ticks, const QString &format);
+
+ // from QGraphicsLayoutItem
+ QRectF boundingRect() const
+ {
+ return QRectF();
+ }
+
+ // from QGraphicsLayoutItem
+ void paint(QPainter*, const QStyleOptionGraphicsItem*, QWidget*)
+ {
+ }
+
+protected:
+ virtual QVector<qreal> calculateLayout() const = 0;
+ virtual void updateLayout(QVector<qreal> &layout) = 0;
+
+ QList<QGraphicsItem *> gridItems() { return m_grid->childItems(); }
+ QList<QGraphicsItem *> labelItems() { return m_labels->childItems(); }
+ QList<QGraphicsItem *> shadeItems() { return m_shades->childItems(); }
+ QList<QGraphicsItem *> arrowItems() { return m_arrow->childItems(); }
+ QGraphicsSimpleTextItem *titleItem() const { return m_title.data(); }
+ QGraphicsItemGroup *gridGroup() { return m_grid.data(); }
+ QGraphicsItemGroup *labelGroup() { return m_labels.data(); }
+ QGraphicsItemGroup *shadeGroup() { return m_shades.data(); }
+ QGraphicsItemGroup *arrowGroup() { return m_arrow.data(); }
+
+public Q_SLOTS:
+ void handleVisibleChanged(bool visible);
+ void handleArrowVisibleChanged(bool visible);
+ void handleGridVisibleChanged(bool visible);
+ void handleLabelsVisibleChanged(bool visible);
+ void handleShadesVisibleChanged(bool visible);
+ void handleLabelsAngleChanged(int angle);
+ virtual void handleShadesBrushChanged(const QBrush &brush) = 0;
+ virtual void handleShadesPenChanged(const QPen &pen) = 0;
+ virtual void handleArrowPenChanged(const QPen &pen) = 0;
+ virtual void handleGridPenChanged(const QPen &pen) = 0;
+ void handleLabelsPenChanged(const QPen &pen);
+ void handleLabelsBrushChanged(const QBrush &brush);
+ void handleLabelsFontChanged(const QFont &font);
+ void handleTitlePenChanged(const QPen &pen);
+ void handleTitleBrushChanged(const QBrush &brush);
+ void handleTitleFontChanged(const QFont &font);
+ void handleTitleTextChanged(const QString &title);
+ void handleTitleVisibleChanged(bool visible);
+ void handleRangeChanged(qreal min, qreal max);
+
+Q_SIGNALS:
+ void clicked();
+
+private:
+ void connectSlots();
+
+ QAbstractAxis *m_axis;
+ AxisAnimation *m_animation;
+ QVector<qreal> m_layout;
+ QStringList m_labelsList;
+ QRectF m_axisRect;
+ QScopedPointer<QGraphicsItemGroup> m_grid;
+ QScopedPointer<QGraphicsItemGroup> m_arrow;
+ QScopedPointer<QGraphicsItemGroup> m_shades;
+ QScopedPointer<QGraphicsItemGroup> m_labels;
+ QScopedPointer<QGraphicsSimpleTextItem> m_title;
+ bool m_intervalAxis;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif /* CHARTAXISELEMENT_H */
diff --git a/src/axis/datetimeaxis/chartdatetimeaxisx.cpp b/src/axis/datetimeaxis/chartdatetimeaxisx.cpp
index 39fc3ba7..6ff32c5e 100644
--- a/src/axis/datetimeaxis/chartdatetimeaxisx.cpp
+++ b/src/axis/datetimeaxis/chartdatetimeaxisx.cpp
@@ -21,7 +21,7 @@
#include "chartdatetimeaxisx_p.h"
#include "chartpresenter_p.h"
#include "qdatetimeaxis.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QDateTime>
#include <QFontMetrics>
@@ -29,12 +29,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ChartDateTimeAxisX::ChartDateTimeAxisX(QDateTimeAxis *axis, QGraphicsItem* item)
+ChartDateTimeAxisX::ChartDateTimeAxisX(QDateTimeAxis *axis, QGraphicsItem *item)
: HorizontalAxis(axis, item),
m_axis(axis)
{
- QObject::connect(m_axis,SIGNAL(tickCountChanged(int)),this, SLOT(handleTickCountChanged(int)));
- QObject::connect(m_axis,SIGNAL(formatChanged(QString)),this, SLOT(handleFormatChanged(QString)));
+ QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(m_axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString)));
}
ChartDateTimeAxisX::~ChartDateTimeAxisX()
@@ -58,10 +58,10 @@ QVector<qreal> ChartDateTimeAxisX::calculateLayout() const
void ChartDateTimeAxisX::updateGeometry()
{
- const QVector<qreal>& layout = ChartAxis::layout();
+ const QVector<qreal>& layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
- setLabels(createDateTimeLabels(min(),max(), layout.size(),m_axis->format()));
+ setLabels(createDateTimeLabels(min(), max(), layout.size(), m_axis->format()));
HorizontalAxis::updateGeometry();
}
@@ -69,25 +69,27 @@ void ChartDateTimeAxisX::handleTickCountChanged(int tick)
{
Q_UNUSED(tick)
QGraphicsLayoutItem::updateGeometry();
- if(presenter()) presenter()->layout()->invalidate();
+ if (presenter())
+ presenter()->layout()->invalidate();
}
void ChartDateTimeAxisX::handleFormatChanged(const QString &format)
{
Q_UNUSED(format);
QGraphicsLayoutItem::updateGeometry();
- if(presenter()) presenter()->layout()->invalidate();
+ if (presenter())
+ presenter()->layout()->invalidate();
}
QSizeF ChartDateTimeAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = HorizontalAxis::sizeHint(which, constraint);
- QStringList ticksList = createDateTimeLabels(min(),max(),m_axis->tickCount(),m_axis->format());
+ QStringList ticksList = createDateTimeLabels(min(), max(), m_axis->tickCount(), m_axis->format());
// Width of horizontal axis sizeHint indicates the maximum distance labels can extend past
// first and last ticks. Base width is irrelevant.
qreal width = 0;
@@ -97,7 +99,7 @@ QSizeF ChartDateTimeAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint
return sh;
switch (which) {
- case Qt::MinimumSize:{
+ case Qt::MinimumSize: {
QRectF boundingRect = labelBoundingRect(fn, "...");
width = boundingRect.width() / 2.0;
height = boundingRect.height() + labelPadding();
diff --git a/src/axis/datetimeaxis/chartdatetimeaxisx_p.h b/src/axis/datetimeaxis/chartdatetimeaxisx_p.h
index 841ae1ea..03fe98bb 100644
--- a/src/axis/datetimeaxis/chartdatetimeaxisx_p.h
+++ b/src/axis/datetimeaxis/chartdatetimeaxisx_p.h
@@ -35,7 +35,6 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QDateTimeAxis;
-class ChartPresenter;
class ChartDateTimeAxisX : public HorizontalAxis
{
diff --git a/src/axis/datetimeaxis/chartdatetimeaxisy.cpp b/src/axis/datetimeaxis/chartdatetimeaxisy.cpp
index a534617f..a8fe58a2 100644
--- a/src/axis/datetimeaxis/chartdatetimeaxisy.cpp
+++ b/src/axis/datetimeaxis/chartdatetimeaxisy.cpp
@@ -21,7 +21,7 @@
#include "chartdatetimeaxisy_p.h"
#include "chartpresenter_p.h"
#include "qdatetimeaxis.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QFontMetrics>
#include <QDateTime>
@@ -29,12 +29,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ChartDateTimeAxisY::ChartDateTimeAxisY(QDateTimeAxis *axis, QGraphicsItem* item)
+ChartDateTimeAxisY::ChartDateTimeAxisY(QDateTimeAxis *axis, QGraphicsItem *item)
: VerticalAxis(axis, item),
m_axis(axis)
{
- QObject::connect(m_axis,SIGNAL(tickCountChanged(int)),this, SLOT(handleTickCountChanged(int)));
- QObject::connect(m_axis,SIGNAL(formatChanged(QString)),this, SLOT(handleFormatChanged(QString)));
+ QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(m_axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString)));
}
ChartDateTimeAxisY::~ChartDateTimeAxisY()
@@ -59,10 +59,10 @@ QVector<qreal> ChartDateTimeAxisY::calculateLayout() const
void ChartDateTimeAxisY::updateGeometry()
{
- const QVector<qreal> &layout = ChartAxis::layout();
+ const QVector<qreal> &layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
- setLabels(createDateTimeLabels(min(),max(), layout.size(),m_axis->format()));
+ setLabels(createDateTimeLabels(min(), max(), layout.size(), m_axis->format()));
VerticalAxis::updateGeometry();
}
@@ -70,25 +70,27 @@ void ChartDateTimeAxisY::handleTickCountChanged(int tick)
{
Q_UNUSED(tick)
QGraphicsLayoutItem::updateGeometry();
- if(presenter()) presenter()->layout()->invalidate();
+ if (presenter())
+ presenter()->layout()->invalidate();
}
void ChartDateTimeAxisY::handleFormatChanged(const QString &format)
{
Q_UNUSED(format);
QGraphicsLayoutItem::updateGeometry();
- if(presenter()) presenter()->layout()->invalidate();
+ if (presenter())
+ presenter()->layout()->invalidate();
}
QSizeF ChartDateTimeAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = VerticalAxis::sizeHint(which, constraint);
- QStringList ticksList = createDateTimeLabels(min(),max(),m_axis->tickCount(),m_axis->format());
+ QStringList ticksList = createDateTimeLabels(min(), max(), m_axis->tickCount(), m_axis->format());
qreal width = 0;
// Height of vertical axis sizeHint indicates the maximum distance labels can extend past
// first and last ticks. Base height is irrelevant.
diff --git a/src/axis/datetimeaxis/chartdatetimeaxisy_p.h b/src/axis/datetimeaxis/chartdatetimeaxisy_p.h
index 0bbe0d5a..be3adc54 100644
--- a/src/axis/datetimeaxis/chartdatetimeaxisy_p.h
+++ b/src/axis/datetimeaxis/chartdatetimeaxisy_p.h
@@ -35,7 +35,6 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QDateTimeAxis;
-class ChartPresenter;
class ChartDateTimeAxisY : public VerticalAxis
{
diff --git a/src/axis/datetimeaxis/polarchartdatetimeaxisangular.cpp b/src/axis/datetimeaxis/polarchartdatetimeaxisangular.cpp
new file mode 100644
index 00000000..6b1d86af
--- /dev/null
+++ b/src/axis/datetimeaxis/polarchartdatetimeaxisangular.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartdatetimeaxisangular_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "qdatetimeaxis.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartDateTimeAxisAngular::PolarChartDateTimeAxisAngular(QDateTimeAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisAngular(axis, item)
+{
+ QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString)));
+}
+
+PolarChartDateTimeAxisAngular::~PolarChartDateTimeAxisAngular()
+{
+}
+
+QVector<qreal> PolarChartDateTimeAxisAngular::calculateLayout() const
+{
+ int tickCount = static_cast<QDateTimeAxis *>(axis())->tickCount();
+ Q_ASSERT(tickCount >= 2);
+
+ QVector<qreal> points;
+ points.resize(tickCount);
+
+ const qreal d = 360.0 / qreal(tickCount - 1);
+
+ for (int i = 0; i < tickCount; ++i) {
+ qreal angularCoordinate = qreal(i) * d;
+ points[i] = angularCoordinate;
+ }
+
+ return points;
+}
+void PolarChartDateTimeAxisAngular::createAxisLabels(const QVector<qreal> &layout)
+{
+ QStringList labelList = createDateTimeLabels(min(), max(), layout.size(), static_cast<QDateTimeAxis *>(axis())->format());
+ setLabels(labelList);
+}
+
+void PolarChartDateTimeAxisAngular::handleTickCountChanged(int tick)
+{
+ Q_UNUSED(tick);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+void PolarChartDateTimeAxisAngular::handleFormatChanged(const QString &format)
+{
+ Q_UNUSED(format);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_polarchartdatetimeaxisangular_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/datetimeaxis/polarchartdatetimeaxisangular_p.h b/src/axis/datetimeaxis/polarchartdatetimeaxisangular_p.h
new file mode 100644
index 00000000..9a7ecffe
--- /dev/null
+++ b/src/axis/datetimeaxis/polarchartdatetimeaxisangular_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTDATETIMEAXISANGULAR_P_H
+#define POLARCHARTDATETIMEAXISANGULAR_P_H
+
+#include "polarchartaxisangular_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QDateTimeAxis;
+
+class PolarChartDateTimeAxisAngular : public PolarChartAxisAngular
+{
+ Q_OBJECT
+public:
+ PolarChartDateTimeAxisAngular(QDateTimeAxis *axis, QGraphicsItem *item);
+ ~PolarChartDateTimeAxisAngular();
+
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+private Q_SLOTS:
+ void handleTickCountChanged(int tick);
+ void handleFormatChanged(const QString &format);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTDATETIMEAXISANGULAR_P_H
diff --git a/src/axis/datetimeaxis/polarchartdatetimeaxisradial.cpp b/src/axis/datetimeaxis/polarchartdatetimeaxisradial.cpp
new file mode 100644
index 00000000..bcd04283
--- /dev/null
+++ b/src/axis/datetimeaxis/polarchartdatetimeaxisradial.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartdatetimeaxisradial_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "qdatetimeaxis.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartDateTimeAxisRadial::PolarChartDateTimeAxisRadial(QDateTimeAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisRadial(axis, item)
+{
+ QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(axis, SIGNAL(formatChanged(QString)), this, SLOT(handleFormatChanged(QString)));
+}
+
+PolarChartDateTimeAxisRadial::~PolarChartDateTimeAxisRadial()
+{
+}
+
+QVector<qreal> PolarChartDateTimeAxisRadial::calculateLayout() const
+{
+ int tickCount = static_cast<QDateTimeAxis *>(axis())->tickCount();
+ Q_ASSERT(tickCount >= 2);
+
+ QVector<qreal> points;
+ points.resize(tickCount);
+
+ const qreal d = (axisGeometry().width() / 2) / qreal(tickCount - 1);
+
+ for (int i = 0; i < tickCount; ++i) {
+ qreal radialCoordinate = qreal(i) * d;
+ points[i] = radialCoordinate;
+ }
+
+ return points;
+}
+void PolarChartDateTimeAxisRadial::createAxisLabels(const QVector<qreal> &layout)
+{
+ setLabels(createDateTimeLabels(min(), max(), layout.size(), static_cast<QDateTimeAxis *>(axis())->format()));
+}
+
+void PolarChartDateTimeAxisRadial::handleTickCountChanged(int tick)
+{
+ Q_UNUSED(tick);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+void PolarChartDateTimeAxisRadial::handleFormatChanged(const QString &format)
+{
+ Q_UNUSED(format);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_polarchartdatetimeaxisradial_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/datetimeaxis/polarchartdatetimeaxisradial_p.h b/src/axis/datetimeaxis/polarchartdatetimeaxisradial_p.h
new file mode 100644
index 00000000..e10e9194
--- /dev/null
+++ b/src/axis/datetimeaxis/polarchartdatetimeaxisradial_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTDATETIMEAXISRADIAL_P_H
+#define POLARCHARTDATETIMEAXISRADIAL_P_H
+
+#include "polarchartaxisradial_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QDateTimeAxis;
+
+class PolarChartDateTimeAxisRadial : public PolarChartAxisRadial
+{
+ Q_OBJECT
+public:
+ PolarChartDateTimeAxisRadial(QDateTimeAxis *axis, QGraphicsItem *item);
+ ~PolarChartDateTimeAxisRadial();
+
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+private Q_SLOTS:
+ void handleTickCountChanged(int tick);
+ void handleFormatChanged(const QString &format);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTDATETIMEAXISRADIAL_P_H
diff --git a/src/axis/datetimeaxis/qdatetimeaxis.cpp b/src/axis/datetimeaxis/qdatetimeaxis.cpp
index 3e00ee90..ed1b4a1c 100644
--- a/src/axis/datetimeaxis/qdatetimeaxis.cpp
+++ b/src/axis/datetimeaxis/qdatetimeaxis.cpp
@@ -22,6 +22,8 @@
#include "qdatetimeaxis_p.h"
#include "chartdatetimeaxisx_p.h"
#include "chartdatetimeaxisy_p.h"
+#include "polarchartdatetimeaxisangular_p.h"
+#include "polarchartdatetimeaxisradial_p.h"
#include "abstractdomain_p.h"
#include "qchart.h"
#include <float.h>
@@ -342,11 +344,20 @@ void QDateTimeAxisPrivate::setRange(const QVariant &min, const QVariant &max)
void QDateTimeAxisPrivate::initializeGraphics(QGraphicsItem* parent)
{
Q_Q(QDateTimeAxis);
- ChartAxis* axis(0);
- if (orientation() == Qt::Vertical)
- axis = new ChartDateTimeAxisY(q,parent);
- if (orientation() == Qt::Horizontal)
- axis = new ChartDateTimeAxisX(q,parent);
+ ChartAxisElement *axis(0);
+ if (m_chart->chartType() == QChart::ChartTypeCartesian) {
+ if (orientation() == Qt::Vertical)
+ axis = new ChartDateTimeAxisY(q,parent);
+ if (orientation() == Qt::Horizontal)
+ axis = new ChartDateTimeAxisX(q,parent);
+ }
+
+ if (m_chart->chartType() == QChart::ChartTypePolar) {
+ if (orientation() == Qt::Vertical)
+ axis = new PolarChartDateTimeAxisRadial(q, parent);
+ if (orientation() == Qt::Horizontal)
+ axis = new PolarChartDateTimeAxisAngular(q, parent);
+ }
m_item.reset(axis);
QAbstractAxisPrivate::initializeGraphics(parent);
diff --git a/src/axis/horizontalaxis.cpp b/src/axis/horizontalaxis.cpp
index 9dcd7750..7068d597 100644
--- a/src/axis/horizontalaxis.cpp
+++ b/src/axis/horizontalaxis.cpp
@@ -19,15 +19,15 @@
****************************************************************************/
#include "horizontalaxis_p.h"
-#include "qabstractaxis.h"
+#include "qabstractaxis_p.h"
#include <QFontMetrics>
#include <qmath.h>
#include <QDebug>
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem* item , bool intervalAxis)
- : ChartAxis(axis, item, intervalAxis)
+HorizontalAxis::HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
+ : CartesianChartAxis(axis, item, intervalAxis)
{
}
@@ -37,18 +37,18 @@ HorizontalAxis::~HorizontalAxis()
void HorizontalAxis::updateGeometry()
{
- const QVector<qreal>& layout = ChartAxis::layout();
+ const QVector<qreal> &layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
QStringList labelList = labels();
- QList<QGraphicsItem *> lines = lineItems();
+ QList<QGraphicsItem *> lines = gridItems();
QList<QGraphicsItem *> labels = labelItems();
QList<QGraphicsItem *> shades = shadeItems();
- QList<QGraphicsItem *> axis = arrowItems();
- QGraphicsSimpleTextItem* title = titleItem();
+ QList<QGraphicsItem *> arrow = arrowItems();
+ QGraphicsSimpleTextItem *title = titleItem();
Q_ASSERT(labels.size() == labelList.size());
Q_ASSERT(layout.size() == labelList.size());
@@ -57,24 +57,24 @@ void HorizontalAxis::updateGeometry()
const QRectF &gridRect = gridGeometry();
//arrow
- QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(axis.at(0));
+ QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem *>(arrow.at(0));
- if (alignment() == Qt::AlignTop)
+ if (axis()->alignment() == Qt::AlignTop)
arrowItem->setLine(gridRect.left(), axisRect.bottom(), gridRect.right(), axisRect.bottom());
- else if (alignment() == Qt::AlignBottom)
+ else if (axis()->alignment() == Qt::AlignBottom)
arrowItem->setLine(gridRect.left(), axisRect.top(), gridRect.right(), axisRect.top());
qreal width = 0;
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
//title
int titlePad = 0;
QRectF titleBoundingRect;
- if (!titleText().isEmpty() && titleItem()->isVisible()) {
+ QString titleText = axis()->titleText();
+ if (!titleText.isEmpty() && titleItem()->isVisible()) {
QFontMetrics fn(title->font());
int size(0);
size = gridRect.width();
- QString titleText = this->titleText();
if (fn.boundingRect(titleText).width() > size) {
QString string = titleText + "...";
@@ -89,9 +89,9 @@ void HorizontalAxis::updateGeometry()
titleBoundingRect = title->boundingRect();
QPointF center = gridRect.center() - titleBoundingRect.center();
- if (alignment() == Qt::AlignTop) {
+ if (axis()->alignment() == Qt::AlignTop) {
title->setPos(center.x(), axisRect.top() + titlePad);
- } else if (alignment() == Qt::AlignBottom) {
+ } else if (axis()->alignment() == Qt::AlignBottom) {
title->setPos(center.x(), axisRect.bottom() - titleBoundingRect.height() - titlePad);
}
}
@@ -100,7 +100,7 @@ void HorizontalAxis::updateGeometry()
//items
QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem*>(lines.at(i));
- QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(axis.at(i + 1));
+ QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem*>(arrow.at(i + 1));
QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem *>(labels.at(i));
//grid line
@@ -128,10 +128,10 @@ void HorizontalAxis::updateGeometry()
int heightDiff = rect.height() - boundingRect.height();
//ticks and label position
- if (alignment() == Qt::AlignTop) {
+ if (axis()->alignment() == Qt::AlignTop) {
labelItem->setPos(layout[i] - center.x(), axisRect.bottom() - rect.height() + (heightDiff / 2) - labelPadding());
tickItem->setLine(layout[i], axisRect.bottom(), layout[i], axisRect.bottom() - labelPadding());
- } else if (alignment() == Qt::AlignBottom) {
+ } else if (axis()->alignment() == Qt::AlignBottom) {
labelItem->setPos(layout[i] - center.x(), axisRect.top() - (heightDiff / 2) + labelPadding());
tickItem->setLine(layout[i], axisRect.top(), layout[i], axisRect.top() + labelPadding());
}
@@ -178,7 +178,7 @@ void HorizontalAxis::updateGeometry()
if (x < gridRect.left() || x > gridRect.right()) {
gridItem->setVisible(false);
tickItem->setVisible(false);
- }else{
+ } else {
gridItem->setVisible(true);
tickItem->setVisible(true);
}
@@ -200,10 +200,10 @@ void HorizontalAxis::updateGeometry()
QSizeF HorizontalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
{
Q_UNUSED(constraint);
- QFontMetrics fn(titleFont());
+ QFontMetrics fn(axis()->titleFont());
QSizeF sh(0,0);
- if (titleText().isEmpty() || !titleItem()->isVisible())
+ if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
return sh;
switch (which) {
diff --git a/src/axis/horizontalaxis_p.h b/src/axis/horizontalaxis_p.h
index 02aa2587..23116792 100644
--- a/src/axis/horizontalaxis_p.h
+++ b/src/axis/horizontalaxis_p.h
@@ -30,14 +30,14 @@
#ifndef HORIZONTALAXIS_P_H_
#define HORIZONTALAXIS_P_H_
-#include "chartaxis_p.h"
+#include "cartesianchartaxis_p.h"
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-class HorizontalAxis : public ChartAxis
+class HorizontalAxis : public CartesianChartAxis
{
public:
- HorizontalAxis(QAbstractAxis *axis, QGraphicsItem* item = 0, bool intervalAxis = false);
+ HorizontalAxis(QAbstractAxis *axis, QGraphicsItem *item = 0, bool intervalAxis = false);
~HorizontalAxis();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
protected:
diff --git a/src/axis/linearrowitem_p.h b/src/axis/linearrowitem_p.h
new file mode 100644
index 00000000..1adfd3bb
--- /dev/null
+++ b/src/axis/linearrowitem_p.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef LINEARROWITEM_P_H
+#define LINEARROWITEM_P_H
+
+#include "chartaxiselement_p.h"
+#include "qabstractaxis_p.h"
+#include <QGraphicsLineItem>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class LineArrowItem: public QGraphicsLineItem
+{
+public:
+ explicit LineArrowItem(ChartAxisElement *axis, QGraphicsItem *parent = 0)
+ : QGraphicsLineItem(parent),
+ m_axis(axis),
+ m_axisOrientation(axis->axis()->orientation())
+ {
+ }
+
+protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event)
+ {
+ Q_UNUSED(event)
+ m_axis->axisSelected();
+ }
+
+ QRectF boundingRect() const
+ {
+ return shape().boundingRect();
+ }
+
+ QPainterPath shape() const
+ {
+ QPainterPath path = QGraphicsLineItem::shape();
+ QRectF rect = path.boundingRect();
+ path.addRect(rect.adjusted(0, 0, m_axisOrientation != Qt::Horizontal ? 8 : 0, m_axisOrientation != Qt::Vertical ? 8 : 0));
+ return path;
+ }
+
+private:
+ ChartAxisElement *m_axis;
+ Qt::Orientation m_axisOrientation;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif /* LINEARROWITEM_P_H */
diff --git a/src/axis/logvalueaxis/chartlogvalueaxisx.cpp b/src/axis/logvalueaxis/chartlogvalueaxisx.cpp
index 3edc6d95..ac8f1f08 100644
--- a/src/axis/logvalueaxis/chartlogvalueaxisx.cpp
+++ b/src/axis/logvalueaxis/chartlogvalueaxisx.cpp
@@ -21,7 +21,7 @@
#include "chartlogvalueaxisx_p.h"
#include "chartpresenter_p.h"
#include "qlogvalueaxis.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QFontMetrics>
#include <qmath.h>
@@ -29,12 +29,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ChartLogValueAxisX::ChartLogValueAxisX(QLogValueAxis *axis, QGraphicsItem* item)
+ChartLogValueAxisX::ChartLogValueAxisX(QLogValueAxis *axis, QGraphicsItem *item)
: HorizontalAxis(axis, item),
m_axis(axis)
{
- QObject::connect(m_axis,SIGNAL(baseChanged(qreal)),this, SLOT(handleBaseChanged(qreal)));
- QObject::connect(m_axis,SIGNAL(labelFormatChanged(QString)),this, SLOT(handleLabelFormatChanged(QString)));
+ QObject::connect(m_axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal)));
+ QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
}
ChartLogValueAxisX::~ChartLogValueAxisX()
@@ -55,14 +55,14 @@ QVector<qreal> ChartLogValueAxisX::calculateLayout() const
const QRectF &gridRect = gridGeometry();
const qreal deltaX = gridRect.width() / qAbs(logMax - logMin);
for (int i = 0; i < tickCount; ++i)
- points[i] = (ceilEdge + i) * deltaX - leftEdge * deltaX + gridRect.left();
+ points[i] = (ceilEdge + qreal(i)) * deltaX - leftEdge * deltaX + gridRect.left();
return points;
}
void ChartLogValueAxisX::updateGeometry()
{
- const QVector<qreal>& layout = ChartAxis::layout();
+ const QVector<qreal>& layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
setLabels(createLogValueLabels(m_axis->min(), m_axis->max(), m_axis->base(), layout.size(), m_axis->labelFormat()));
@@ -87,7 +87,7 @@ QSizeF ChartLogValueAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = HorizontalAxis::sizeHint(which, constraint);
diff --git a/src/axis/logvalueaxis/chartlogvalueaxisx_p.h b/src/axis/logvalueaxis/chartlogvalueaxisx_p.h
index c0b24a58..3017e260 100644
--- a/src/axis/logvalueaxis/chartlogvalueaxisx_p.h
+++ b/src/axis/logvalueaxis/chartlogvalueaxisx_p.h
@@ -35,20 +35,18 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QLogValueAxis;
-class ChartPresenter;
class ChartLogValueAxisX : public HorizontalAxis
{
Q_OBJECT
public:
- ChartLogValueAxisX(QLogValueAxis *axis, QGraphicsItem* item);
+ ChartLogValueAxisX(QLogValueAxis *axis, QGraphicsItem *item);
~ChartLogValueAxisX();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
protected:
- void handleAxisUpdated();
QVector<qreal> calculateLayout() const;
void updateGeometry();
diff --git a/src/axis/logvalueaxis/chartlogvalueaxisy.cpp b/src/axis/logvalueaxis/chartlogvalueaxisy.cpp
index ec474e2f..42ae875c 100644
--- a/src/axis/logvalueaxis/chartlogvalueaxisy.cpp
+++ b/src/axis/logvalueaxis/chartlogvalueaxisy.cpp
@@ -21,7 +21,7 @@
#include "chartlogvalueaxisy_p.h"
#include "chartpresenter_p.h"
#include "qlogvalueaxis.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QFontMetrics>
#include <qmath.h>
@@ -29,12 +29,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ChartLogValueAxisY::ChartLogValueAxisY(QLogValueAxis *axis, QGraphicsItem* item)
+ChartLogValueAxisY::ChartLogValueAxisY(QLogValueAxis *axis, QGraphicsItem *item)
: VerticalAxis(axis, item),
m_axis(axis)
{
- QObject::connect(m_axis, SIGNAL(baseChanged(qreal)),this, SLOT(handleBaseChanged(qreal)));
- QObject::connect(m_axis,SIGNAL(labelFormatChanged(QString)),this, SLOT(handleLabelFormatChanged(QString)));
+ QObject::connect(m_axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal)));
+ QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
}
ChartLogValueAxisY::~ChartLogValueAxisY()
@@ -54,7 +54,7 @@ QVector<qreal> ChartLogValueAxisY::calculateLayout() const
const QRectF &gridRect = gridGeometry();
const qreal deltaY = gridRect.height() / qAbs(logMax - logMin);
for (int i = 0; i < tickCount; ++i)
- points[i] = (ceilEdge + i) * -deltaY - leftEdge * -deltaY + gridRect.bottom();
+ points[i] = (ceilEdge + qreal(i)) * -deltaY - leftEdge * -deltaY + gridRect.bottom();
return points;
}
@@ -62,7 +62,7 @@ QVector<qreal> ChartLogValueAxisY::calculateLayout() const
void ChartLogValueAxisY::updateGeometry()
{
- const QVector<qreal> &layout = ChartAxis::layout();
+ const QVector<qreal> &layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
setLabels(createLogValueLabels(m_axis->min(), m_axis->max(), m_axis->base(), layout.size(), m_axis->labelFormat()));
@@ -87,7 +87,7 @@ QSizeF ChartLogValueAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = VerticalAxis::sizeHint(which, constraint);
diff --git a/src/axis/logvalueaxis/chartlogvalueaxisy_p.h b/src/axis/logvalueaxis/chartlogvalueaxisy_p.h
index 8506cc29..39750976 100644
--- a/src/axis/logvalueaxis/chartlogvalueaxisy_p.h
+++ b/src/axis/logvalueaxis/chartlogvalueaxisy_p.h
@@ -35,20 +35,18 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QLogValueAxis;
-class ChartPresenter;
class ChartLogValueAxisY : public VerticalAxis
{
Q_OBJECT
public:
- ChartLogValueAxisY(QLogValueAxis *axis, QGraphicsItem* item);
+ ChartLogValueAxisY(QLogValueAxis *axis, QGraphicsItem *item);
~ChartLogValueAxisY();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
protected:
- void handleAxisUpdated();
QVector<qreal> calculateLayout() const;
void updateGeometry();
diff --git a/src/axis/logvalueaxis/polarchartlogvalueaxisangular.cpp b/src/axis/logvalueaxis/polarchartlogvalueaxisangular.cpp
new file mode 100644
index 00000000..ddbd9fe6
--- /dev/null
+++ b/src/axis/logvalueaxis/polarchartlogvalueaxisangular.cpp
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartlogvalueaxisangular_p.h"
+#include "abstractchartlayout_p.h"
+#include "chartpresenter_p.h"
+#include "qlogvalueaxis.h"
+#include <qmath.h>
+#include <QDebug>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartLogValueAxisAngular::PolarChartLogValueAxisAngular(QLogValueAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisAngular(axis, item)
+{
+ QObject::connect(axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal)));
+ QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
+}
+
+PolarChartLogValueAxisAngular::~PolarChartLogValueAxisAngular()
+{
+}
+
+QVector<qreal> PolarChartLogValueAxisAngular::calculateLayout() const
+{
+ QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis());
+ const qreal logMax = log10(logValueAxis->max()) / log10(logValueAxis->base());
+ const qreal logMin = log10(logValueAxis->min()) / log10(logValueAxis->base());
+ const qreal startEdge = logMin < logMax ? logMin : logMax;
+ const qreal delta = 360.0 / qAbs(logMax - logMin);
+ const qreal initialSpan = (ceil(startEdge) - startEdge) * delta;
+ int tickCount = qAbs(ceil(logMax) - ceil(logMin));
+
+ QVector<qreal> points;
+ points.resize(tickCount);
+
+ for (int i = 0; i < tickCount; ++i) {
+ qreal angularCoordinate = initialSpan + (delta * qreal(i));
+ points[i] = angularCoordinate;
+ }
+
+ return points;
+}
+
+void PolarChartLogValueAxisAngular::createAxisLabels(const QVector<qreal> &layout)
+{
+ QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis());
+ setLabels(createLogValueLabels(logValueAxis->min(),
+ logValueAxis->max(),
+ logValueAxis->base(),
+ layout.size(),
+ logValueAxis->labelFormat()));
+}
+
+void PolarChartLogValueAxisAngular::handleBaseChanged(qreal base)
+{
+ Q_UNUSED(base);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+void PolarChartLogValueAxisAngular::handleLabelFormatChanged(const QString &format)
+{
+ Q_UNUSED(format);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_polarchartlogvalueaxisangular_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/logvalueaxis/polarchartlogvalueaxisangular_p.h b/src/axis/logvalueaxis/polarchartlogvalueaxisangular_p.h
new file mode 100644
index 00000000..231172aa
--- /dev/null
+++ b/src/axis/logvalueaxis/polarchartlogvalueaxisangular_p.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTLOGVALUEAXISANGULAR_P_H
+#define POLARCHARTLOGVALUEAXISANGULAR_P_H
+
+#include "polarchartaxisangular_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QLogValueAxis;
+
+class PolarChartLogValueAxisAngular : public PolarChartAxisAngular
+{
+ Q_OBJECT
+public:
+ PolarChartLogValueAxisAngular(QLogValueAxis *axis, QGraphicsItem *item);
+ ~PolarChartLogValueAxisAngular();
+
+protected:
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+private Q_SLOTS:
+ void handleBaseChanged(qreal base);
+ void handleLabelFormatChanged(const QString &format);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTLOGVALUEAXISANGULAR_P_H
diff --git a/src/axis/logvalueaxis/polarchartlogvalueaxisradial.cpp b/src/axis/logvalueaxis/polarchartlogvalueaxisradial.cpp
new file mode 100644
index 00000000..d0719dbc
--- /dev/null
+++ b/src/axis/logvalueaxis/polarchartlogvalueaxisradial.cpp
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartlogvalueaxisradial_p.h"
+#include "abstractchartlayout_p.h"
+#include "chartpresenter_p.h"
+#include "qlogvalueaxis.h"
+#include <qmath.h>
+#include <QDebug>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartLogValueAxisRadial::PolarChartLogValueAxisRadial(QLogValueAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisRadial(axis, item)
+{
+ QObject::connect(axis, SIGNAL(baseChanged(qreal)), this, SLOT(handleBaseChanged(qreal)));
+ QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
+}
+
+PolarChartLogValueAxisRadial::~PolarChartLogValueAxisRadial()
+{
+}
+
+QVector<qreal> PolarChartLogValueAxisRadial::calculateLayout() const
+{
+ QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis());
+ const qreal logMax = log10(logValueAxis->max()) / log10(logValueAxis->base());
+ const qreal logMin = log10(logValueAxis->min()) / log10(logValueAxis->base());
+ const qreal innerEdge = logMin < logMax ? logMin : logMax;
+ const qreal outerEdge = logMin > logMax ? logMin : logMax;
+ const qreal delta = (axisGeometry().width() / 2.0) / qAbs(logMax - logMin);
+ const qreal initialSpan = (ceil(innerEdge) - innerEdge) * delta;
+ int tickCount = qAbs(ceil(logMax) - ceil(logMin));
+
+ // Extra tick if outer edge is exactly at the tick
+ if (outerEdge == ceil(outerEdge))
+ tickCount++;
+
+ QVector<qreal> points;
+ points.resize(tickCount);
+
+ for (int i = 0; i < tickCount; ++i) {
+ qreal radialCoordinate = initialSpan + (delta * qreal(i));
+ points[i] = radialCoordinate;
+ }
+
+ return points;
+}
+
+void PolarChartLogValueAxisRadial::createAxisLabels(const QVector<qreal> &layout)
+{
+ QLogValueAxis *logValueAxis = static_cast<QLogValueAxis *>(axis());
+ setLabels(createLogValueLabels(logValueAxis->min(),
+ logValueAxis->max(),
+ logValueAxis->base(),
+ layout.size(),
+ logValueAxis->labelFormat()));
+}
+
+void PolarChartLogValueAxisRadial::handleBaseChanged(qreal base)
+{
+ Q_UNUSED(base);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+void PolarChartLogValueAxisRadial::handleLabelFormatChanged(const QString &format)
+{
+ Q_UNUSED(format);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_polarchartlogvalueaxisradial_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/logvalueaxis/polarchartlogvalueaxisradial_p.h b/src/axis/logvalueaxis/polarchartlogvalueaxisradial_p.h
new file mode 100644
index 00000000..bc7e8982
--- /dev/null
+++ b/src/axis/logvalueaxis/polarchartlogvalueaxisradial_p.h
@@ -0,0 +1,57 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTLOGVALUEAXISRADIAL_P_H
+#define POLARCHARTLOGVALUEAXISRADIAL_P_H
+
+#include "polarchartaxisradial_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QLogValueAxis;
+
+class PolarChartLogValueAxisRadial : public PolarChartAxisRadial
+{
+ Q_OBJECT
+public:
+ PolarChartLogValueAxisRadial(QLogValueAxis *axis, QGraphicsItem *item);
+ ~PolarChartLogValueAxisRadial();
+
+protected:
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+private Q_SLOTS:
+ void handleBaseChanged(qreal base);
+ void handleLabelFormatChanged(const QString &format);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTLOGVALUEAXISRADIAL_P_H
diff --git a/src/axis/logvalueaxis/qlogvalueaxis.cpp b/src/axis/logvalueaxis/qlogvalueaxis.cpp
index 12170b8b..27896b51 100644
--- a/src/axis/logvalueaxis/qlogvalueaxis.cpp
+++ b/src/axis/logvalueaxis/qlogvalueaxis.cpp
@@ -22,6 +22,8 @@
#include "qlogvalueaxis_p.h"
#include "chartlogvalueaxisx_p.h"
#include "chartlogvalueaxisy_p.h"
+#include "polarchartlogvalueaxisangular_p.h"
+#include "polarchartlogvalueaxisradial_p.h"
#include "abstractdomain_p.h"
#include <float.h>
#include <cmath>
@@ -287,14 +289,24 @@ void QLogValueAxisPrivate::setRange(qreal min, qreal max)
}
}
-void QLogValueAxisPrivate::initializeGraphics(QGraphicsItem* parent)
+void QLogValueAxisPrivate::initializeGraphics(QGraphicsItem *parent)
{
Q_Q(QLogValueAxis);
- ChartAxis* axis(0);
- if (orientation() == Qt::Vertical)
- axis = new ChartLogValueAxisY(q,parent);
- if (orientation() == Qt::Horizontal)
- axis = new ChartLogValueAxisX(q,parent);
+ ChartAxisElement *axis(0);
+
+ if (m_chart->chartType() == QChart::ChartTypeCartesian) {
+ if (orientation() == Qt::Vertical)
+ axis = new ChartLogValueAxisY(q,parent);
+ if (orientation() == Qt::Horizontal)
+ axis = new ChartLogValueAxisX(q,parent);
+ }
+
+ if (m_chart->chartType() == QChart::ChartTypePolar) {
+ if (orientation() == Qt::Vertical)
+ axis = new PolarChartLogValueAxisRadial(q, parent);
+ if (orientation() == Qt::Horizontal)
+ axis = new PolarChartLogValueAxisAngular(q, parent);
+ }
m_item.reset(axis);
QAbstractAxisPrivate::initializeGraphics(parent);
@@ -304,7 +316,7 @@ void QLogValueAxisPrivate::initializeGraphics(QGraphicsItem* parent)
void QLogValueAxisPrivate::initializeDomain(AbstractDomain *domain)
{
if (orientation() == Qt::Vertical) {
- if(!qFuzzyCompare(m_max, m_min)) {
+ if (!qFuzzyCompare(m_max, m_min)) {
domain->setRangeY(m_min, m_max);
} else if ( domain->minY() > 0) {
setRange(domain->minY(), domain->maxY());
@@ -315,7 +327,7 @@ void QLogValueAxisPrivate::initializeDomain(AbstractDomain *domain)
}
}
if (orientation() == Qt::Horizontal) {
- if(!qFuzzyCompare(m_max, m_min)) {
+ if (!qFuzzyCompare(m_max, m_min)) {
domain->setRangeX(m_min, m_max);
} else if (domain->minX() > 0){
setRange(domain->minX(), domain->maxX());
diff --git a/src/axis/polarchartaxis.cpp b/src/axis/polarchartaxis.cpp
new file mode 100644
index 00000000..8bb80420
--- /dev/null
+++ b/src/axis/polarchartaxis.cpp
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartaxis_p.h"
+#include "qabstractaxis_p.h"
+#include "chartpresenter_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartAxis::PolarChartAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
+ : ChartAxisElement(axis, item, intervalAxis)
+{
+}
+
+PolarChartAxis::~PolarChartAxis()
+{
+
+}
+
+void PolarChartAxis::setGeometry(const QRectF &axis, const QRectF &grid)
+{
+ Q_UNUSED(grid);
+ setAxisGeometry(axis);
+
+ if (isEmpty())
+ return;
+
+ QVector<qreal> layout = calculateLayout();
+ updateLayout(layout);
+}
+
+QRectF PolarChartAxis::gridGeometry() const
+{
+ return QRectF();
+}
+
+void PolarChartAxis::updateLayout(QVector<qreal> &layout)
+{
+ int diff = ChartAxisElement::layout().size() - layout.size();
+
+ if (animation()) {
+ switch (presenter()->state()) {
+ case ChartPresenter::ShowState:
+ animation()->setAnimationType(AxisAnimation::DefaultAnimation);
+ break;
+ }
+ // Update to "old" geometry before starting animation to avoid incorrectly sized
+ // axes lingering in wrong position compared to series plot before animation can kick in.
+ // Note that the position mismatch still exists even with this update, but it will be
+ // far less ugly.
+ updateGeometry();
+ }
+
+ if (diff > 0)
+ deleteItems(diff);
+ else if (diff < 0)
+ createItems(-diff);
+
+ if (animation()) {
+ animation()->setValues(ChartAxisElement::layout(), layout);
+ presenter()->startAnimation(animation());
+ } else {
+ setLayout(layout);
+ updateGeometry();
+ }
+}
+
+bool PolarChartAxis::isEmpty()
+{
+ return !axisGeometry().isValid() || qFuzzyIsNull(min() - max());
+}
+
+void PolarChartAxis::deleteItems(int count)
+{
+ QList<QGraphicsItem *> gridLines = gridItems();
+ QList<QGraphicsItem *> labels = labelItems();
+ QList<QGraphicsItem *> shades = shadeItems();
+ QList<QGraphicsItem *> axis = arrowItems();
+
+ for (int i = 0; i < count; ++i) {
+ if (gridItems().size() == 1 || (((gridLines.size() + 1) % 2) && gridLines.size() > 0))
+ delete(shades.takeLast());
+ delete(gridLines.takeLast());
+ delete(labels.takeLast());
+ delete(axis.takeLast());
+ }
+}
+
+void PolarChartAxis::handleShadesBrushChanged(const QBrush &brush)
+{
+ foreach (QGraphicsItem *item, shadeItems())
+ static_cast<QGraphicsPathItem *>(item)->setBrush(brush);
+}
+
+void PolarChartAxis::handleShadesPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, shadeItems())
+ static_cast<QGraphicsPathItem *>(item)->setPen(pen);
+}
+
+#include "moc_polarchartaxis_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/polarchartaxis_p.h b/src/axis/polarchartaxis_p.h
new file mode 100644
index 00000000..605b8fee
--- /dev/null
+++ b/src/axis/polarchartaxis_p.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTAXIS_P_H
+#define POLARCHARTAXIS_P_H
+
+#include "chartaxiselement_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class PolarChartAxis : public ChartAxisElement
+{
+ Q_OBJECT
+ Q_INTERFACES(QGraphicsLayoutItem)
+public:
+ PolarChartAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false);
+ ~PolarChartAxis();
+
+ void setGeometry(const QRectF &axis, const QRectF &grid);
+ virtual qreal preferredAxisRadius(const QSizeF &maxSize) = 0;
+ int tickWidth() { return 3; }
+
+public: // from ChartAxisElement
+ QRectF gridGeometry() const;
+ bool isEmpty();
+
+protected:
+ void updateLayout(QVector<qreal> &layout);
+
+protected: // virtual functions
+ virtual void createItems(int count) = 0;
+ virtual void createAxisLabels(const QVector<qreal> &layout) = 0;
+
+public Q_SLOTS:
+ virtual void handleShadesBrushChanged(const QBrush &brush);
+ virtual void handleShadesPenChanged(const QPen &pen);
+
+private:
+ void deleteItems(int count);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTAXIS_P_H
diff --git a/src/axis/polarchartaxisangular.cpp b/src/axis/polarchartaxisangular.cpp
new file mode 100644
index 00000000..8eed1f9d
--- /dev/null
+++ b/src/axis/polarchartaxisangular.cpp
@@ -0,0 +1,428 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartaxisangular_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "qabstractaxis.h"
+#include "qabstractaxis_p.h"
+#include <QFontMetrics>
+#include <QDebug>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartAxisAngular::PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
+ : PolarChartAxis(axis, item, intervalAxis)
+{
+}
+
+PolarChartAxisAngular::~PolarChartAxisAngular()
+{
+}
+
+void PolarChartAxisAngular::updateGeometry()
+{
+ QGraphicsLayoutItem::updateGeometry();
+
+ const QVector<qreal> &layout = this->layout();
+ if (layout.isEmpty())
+ return;
+
+ createAxisLabels(layout);
+ QStringList labelList = labels();
+ QPointF center = axisGeometry().center();
+ QList<QGraphicsItem *> arrowItemList = arrowItems();
+ QList<QGraphicsItem *> gridItemList = gridItems();
+ QList<QGraphicsItem *> labelItemList = labelItems();
+ QList<QGraphicsItem *> shadeItemList = shadeItems();
+ QGraphicsSimpleTextItem *title = titleItem();
+
+ QGraphicsEllipseItem *axisLine = static_cast<QGraphicsEllipseItem *>(arrowItemList.at(0));
+ axisLine->setRect(axisGeometry());
+
+ qreal radius = axisGeometry().height() / 2.0;
+
+ QFontMetrics fn(axis()->labelsFont());
+ QRectF previousLabelRect;
+ QRectF firstLabelRect;
+
+ qreal labelHeight = 0;
+
+ bool firstShade = true;
+ bool nextTickVisible = false;
+ if (layout.size())
+ nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > 360.0);
+
+ for (int i = 0; i < layout.size(); ++i) {
+ qreal angularCoordinate = layout.at(i);
+
+ QGraphicsLineItem *gridLineItem = static_cast<QGraphicsLineItem *>(gridItemList.at(i));
+ QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
+ QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem *>(labelItemList.at(i));
+ QGraphicsPathItem *shadeItem = 0;
+ if (i == 0)
+ shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
+ else if (i % 2)
+ shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
+
+ // Ignore ticks outside valid range
+ bool currentTickVisible = nextTickVisible;
+ if ((i == layout.size() - 1)
+ || layout.at(i + 1) < 0.0
+ || layout.at(i + 1) > 360.0) {
+ nextTickVisible = false;
+ } else {
+ nextTickVisible = true;
+ }
+
+ qreal labelCoordinate = angularCoordinate;
+ qreal labelVisible = currentTickVisible;
+ if (intervalAxis()) {
+ qreal farEdge;
+ if (i == (layout.size() - 1))
+ farEdge = 360.0;
+ else
+ farEdge = qMin(360.0, layout.at(i + 1));
+
+ // Adjust the labelCoordinate to show it if next tick is visible
+ if (nextTickVisible)
+ labelCoordinate = qMax(0.0, labelCoordinate);
+
+ labelCoordinate = (labelCoordinate + farEdge) / 2.0;
+ // Don't display label once the category gets too small near the axis
+ if (labelCoordinate < 5.0 || labelCoordinate > 355.0)
+ labelVisible = false;
+ else
+ labelVisible = true;
+ }
+
+ // Need this also in label calculations, so determine it first
+ QLineF tickLine(QLineF::fromPolar(radius - tickWidth(), 90.0 - angularCoordinate).p2(),
+ QLineF::fromPolar(radius + tickWidth(), 90.0 - angularCoordinate).p2());
+ tickLine.translate(center);
+
+ // Angular axis label
+ if (axis()->labelsVisible() && labelVisible) {
+ labelItem->setText(labelList.at(i));
+ const QRectF &rect = labelItem->boundingRect();
+ QPointF labelCenter = rect.center();
+ labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
+ QRectF boundingRect = labelBoundingRect(fn, labelList.at(i));
+ boundingRect.moveCenter(labelCenter);
+ QPointF positionDiff(rect.topLeft() - boundingRect.topLeft());
+
+ QPointF labelPoint;
+ if (intervalAxis()) {
+ QLineF labelLine = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate);
+ labelLine.translate(center);
+ labelPoint = labelLine.p2();
+ } else {
+ labelPoint = tickLine.p2();
+ }
+
+ QRectF labelRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
+ labelItem->setPos(labelRect.topLeft() + positionDiff);
+
+ // Store height for title calculations
+ qreal labelClearance = axisGeometry().top() - labelRect.top();
+ labelHeight = qMax(labelHeight, labelClearance);
+
+ // Label overlap detection
+ if (i && (previousLabelRect.intersects(labelRect) || firstLabelRect.intersects(labelRect))) {
+ labelVisible = false;
+ } else {
+ // Store labelRect for future comparison. Some area is deducted to make things look
+ // little nicer, as usually intersection happens at label corner with angular labels.
+ labelRect.adjust(-2.0, -4.0, -2.0, -4.0);
+ if (firstLabelRect.isEmpty())
+ firstLabelRect = labelRect;
+
+ previousLabelRect = labelRect;
+ labelVisible = true;
+ }
+ }
+
+ labelItem->setVisible(labelVisible);
+ if (!currentTickVisible) {
+ gridLineItem->setVisible(false);
+ tickItem->setVisible(false);
+ if (shadeItem)
+ shadeItem->setVisible(false);
+ continue;
+ }
+
+ // Angular grid line
+ QLineF gridLine = QLineF::fromPolar(radius, 90.0 - angularCoordinate);
+ gridLine.translate(center);
+ gridLineItem->setLine(gridLine);
+ gridLineItem->setVisible(true);
+
+ // Tick
+ tickItem->setLine(tickLine);
+ tickItem->setVisible(true);
+
+ // Shades
+ if (i % 2 || (i == 0 && !nextTickVisible)) {
+ QPainterPath path;
+ path.moveTo(center);
+ if (i == 0) {
+ // If first tick is also the last, we need to custom fill the first partial arc
+ // or it won't get filled.
+ path.arcTo(axisGeometry(), 90.0 - layout.at(0), layout.at(0));
+ path.closeSubpath();
+ } else {
+ qreal nextCoordinate;
+ if (!nextTickVisible) // Last visible tick
+ nextCoordinate = 360.0;
+ else
+ nextCoordinate = layout.at(i + 1);
+ qreal arcSpan = angularCoordinate - nextCoordinate;
+ path.arcTo(axisGeometry(), 90.0 - angularCoordinate, arcSpan);
+ path.closeSubpath();
+
+ // Add additional arc for first shade item if there is a partial arc to be filled
+ if (firstShade) {
+ QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
+ if (layout.at(i - 1) > 0.0) {
+ QPainterPath specialPath;
+ specialPath.moveTo(center);
+ specialPath.arcTo(axisGeometry(), 90.0 - layout.at(i - 1), layout.at(i - 1));
+ specialPath.closeSubpath();
+ specialShadeItem->setPath(specialPath);
+ specialShadeItem->setVisible(true);
+ } else {
+ specialShadeItem->setVisible(false);
+ }
+ }
+ }
+ shadeItem->setPath(path);
+ shadeItem->setVisible(true);
+ firstShade = false;
+ }
+ }
+
+ // Title, centered above the chart
+ QString titleText = axis()->titleText();
+ if (!titleText.isEmpty() && axis()->isTitleVisible()) {
+ int size(0);
+ size = axisGeometry().width();
+
+ QFontMetrics titleMetrics(axis()->titleFont());
+ if (titleMetrics.boundingRect(titleText).width() > size) {
+ QString string = titleText + "...";
+ while (titleMetrics.boundingRect(string).width() > size && string.length() > 3)
+ string.remove(string.length() - 4, 1);
+ title->setText(string);
+ } else {
+ title->setText(titleText);
+ }
+
+ QRectF titleBoundingRect;
+ titleBoundingRect = title->boundingRect();
+ QPointF titleCenter = center - titleBoundingRect.center();
+ title->setPos(titleCenter.x(), axisGeometry().top() - qreal(titlePadding()) * 2.0 - titleBoundingRect.height() - labelHeight);
+ }
+}
+
+Qt::Orientation PolarChartAxisAngular::orientation() const
+{
+ return Qt::Horizontal;
+}
+
+void PolarChartAxisAngular::createItems(int count)
+{
+ if (arrowItems().count() == 0) {
+ // angular axis line
+ // TODO: need class similar to LineArrowItem for click handling?
+ QGraphicsEllipseItem *arrow = new QGraphicsEllipseItem(presenter()->rootItem());
+ arrow->setPen(axis()->linePen());
+ arrowGroup()->addToGroup(arrow);
+ }
+
+ for (int i = 0; i < count; ++i) {
+ QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
+ QGraphicsLineItem *grid = new QGraphicsLineItem(presenter()->rootItem());
+ QGraphicsSimpleTextItem *label = new QGraphicsSimpleTextItem(presenter()->rootItem());
+ QGraphicsSimpleTextItem *title = titleItem();
+ arrow->setPen(axis()->linePen());
+ grid->setPen(axis()->gridLinePen());
+ label->setFont(axis()->labelsFont());
+ label->setPen(axis()->labelsPen());
+ label->setBrush(axis()->labelsBrush());
+ label->setRotation(axis()->labelsAngle());
+ title->setFont(axis()->titleFont());
+ title->setPen(axis()->titlePen());
+ title->setBrush(axis()->titleBrush());
+ title->setText(axis()->titleText());
+ arrowGroup()->addToGroup(arrow);
+ gridGroup()->addToGroup(grid);
+ labelGroup()->addToGroup(label);
+ if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
+ QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
+ shade->setPen(axis()->shadesPen());
+ shade->setBrush(axis()->shadesBrush());
+ shadeGroup()->addToGroup(shade);
+ }
+ }
+}
+
+void PolarChartAxisAngular::handleArrowPenChanged(const QPen &pen)
+{
+ bool first = true;
+ foreach (QGraphicsItem *item, arrowItems()) {
+ if (first) {
+ first = false;
+ // First arrow item is the outer circle of axis
+ static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
+ } else {
+ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
+ }
+ }
+}
+
+void PolarChartAxisAngular::handleGridPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, gridItems())
+ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
+}
+
+QSizeF PolarChartAxisAngular::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_UNUSED(which);
+ Q_UNUSED(constraint);
+ return QSizeF(-1, -1);
+}
+
+qreal PolarChartAxisAngular::preferredAxisRadius(const QSizeF &maxSize)
+{
+ qreal radius = maxSize.height() / 2.0;
+ if (maxSize.width() < maxSize.height())
+ radius = maxSize.width() / 2.0;
+
+ int labelHeight = 0;
+
+ if (axis()->labelsVisible()) {
+ QVector<qreal> layout = calculateLayout();
+ if (layout.isEmpty())
+ return radius;
+
+ createAxisLabels(layout);
+ QStringList labelList = labels();
+ QFont font = axis()->labelsFont();
+
+ QRectF maxRect;
+ maxRect.setSize(maxSize);
+ maxRect.moveCenter(QPointF(0.0, 0.0));
+
+ // This is a horrible way to find out the maximum radius for angular axis and its labels.
+ // It just increments the radius down until everyhing fits the constraint size.
+ // Proper way would be to actually calculate it but this seems to work reasonably fast as it is.
+ QFontMetrics fm(font);
+ bool nextTickVisible = false;
+ for (int i = 0; i < layout.size(); ) {
+ if ((i == layout.size() - 1)
+ || layout.at(i + 1) < 0.0
+ || layout.at(i + 1) > 360.0) {
+ nextTickVisible = false;
+ } else {
+ nextTickVisible = true;
+ }
+
+ qreal labelCoordinate = layout.at(i);
+ qreal labelVisible;
+
+ if (intervalAxis()) {
+ qreal farEdge;
+ if (i == (layout.size() - 1))
+ farEdge = 360.0;
+ else
+ farEdge = qMin(360.0, layout.at(i + 1));
+
+ // Adjust the labelCoordinate to show it if next tick is visible
+ if (nextTickVisible)
+ labelCoordinate = qMax(0.0, labelCoordinate);
+
+ labelCoordinate = (labelCoordinate + farEdge) / 2.0;
+ }
+
+ if (labelCoordinate < 0.0 || labelCoordinate > 360.0)
+ labelVisible = false;
+ else
+ labelVisible = true;
+
+ if (!labelVisible) {
+ i++;
+ continue;
+ }
+
+ QRectF boundingRect = labelBoundingRect(fm, labelList.at(i));
+ labelHeight = boundingRect.height();
+ QPointF labelPoint = QLineF::fromPolar(radius + tickWidth(), 90.0 - labelCoordinate).p2();
+
+ boundingRect = moveLabelToPosition(labelCoordinate, labelPoint, boundingRect);
+ if (boundingRect.isEmpty() || maxRect.intersected(boundingRect) == boundingRect) {
+ i++;
+ } else {
+ radius -= 1.0;
+ if (radius < 1.0) // safeguard
+ return 1.0;
+ }
+ }
+ }
+
+ if (!axis()->titleText().isEmpty() && axis()->isTitleVisible()) {
+ QFontMetrics titleMetrics(axis()->titleFont());
+ int titleHeight = titleMetrics.boundingRect(axis()->titleText()).height();
+ radius -= titlePadding() + (titleHeight / 2);
+ if (radius < 1.0) // safeguard
+ return 1.0;
+ }
+
+ return radius;
+}
+
+QRectF PolarChartAxisAngular::moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const
+{
+ // TODO use fuzzy compare for "==" cases?
+ // TODO Adjust the rect position near 0, 90, 180, and 270 angles for smoother animation?
+ if (angularCoordinate == 0.0)
+ labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
+ else if (angularCoordinate < 90.0)
+ labelRect.moveBottomLeft(labelPoint);
+ else if (angularCoordinate == 90.0)
+ labelRect.moveCenter(labelPoint + QPointF(labelRect.width() / 2.0 + 2.0, 0)); // +2 so that it does not hit the radial axis
+ else if (angularCoordinate < 180.0)
+ labelRect.moveTopLeft(labelPoint);
+ else if (angularCoordinate == 180.0)
+ labelRect.moveCenter(labelPoint + QPointF(0, labelRect.height() / 2.0));
+ else if (angularCoordinate < 270.0)
+ labelRect.moveTopRight(labelPoint);
+ else if (angularCoordinate == 270.0)
+ labelRect.moveCenter(labelPoint + QPointF(-labelRect.width() / 2.0 - 2.0, 0)); // -2 so that it does not hit the radial axis
+ else if (angularCoordinate < 360.0)
+ labelRect.moveBottomRight(labelPoint);
+ else
+ labelRect.moveCenter(labelPoint + QPointF(0, -labelRect.height() / 2.0));
+ return labelRect;
+}
+
+#include "moc_polarchartaxisangular_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/polarchartaxisangular_p.h b/src/axis/polarchartaxisangular_p.h
new file mode 100644
index 00000000..7e7b292d
--- /dev/null
+++ b/src/axis/polarchartaxisangular_p.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTAXISANGULAR_P_H
+#define POLARCHARTAXISANGULAR_P_H
+
+#include "polarchartaxis_p.h"
+#include "qvalueaxis.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class PolarChartAxisAngular : public PolarChartAxis
+{
+ Q_OBJECT
+public:
+ PolarChartAxisAngular(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false);
+ ~PolarChartAxisAngular();
+
+ Qt::Orientation orientation() const;
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+ virtual void updateGeometry();
+ virtual void createItems(int count);
+
+ qreal preferredAxisRadius(const QSizeF &maxSize);
+
+public Q_SLOTS:
+ virtual void handleArrowPenChanged(const QPen &pen);
+ virtual void handleGridPenChanged(const QPen &pen);
+
+private:
+ QRectF moveLabelToPosition(qreal angularCoordinate, QPointF labelPoint, QRectF labelRect) const;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTAXISANGULAR_P_H
diff --git a/src/axis/polarchartaxisradial.cpp b/src/axis/polarchartaxisradial.cpp
new file mode 100644
index 00000000..55923985
--- /dev/null
+++ b/src/axis/polarchartaxisradial.cpp
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartaxisradial_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+#include "qabstractaxis_p.h"
+#include "linearrowitem_p.h"
+#include <QFontMetrics>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartAxisRadial::PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
+ : PolarChartAxis(axis, item, intervalAxis)
+{
+}
+
+PolarChartAxisRadial::~PolarChartAxisRadial()
+{
+}
+
+void PolarChartAxisRadial::updateGeometry()
+{
+ const QVector<qreal> &layout = this->layout();
+ if (layout.isEmpty())
+ return;
+
+ createAxisLabels(layout);
+ QStringList labelList = labels();
+ QPointF center = axisGeometry().center();
+ QList<QGraphicsItem *> arrowItemList = arrowItems();
+ QList<QGraphicsItem *> gridItemList = gridItems();
+ QList<QGraphicsItem *> labelItemList = labelItems();
+ QList<QGraphicsItem *> shadeItemList = shadeItems();
+ QGraphicsSimpleTextItem* title = titleItem();
+ qreal radius = axisGeometry().height() / 2.0;
+
+ QLineF line(center, center + QPointF(0, -radius));
+ QGraphicsLineItem *axisLine = static_cast<QGraphicsLineItem *>(arrowItemList.at(0));
+ axisLine->setLine(line);
+
+ QFontMetrics fn(axis()->labelsFont());
+ QRectF previousLabelRect;
+ bool firstShade = true;
+ bool nextTickVisible = false;
+ if (layout.size())
+ nextTickVisible = !(layout.at(0) < 0.0 || layout.at(0) > radius);
+
+ for (int i = 0; i < layout.size(); ++i) {
+ qreal radialCoordinate = layout.at(i);
+
+ QGraphicsEllipseItem *gridItem = static_cast<QGraphicsEllipseItem *>(gridItemList.at(i));
+ QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrowItemList.at(i + 1));
+ QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem *>(labelItemList.at(i));
+ QGraphicsPathItem *shadeItem = 0;
+ if (i == 0)
+ shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
+ else if (i % 2)
+ shadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at((i / 2) + 1));
+
+ // Ignore ticks outside valid range
+ bool currentTickVisible = nextTickVisible;
+ if ((i == layout.size() - 1)
+ || layout.at(i + 1) < 0.0
+ || layout.at(i + 1) > radius) {
+ nextTickVisible = false;
+ } else {
+ nextTickVisible = true;
+ }
+
+ qreal labelCoordinate = radialCoordinate;
+ qreal labelVisible = currentTickVisible;
+ qreal labelPad = labelPadding() / 2.0;
+ if (intervalAxis()) {
+ qreal farEdge;
+ if (i == (layout.size() - 1))
+ farEdge = radius;
+ else
+ farEdge = qMin(radius, layout.at(i + 1));
+
+ // Adjust the labelCoordinate to show it if next tick is visible
+ if (nextTickVisible)
+ labelCoordinate = qMax(0.0, labelCoordinate);
+
+ labelCoordinate = (labelCoordinate + farEdge) / 2.0;
+ if (labelCoordinate > 0.0 && labelCoordinate < radius)
+ labelVisible = true;
+ else
+ labelVisible = false;
+ }
+
+ // Radial axis label
+ if (axis()->labelsVisible() && labelVisible) {
+ labelItem->setText(labelList.at(i));
+ QRectF labelRect = labelItem->boundingRect();
+ QPointF labelCenter = labelRect.center();
+ labelItem->setTransformOriginPoint(labelCenter.x(), labelCenter.y());
+ QRectF boundingRect = labelBoundingRect(fn, labelList.at(i));
+ boundingRect.moveCenter(labelCenter);
+ QPointF positionDiff(labelRect.topLeft() - boundingRect.topLeft());
+ QPointF labelPoint = center;
+ if (intervalAxis())
+ labelPoint += QPointF(labelPad, -labelCoordinate - (boundingRect.height() / 2.0));
+ else
+ labelPoint += QPointF(labelPad, labelPad - labelCoordinate);
+ labelRect.moveTopLeft(labelPoint);
+ labelItem->setPos(labelRect.topLeft() + positionDiff);
+
+ // Label overlap detection
+ labelRect.setSize(boundingRect.size());
+ if ((i && previousLabelRect.intersects(labelRect))
+ || !axisGeometry().contains(labelRect)) {
+ labelVisible = false;
+ } else {
+ previousLabelRect = labelRect;
+ labelVisible = true;
+ }
+ }
+
+ labelItem->setVisible(labelVisible);
+ if (!currentTickVisible) {
+ gridItem->setVisible(false);
+ tickItem->setVisible(false);
+ if (shadeItem)
+ shadeItem->setVisible(false);
+ continue;
+ }
+
+ // Radial grid line
+ QRectF gridRect;
+ gridRect.setWidth(radialCoordinate * 2.0);
+ gridRect.setHeight(radialCoordinate * 2.0);
+ gridRect.moveCenter(center);
+
+ gridItem->setRect(gridRect);
+ gridItem->setVisible(true);
+
+ // Tick
+ QLineF tickLine(-tickWidth(), 0.0, tickWidth(), 0.0);
+ tickLine.translate(center.rx(), gridRect.top());
+ tickItem->setLine(tickLine);
+ tickItem->setVisible(true);
+
+ // Shades
+ if (i % 2 || (i == 0 && !nextTickVisible)) {
+ QPainterPath path;
+ if (i == 0) {
+ // If first tick is also the last, we need to custom fill the inner circle
+ // or it won't get filled.
+ QRectF innerCircle(0.0, 0.0, layout.at(0) * 2.0, layout.at(0) * 2.0);
+ innerCircle.moveCenter(center);
+ path.addEllipse(innerCircle);
+ } else {
+ QRectF otherGridRect;
+ if (!nextTickVisible) { // Last visible tick
+ otherGridRect = axisGeometry();
+ } else {
+ qreal otherGridRectDimension = layout.at(i + 1) * 2.0;
+ otherGridRect.setWidth(otherGridRectDimension);
+ otherGridRect.setHeight(otherGridRectDimension);
+ otherGridRect.moveCenter(center);
+ }
+ path.addEllipse(gridRect);
+ path.addEllipse(otherGridRect);
+
+ // Add additional shading in first visible shade item if there is a partial tick
+ // to be filled at the center (log & category axes)
+ if (firstShade) {
+ QGraphicsPathItem *specialShadeItem = static_cast<QGraphicsPathItem *>(shadeItemList.at(0));
+ if (layout.at(i - 1) > 0.0) {
+ QRectF innerCircle(0.0, 0.0, layout.at(i - 1) * 2.0, layout.at(i - 1) * 2.0);
+ innerCircle.moveCenter(center);
+ QPainterPath specialPath;
+ specialPath.addEllipse(innerCircle);
+ specialShadeItem->setPath(specialPath);
+ specialShadeItem->setVisible(true);
+ } else {
+ specialShadeItem->setVisible(false);
+ }
+ }
+ }
+ shadeItem->setPath(path);
+ shadeItem->setVisible(true);
+ firstShade = false;
+ }
+ }
+
+ // Title, along the 0 axis
+ QString titleText = axis()->titleText();
+ if (!titleText.isEmpty() && axis()->isTitleVisible()) {
+ QFontMetrics titleMetrics(axis()->titleFont());
+ if (titleMetrics.boundingRect(titleText).width() > radius) {
+ QString string = titleText + "...";
+ while (titleMetrics.boundingRect(string).width() > radius && string.length() > 3)
+ string.remove(string.length() - 4, 1);
+ title->setText(string);
+ } else {
+ title->setText(titleText);
+ }
+
+ QRectF titleBoundingRect;
+ titleBoundingRect = title->boundingRect();
+ QPointF titleCenter = titleBoundingRect.center();
+ QPointF arrowCenter = axisLine->boundingRect().center();
+ QPointF titleCenterDiff = arrowCenter - titleCenter;
+ title->setPos(titleCenterDiff.x() - qreal(titlePadding()) - (titleBoundingRect.height() / 2.0), titleCenterDiff.y());
+ title->setTransformOriginPoint(titleCenter);
+ title->setRotation(270.0);
+ }
+
+ QGraphicsLayoutItem::updateGeometry();
+}
+
+Qt::Orientation PolarChartAxisRadial::orientation() const
+{
+ return Qt::Vertical;
+}
+
+void PolarChartAxisRadial::createItems(int count)
+{
+ if (arrowItems().count() == 0) {
+ // radial axis center line
+ QGraphicsLineItem *arrow = new LineArrowItem(this, presenter()->rootItem());
+ arrow->setPen(axis()->linePen());
+ arrowGroup()->addToGroup(arrow);
+ }
+
+ for (int i = 0; i < count; ++i) {
+ QGraphicsLineItem *arrow = new QGraphicsLineItem(presenter()->rootItem());
+ QGraphicsEllipseItem *grid = new QGraphicsEllipseItem(presenter()->rootItem());
+ QGraphicsSimpleTextItem *label = new QGraphicsSimpleTextItem(presenter()->rootItem());
+ QGraphicsSimpleTextItem *title = titleItem();
+ arrow->setPen(axis()->linePen());
+ grid->setPen(axis()->gridLinePen());
+ label->setFont(axis()->labelsFont());
+ label->setPen(axis()->labelsPen());
+ label->setBrush(axis()->labelsBrush());
+ label->setRotation(axis()->labelsAngle());
+ title->setFont(axis()->titleFont());
+ title->setPen(axis()->titlePen());
+ title->setBrush(axis()->titleBrush());
+ title->setText(axis()->titleText());
+ arrowGroup()->addToGroup(arrow);
+ gridGroup()->addToGroup(grid);
+ labelGroup()->addToGroup(label);
+ if (gridItems().size() == 1 || (((gridItems().size() + 1) % 2) && gridItems().size() > 0)) {
+ QGraphicsPathItem *shade = new QGraphicsPathItem(presenter()->rootItem());
+ shade->setPen(axis()->shadesPen());
+ shade->setBrush(axis()->shadesBrush());
+ shadeGroup()->addToGroup(shade);
+ }
+ }
+}
+
+void PolarChartAxisRadial::handleArrowPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, arrowItems())
+ static_cast<QGraphicsLineItem *>(item)->setPen(pen);
+}
+
+void PolarChartAxisRadial::handleGridPenChanged(const QPen &pen)
+{
+ foreach (QGraphicsItem *item, gridItems())
+ static_cast<QGraphicsEllipseItem *>(item)->setPen(pen);
+}
+
+QSizeF PolarChartAxisRadial::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_UNUSED(which);
+ Q_UNUSED(constraint);
+ return QSizeF(-1.0, -1.0);
+}
+
+qreal PolarChartAxisRadial::preferredAxisRadius(const QSizeF &maxSize)
+{
+ qreal radius = maxSize.height() / 2.0;
+ if (maxSize.width() < maxSize.height())
+ radius = maxSize.width() / 2.0;
+ return radius;
+}
+
+#include "moc_polarchartaxisradial_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/polarchartaxisradial_p.h b/src/axis/polarchartaxisradial_p.h
new file mode 100644
index 00000000..9874f28a
--- /dev/null
+++ b/src/axis/polarchartaxisradial_p.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTAXISRADIAL_P_H
+#define POLARCHARTAXISRADIAL_P_H
+
+#include "polarchartaxis_p.h"
+#include "qvalueaxis.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class PolarChartAxisRadial : public PolarChartAxis
+{
+ Q_OBJECT
+public:
+ PolarChartAxisRadial(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis = false);
+ ~PolarChartAxisRadial();
+
+ Qt::Orientation orientation() const;
+ QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
+
+ virtual void updateGeometry();
+ virtual void createItems(int count);
+
+ qreal preferredAxisRadius(const QSizeF &maxSize);
+
+public Q_SLOTS:
+ virtual void handleArrowPenChanged(const QPen &pen);
+ virtual void handleGridPenChanged(const QPen &pen);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTAXISRADIAL_P_H
diff --git a/src/axis/qabstractaxis.cpp b/src/axis/qabstractaxis.cpp
index 60e071d6..77c89b53 100644
--- a/src/axis/qabstractaxis.cpp
+++ b/src/axis/qabstractaxis.cpp
@@ -254,11 +254,11 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
/*!
\property QAbstractAxis::alignment
- The alignment of the axis. Either Qt::AlignLeft or Qt::AlignBottom.
+ The alignment of the axis. Can be Qt::AlignLeft, Qt::AlignRight, Qt::AlignBottom, or Qt::AlignTop.
*/
/*!
\qmlproperty alignment AbstractAxis::alignment
- The alignment of the axis. Either Qt.AlignLeft or Qt.AlignBottom.
+ The alignment of the axis. Can be Qt.AlignLeft, Qt.AlignRight, Qt.AlignBottom, or Qt.AlignTop.
*/
/*!
@@ -990,11 +990,11 @@ void QAbstractAxisPrivate::initializeGraphics(QGraphicsItem* parent)
void QAbstractAxisPrivate::initializeAnimations(QChart::AnimationOptions options)
{
- ChartAxis* axis = m_item.data();
+ ChartAxisElement *axis = m_item.data();
Q_ASSERT(axis);
- if(options.testFlag(QChart::GridAxisAnimations)) {
+ if (options.testFlag(QChart::GridAxisAnimations)) {
axis->setAnimation(new AxisAnimation(axis));
- }else{
+ } else {
axis->setAnimation(0);
}
}
diff --git a/src/axis/qabstractaxis.h b/src/axis/qabstractaxis.h
index 5ebd7974..e29325de 100644
--- a/src/axis/qabstractaxis.h
+++ b/src/axis/qabstractaxis.h
@@ -155,36 +155,37 @@ public:
Q_SIGNALS:
void visibleChanged(bool visible);
- void linePenChanged(const QPen& pen);
+ void linePenChanged(const QPen &pen);
void lineVisibleChanged(bool visible);
void labelsVisibleChanged(bool visible);
- void labelsPenChanged(const QPen& pen);
- void labelsBrushChanged(const QBrush& brush);
- void labelsFontChanged(const QFont& pen);
+ void labelsPenChanged(const QPen &pen);
+ void labelsBrushChanged(const QBrush &brush);
+ void labelsFontChanged(const QFont &pen);
void labelsAngleChanged(int angle);
- void gridLinePenChanged(const QPen& pen);
+ void gridLinePenChanged(const QPen &pen);
void gridVisibleChanged(bool visible);
void colorChanged(QColor color);
void labelsColorChanged(QColor color);
- void titleTextChanged(const QString& title);
- void titlePenChanged(const QPen& pen);
- void titleBrushChanged(const QBrush& brush);
+ void titleTextChanged(const QString &title);
+ void titlePenChanged(const QPen &pen);
+ void titleBrushChanged(const QBrush &brush);
void titleVisibleChanged(bool visible);
- void titleFontChanged(const QFont& font);
+ void titleFontChanged(const QFont &font);
void shadesVisibleChanged(bool visible);
void shadesColorChanged(QColor color);
void shadesBorderColorChanged(QColor color);
- void shadesPenChanged(const QPen& pen);
- void shadesBrushChanged(const QBrush& brush);
+ void shadesPenChanged(const QPen &pen);
+ void shadesBrushChanged(const QBrush &brush);
protected:
QScopedPointer<QAbstractAxisPrivate> d_ptr;
Q_DISABLE_COPY(QAbstractAxis)
friend class ChartDataSet;
- friend class ChartAxis;
friend class ChartPresenter;
friend class ChartThemeManager;
friend class AbstractDomain;
+ friend class ChartAxisElement;
+ friend class XYChart;
};
QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/qabstractaxis_p.h b/src/axis/qabstractaxis_p.h
index a284d46f..9ab993de 100644
--- a/src/axis/qabstractaxis_p.h
+++ b/src/axis/qabstractaxis_p.h
@@ -31,7 +31,7 @@
#define QABSTRACTAXIS_P_H
#include "qabstractaxis.h"
-#include "chartaxis_p.h"
+#include "chartaxiselement_p.h"
#include "qchart.h"
#include <QDebug>
@@ -59,7 +59,7 @@ public:
void setAlignment( Qt::Alignment alignment);
virtual void initializeDomain(AbstractDomain *domain) = 0;
- virtual void initializeGraphics(QGraphicsItem* parent) = 0;
+ virtual void initializeGraphics(QGraphicsItem *parent) = 0;
virtual void initializeTheme(ChartTheme* theme, bool forced = false);
virtual void initializeAnimations(QChart::AnimationOptions options);
@@ -73,7 +73,7 @@ public:
virtual qreal min() = 0;
virtual qreal max() = 0;
- ChartAxis* axisItem() { return m_item.data(); }
+ ChartAxisElement *axisItem() { return m_item.data(); }
public Q_SLOTS:
void handleRangeChanged(qreal min, qreal max);
@@ -84,7 +84,7 @@ Q_SIGNALS:
protected:
QAbstractAxis *q_ptr;
QChart *m_chart;
- QScopedPointer<ChartAxis> m_item;
+ QScopedPointer<ChartAxisElement> m_item;
private:
QList<QAbstractSeries*> m_series;
diff --git a/src/axis/valueaxis/chartvalueaxisx.cpp b/src/axis/valueaxis/chartvalueaxisx.cpp
index a084ac32..da6055f1 100644
--- a/src/axis/valueaxis/chartvalueaxisx.cpp
+++ b/src/axis/valueaxis/chartvalueaxisx.cpp
@@ -22,7 +22,7 @@
#include "qabstractaxis.h"
#include "chartpresenter_p.h"
#include "qvalueaxis.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QFontMetrics>
#include <qmath.h>
@@ -31,12 +31,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ChartValueAxisX::ChartValueAxisX(QValueAxis *axis, QGraphicsItem* item )
+ChartValueAxisX::ChartValueAxisX(QValueAxis *axis, QGraphicsItem *item )
: HorizontalAxis(axis, item),
m_axis(axis)
{
- QObject::connect(m_axis,SIGNAL(tickCountChanged(int)),this, SLOT(handleTickCountChanged(int)));
- QObject::connect(m_axis,SIGNAL(labelFormatChanged(QString)),this, SLOT(handleLabelFormatChanged(QString)));
+ QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
}
ChartValueAxisX::~ChartValueAxisX()
@@ -61,10 +61,10 @@ QVector<qreal> ChartValueAxisX::calculateLayout() const
void ChartValueAxisX::updateGeometry()
{
- const QVector<qreal>& layout = ChartAxis::layout();
+ const QVector<qreal>& layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
- setLabels(createValueLabels(min(),max(),layout.size(),m_axis->labelFormat()));
+ setLabels(createValueLabels(min(), max(), layout.size(), m_axis->labelFormat()));
HorizontalAxis::updateGeometry();
}
@@ -86,7 +86,7 @@ QSizeF ChartValueAxisX::sizeHint(Qt::SizeHint which, const QSizeF &constraint) c
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = HorizontalAxis::sizeHint(which, constraint);
diff --git a/src/axis/valueaxis/chartvalueaxisx_p.h b/src/axis/valueaxis/chartvalueaxisx_p.h
index e0556b60..bebfdb38 100644
--- a/src/axis/valueaxis/chartvalueaxisx_p.h
+++ b/src/axis/valueaxis/chartvalueaxisx_p.h
@@ -35,13 +35,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QValueAxis;
-class ChartPresenter;
class ChartValueAxisX : public HorizontalAxis
{
Q_OBJECT
public:
- ChartValueAxisX(QValueAxis *axis, QGraphicsItem* item = 0);
+ ChartValueAxisX(QValueAxis *axis, QGraphicsItem *item = 0);
~ChartValueAxisX();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
diff --git a/src/axis/valueaxis/chartvalueaxisy.cpp b/src/axis/valueaxis/chartvalueaxisy.cpp
index 14b2d207..54b58242 100644
--- a/src/axis/valueaxis/chartvalueaxisy.cpp
+++ b/src/axis/valueaxis/chartvalueaxisy.cpp
@@ -22,7 +22,7 @@
#include "qabstractaxis.h"
#include "chartpresenter_p.h"
#include "qvalueaxis.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include <QGraphicsLayout>
#include <QFontMetrics>
#include <qmath.h>
@@ -30,12 +30,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ChartValueAxisY::ChartValueAxisY(QValueAxis *axis, QGraphicsItem* item)
+ChartValueAxisY::ChartValueAxisY(QValueAxis *axis, QGraphicsItem *item)
: VerticalAxis(axis, item),
m_axis(axis)
{
- QObject::connect(m_axis,SIGNAL(tickCountChanged(int)),this, SLOT(handleTickCountChanged(int)));
- QObject::connect(m_axis,SIGNAL(labelFormatChanged(QString)),this, SLOT(handleLabelFormatChanged(QString)));
+ QObject::connect(m_axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(m_axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
}
ChartValueAxisY::~ChartValueAxisY()
@@ -62,7 +62,7 @@ QVector<qreal> ChartValueAxisY::calculateLayout() const
void ChartValueAxisY::updateGeometry()
{
- const QVector<qreal> &layout = ChartAxis::layout();
+ const QVector<qreal> &layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
setLabels(createValueLabels(min(),max(),layout.size(),m_axis->labelFormat()));
@@ -87,7 +87,7 @@ QSizeF ChartValueAxisY::sizeHint(Qt::SizeHint which, const QSizeF &constraint) c
{
Q_UNUSED(constraint)
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
QSizeF sh;
QSizeF base = VerticalAxis::sizeHint(which, constraint);
QStringList ticksList = createValueLabels(min(),max(),m_axis->tickCount(),m_axis->labelFormat());
diff --git a/src/axis/valueaxis/chartvalueaxisy_p.h b/src/axis/valueaxis/chartvalueaxisy_p.h
index 5a01b9b2..3b586698 100644
--- a/src/axis/valueaxis/chartvalueaxisy_p.h
+++ b/src/axis/valueaxis/chartvalueaxisy_p.h
@@ -35,13 +35,12 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
class QValueAxis;
-class ChartPresenter;
class ChartValueAxisY : public VerticalAxis
{
Q_OBJECT
public:
- ChartValueAxisY(QValueAxis *axis, QGraphicsItem* item = 0);
+ ChartValueAxisY(QValueAxis *axis, QGraphicsItem *item = 0);
~ChartValueAxisY();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint) const;
diff --git a/src/axis/valueaxis/polarchartvalueaxisangular.cpp b/src/axis/valueaxis/polarchartvalueaxisangular.cpp
new file mode 100644
index 00000000..5fdbcb4b
--- /dev/null
+++ b/src/axis/valueaxis/polarchartvalueaxisangular.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartvalueaxisangular_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartValueAxisAngular::PolarChartValueAxisAngular(QValueAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisAngular(axis, item)
+{
+ QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
+}
+
+PolarChartValueAxisAngular::~PolarChartValueAxisAngular()
+{
+}
+
+QVector<qreal> PolarChartValueAxisAngular::calculateLayout() const
+{
+ int tickCount = static_cast<QValueAxis *>(axis())->tickCount();
+ Q_ASSERT(tickCount >= 2);
+
+ QVector<qreal> points;
+ points.resize(tickCount);
+
+ const qreal d = 360.0 / qreal(tickCount - 1);
+
+ for (int i = 0; i < tickCount; ++i) {
+ qreal angularCoordinate = qreal(i) * d;
+ points[i] = angularCoordinate;
+ }
+
+ return points;
+}
+
+void PolarChartValueAxisAngular::createAxisLabels(const QVector<qreal> &layout)
+{
+ QStringList labelList = createValueLabels(min(), max(), layout.size(), static_cast<QValueAxis *>(axis())->labelFormat());
+ setLabels(labelList);
+}
+
+void PolarChartValueAxisAngular::handleTickCountChanged(int tick)
+{
+ Q_UNUSED(tick);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+void PolarChartValueAxisAngular::handleLabelFormatChanged(const QString &format)
+{
+ Q_UNUSED(format);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_polarchartvalueaxisangular_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/valueaxis/polarchartvalueaxisangular_p.h b/src/axis/valueaxis/polarchartvalueaxisangular_p.h
new file mode 100644
index 00000000..afe5192a
--- /dev/null
+++ b/src/axis/valueaxis/polarchartvalueaxisangular_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTVALUEAXISANGULAR_P_H
+#define POLARCHARTVALUEAXISANGULAR_P_H
+
+#include "polarchartaxisangular_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QValueAxis;
+
+class PolarChartValueAxisAngular : public PolarChartAxisAngular
+{
+ Q_OBJECT
+public:
+ PolarChartValueAxisAngular(QValueAxis *axis, QGraphicsItem *item);
+ ~PolarChartValueAxisAngular();
+
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+private Q_SLOTS:
+ void handleTickCountChanged(int tick);
+ void handleLabelFormatChanged(const QString &format);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTVALUEAXISANGULAR_P_H
diff --git a/src/axis/valueaxis/polarchartvalueaxisradial.cpp b/src/axis/valueaxis/polarchartvalueaxisradial.cpp
new file mode 100644
index 00000000..f11e9265
--- /dev/null
+++ b/src/axis/valueaxis/polarchartvalueaxisradial.cpp
@@ -0,0 +1,79 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartvalueaxisradial_p.h"
+#include "chartpresenter_p.h"
+#include "abstractchartlayout_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarChartValueAxisRadial::PolarChartValueAxisRadial(QValueAxis *axis, QGraphicsItem *item)
+ : PolarChartAxisRadial(axis, item)
+{
+ QObject::connect(axis, SIGNAL(tickCountChanged(int)), this, SLOT(handleTickCountChanged(int)));
+ QObject::connect(axis, SIGNAL(labelFormatChanged(QString)), this, SLOT(handleLabelFormatChanged(QString)));
+}
+
+PolarChartValueAxisRadial::~PolarChartValueAxisRadial()
+{
+}
+
+QVector<qreal> PolarChartValueAxisRadial::calculateLayout() const
+{
+ int tickCount = static_cast<QValueAxis *>(axis())->tickCount();
+ Q_ASSERT(tickCount >= 2);
+
+ QVector<qreal> points;
+ points.resize(tickCount);
+
+ const qreal d = (axisGeometry().width() / 2) / qreal(tickCount - 1);
+
+ for (int i = 0; i < tickCount; ++i) {
+ qreal radialCoordinate = qreal(i) * d;
+ points[i] = radialCoordinate;
+ }
+
+ return points;
+}
+
+void PolarChartValueAxisRadial::createAxisLabels(const QVector<qreal> &layout)
+{
+ setLabels(createValueLabels(min(), max(), layout.size(), static_cast<QValueAxis *>(axis())->labelFormat()));
+}
+
+void PolarChartValueAxisRadial::handleTickCountChanged(int tick)
+{
+ Q_UNUSED(tick);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+void PolarChartValueAxisRadial::handleLabelFormatChanged(const QString &format)
+{
+ Q_UNUSED(format);
+ QGraphicsLayoutItem::updateGeometry();
+ if (presenter())
+ presenter()->layout()->invalidate();
+}
+
+#include "moc_polarchartvalueaxisradial_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/axis/valueaxis/polarchartvalueaxisradial_p.h b/src/axis/valueaxis/polarchartvalueaxisradial_p.h
new file mode 100644
index 00000000..f443d1dc
--- /dev/null
+++ b/src/axis/valueaxis/polarchartvalueaxisradial_p.h
@@ -0,0 +1,56 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTVALUEAXISRADIAL_P_H
+#define POLARCHARTVALUEAXISRADIAL_P_H
+
+#include "polarchartaxisradial_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QValueAxis;
+
+class PolarChartValueAxisRadial : public PolarChartAxisRadial
+{
+ Q_OBJECT
+public:
+ PolarChartValueAxisRadial(QValueAxis *axis, QGraphicsItem *item);
+ ~PolarChartValueAxisRadial();
+
+ virtual QVector<qreal> calculateLayout() const;
+ virtual void createAxisLabels(const QVector<qreal> &layout);
+
+private Q_SLOTS:
+ void handleTickCountChanged(int tick);
+ void handleLabelFormatChanged(const QString &format);
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTVALUEAXISRADIAL_P_H
diff --git a/src/axis/valueaxis/qvalueaxis.cpp b/src/axis/valueaxis/qvalueaxis.cpp
index 032fb4e1..80aa25ce 100644
--- a/src/axis/valueaxis/qvalueaxis.cpp
+++ b/src/axis/valueaxis/qvalueaxis.cpp
@@ -23,6 +23,8 @@
#include "chartvalueaxisx_p.h"
#include "chartvalueaxisy_p.h"
#include "abstractdomain_p.h"
+#include "polarchartvalueaxisangular_p.h"
+#include "polarchartvalueaxisradial_p.h"
#include "chartdataset_p.h"
#include "chartpresenter_p.h"
#include "charttheme_p.h"
@@ -387,14 +389,24 @@ void QValueAxisPrivate::setRange(qreal min, qreal max)
}
}
-void QValueAxisPrivate::initializeGraphics(QGraphicsItem* parent)
+void QValueAxisPrivate::initializeGraphics(QGraphicsItem *parent)
{
Q_Q(QValueAxis);
- ChartAxis* axis(0);
- if (orientation() == Qt::Vertical)
- axis = new ChartValueAxisY(q,parent);
- if (orientation() == Qt::Horizontal)
- axis = new ChartValueAxisX(q,parent);
+ ChartAxisElement *axis(0);
+
+ if (m_chart->chartType() == QChart::ChartTypeCartesian) {
+ if (orientation() == Qt::Vertical)
+ axis = new ChartValueAxisY(q,parent);
+ if (orientation() == Qt::Horizontal)
+ axis = new ChartValueAxisX(q,parent);
+ }
+
+ if (m_chart->chartType() == QChart::ChartTypePolar) {
+ if (orientation() == Qt::Vertical)
+ axis = new PolarChartValueAxisRadial(q, parent);
+ if (orientation() == Qt::Horizontal)
+ axis = new PolarChartValueAxisAngular(q, parent);
+ }
m_item.reset(axis);
QAbstractAxisPrivate::initializeGraphics(parent);
@@ -404,20 +416,16 @@ void QValueAxisPrivate::initializeGraphics(QGraphicsItem* parent)
void QValueAxisPrivate::initializeDomain(AbstractDomain *domain)
{
if (orientation() == Qt::Vertical) {
- if(!qFuzzyIsNull(m_max - m_min)) {
+ if (!qFuzzyIsNull(m_max - m_min))
domain->setRangeY(m_min, m_max);
- }
- else {
+ else
setRange(domain->minY(), domain->maxY());
- }
}
if (orientation() == Qt::Horizontal) {
- if(!qFuzzyIsNull(m_max - m_min)) {
+ if (!qFuzzyIsNull(m_max - m_min))
domain->setRangeX(m_min, m_max);
- }
- else {
+ else
setRange(domain->minX(), domain->maxX());
- }
}
}
diff --git a/src/axis/verticalaxis.cpp b/src/axis/verticalaxis.cpp
index d3c5efa6..3726359b 100644
--- a/src/axis/verticalaxis.cpp
+++ b/src/axis/verticalaxis.cpp
@@ -25,31 +25,29 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem* item, bool intervalAxis)
- : ChartAxis(axis, item, intervalAxis)
+VerticalAxis::VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item, bool intervalAxis)
+ : CartesianChartAxis(axis, item, intervalAxis)
{
-
}
VerticalAxis::~VerticalAxis()
{
-
}
void VerticalAxis::updateGeometry()
{
- const QVector<qreal> &layout = ChartAxis::layout();
+ const QVector<qreal> &layout = ChartAxisElement::layout();
if (layout.isEmpty())
return;
QStringList labelList = labels();
- QList<QGraphicsItem *> lines = lineItems();
+ QList<QGraphicsItem *> lines = gridItems();
QList<QGraphicsItem *> labels = labelItems();
QList<QGraphicsItem *> shades = shadeItems();
- QList<QGraphicsItem *> axis = arrowItems();
- QGraphicsSimpleTextItem* title = titleItem();
+ QList<QGraphicsItem *> arrow = arrowItems();
+ QGraphicsSimpleTextItem *title = titleItem();
Q_ASSERT(labels.size() == labelList.size());
Q_ASSERT(layout.size() == labelList.size());
@@ -61,32 +59,31 @@ void VerticalAxis::updateGeometry()
//arrow
- QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(axis.at(0));
+ QGraphicsLineItem *arrowItem = static_cast<QGraphicsLineItem*>(arrow.at(0));
//arrow position
- if (alignment()==Qt::AlignLeft)
- arrowItem->setLine( axisRect.right() , gridRect.top(), axisRect.right(), gridRect.bottom());
- else if(alignment()==Qt::AlignRight)
- arrowItem->setLine( axisRect.left() , gridRect.top(), axisRect.left(), gridRect.bottom());
+ if (axis()->alignment() == Qt::AlignLeft)
+ arrowItem->setLine(axisRect.right(), gridRect.top(), axisRect.right(), gridRect.bottom());
+ else if (axis()->alignment() == Qt::AlignRight)
+ arrowItem->setLine(axisRect.left(), gridRect.top(), axisRect.left(), gridRect.bottom());
- QFontMetrics fn(font());
+ QFontMetrics fn(axis()->labelsFont());
//title
int titlePad = 0;
QRectF titleBoundingRect;
- if (!titleText().isEmpty() && titleItem()->isVisible()) {
+ QString titleText = axis()->titleText();
+ if (!titleText.isEmpty() && titleItem()->isVisible()) {
QFontMetrics fn(title->font());
int size(0);
size = gridRect.height();
- QString titleText = this->titleText();
if (fn.boundingRect(titleText).width() > size) {
QString string = titleText + "...";
while (fn.boundingRect(string).width() > size && string.length() > 3)
- string.remove(string.length() - 4, 1);
+ string.remove(string.length() - 4, 1);
title->setText(string);
- }
- else {
+ } else {
title->setText(titleText);
}
@@ -94,10 +91,10 @@ void VerticalAxis::updateGeometry()
titleBoundingRect = title->boundingRect();
QPointF center = gridRect.center() - titleBoundingRect.center();
- if (alignment() == Qt::AlignLeft) {
+ if (axis()->alignment() == Qt::AlignLeft) {
title->setPos(axisRect.left() - titleBoundingRect.width() / 2 + titleBoundingRect.height() / 2 + titlePad, center.y());
}
- else if (alignment() == Qt::AlignRight) {
+ else if (axis()->alignment() == Qt::AlignRight) {
title->setPos(axisRect.right() - titleBoundingRect.width() / 2 - titleBoundingRect.height() / 2 - titlePad, center.y());
}
title->setTransformOriginPoint(titleBoundingRect.center());
@@ -105,14 +102,13 @@ void VerticalAxis::updateGeometry()
}
for (int i = 0; i < layout.size(); ++i) {
-
//items
QGraphicsLineItem *gridItem = static_cast<QGraphicsLineItem *>(lines.at(i));
- QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(axis.at(i + 1));
+ QGraphicsLineItem *tickItem = static_cast<QGraphicsLineItem *>(arrow.at(i + 1));
QGraphicsSimpleTextItem *labelItem = static_cast<QGraphicsSimpleTextItem *>(labels.at(i));
//grid line
- gridItem->setLine(gridRect.left() , layout[i], gridRect.right(), layout[i]);
+ gridItem->setLine(gridRect.left(), layout[i], gridRect.right(), layout[i]);
//label text wrapping
QString text = labelList.at(i);
@@ -138,10 +134,10 @@ void VerticalAxis::updateGeometry()
int widthDiff = rect.width() - boundingRect.width();
//ticks and label position
- if (alignment() == Qt::AlignLeft) {
+ if (axis()->alignment() == Qt::AlignLeft) {
labelItem->setPos(axisRect.right() - rect.width() + (widthDiff / 2) - labelPadding(), layout[i] - center.y());
tickItem->setLine(axisRect.right() - labelPadding(), layout[i], axisRect.right(), layout[i]);
- } else if (alignment() == Qt::AlignRight) {
+ } else if (axis()->alignment() == Qt::AlignRight) {
labelItem->setPos(axisRect.left() + labelPadding() - (widthDiff / 2), layout[i] - center.y());
tickItem->setLine(axisRect.left(), layout[i], axisRect.left() + labelPadding(), layout[i]);
}
@@ -202,7 +198,7 @@ void VerticalAxis::updateGeometry()
gridLine = static_cast<QGraphicsLineItem *>(lines.at(layout.size()));
gridLine->setLine(gridRect.left(), gridRect.top(), gridRect.right(), gridRect.top());
gridLine->setVisible(true);
- gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size()+1));
+ gridLine = static_cast<QGraphicsLineItem*>(lines.at(layout.size() + 1));
gridLine->setLine(gridRect.left(), gridRect.bottom(), gridRect.right(), gridRect.bottom());
gridLine->setVisible(true);
}
@@ -212,10 +208,10 @@ QSizeF VerticalAxis::sizeHint(Qt::SizeHint which, const QSizeF &constraint) cons
{
Q_UNUSED(constraint);
- QFontMetrics fn(titleFont());
- QSizeF sh(0,0);
+ QFontMetrics fn(axis()->titleFont());
+ QSizeF sh(0, 0);
- if (titleText().isEmpty() || !titleItem()->isVisible())
+ if (axis()->titleText().isEmpty() || !titleItem()->isVisible())
return sh;
switch (which) {
diff --git a/src/axis/verticalaxis_p.h b/src/axis/verticalaxis_p.h
index 4d186c44..159bba63 100644
--- a/src/axis/verticalaxis_p.h
+++ b/src/axis/verticalaxis_p.h
@@ -30,14 +30,14 @@
#ifndef VERTICALAXIS_P_H_
#define VERTICALAXIS_P_H_
-#include "chartaxis_p.h"
+#include "cartesianchartaxis_p.h"
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-class VerticalAxis : public ChartAxis
+class VerticalAxis : public CartesianChartAxis
{
public:
- VerticalAxis(QAbstractAxis *axis, QGraphicsItem* item = 0, bool intervalAxis = false);
+ VerticalAxis(QAbstractAxis *axis, QGraphicsItem *item = 0, bool intervalAxis = false);
~VerticalAxis();
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
protected:
diff --git a/src/chartdataset.cpp b/src/chartdataset.cpp
index d5401663..4d7e1a09 100644
--- a/src/chartdataset.cpp
+++ b/src/chartdataset.cpp
@@ -33,9 +33,13 @@
#include "qpieseries.h"
#include "chartitem_p.h"
#include "xydomain_p.h"
+#include "xypolardomain_p.h"
#include "xlogydomain_p.h"
#include "logxydomain_p.h"
#include "logxlogydomain_p.h"
+#include "xlogypolardomain_p.h"
+#include "logxypolardomain_p.h"
+#include "logxlogypolardomain_p.h"
#ifndef QT_ON_ARM
#include "qdatetimeaxis.h"
@@ -66,6 +70,20 @@ void ChartDataSet::addSeries(QAbstractSeries *series)
return;
}
+ // Ignore unsupported series added to polar chart
+ if (m_chart && m_chart->chartType() == QChart::ChartTypePolar) {
+ if (!(series->type() == QAbstractSeries::SeriesTypeArea
+ || series->type() == QAbstractSeries::SeriesTypeLine
+ || series->type() == QAbstractSeries::SeriesTypeScatter
+ || series->type() == QAbstractSeries::SeriesTypeSpline)) {
+ qWarning() << QObject::tr("Can not add series. Series type is not supported by a polar chart.");
+ return;
+ }
+ series->d_ptr->setDomain(new XYPolarDomain());
+ } else {
+ series->d_ptr->setDomain(new XYDomain());
+ }
+
series->d_ptr->initializeDomain();
m_seriesList.append(series);
@@ -78,7 +96,7 @@ void ChartDataSet::addSeries(QAbstractSeries *series)
/*
* This method adds axis to chartdataset, axis ownership is taken from caller.
*/
-void ChartDataSet::addAxis(QAbstractAxis *axis,Qt::Alignment aligment)
+void ChartDataSet::addAxis(QAbstractAxis *axis, Qt::Alignment aligment)
{
if (m_axisList.contains(axis)) {
qWarning() << QObject::tr("Can not add axis. Axis already on the chart.");
@@ -87,12 +105,25 @@ void ChartDataSet::addAxis(QAbstractAxis *axis,Qt::Alignment aligment)
axis->d_ptr->setAlignment(aligment);
- if(!axis->alignment()) {
- qWarning()<< QObject::tr("No alignment specified !");
+ if (!axis->alignment()) {
+ qWarning() << QObject::tr("No alignment specified !");
return;
};
- QSharedPointer<AbstractDomain> domain(new XYDomain());
+ AbstractDomain *newDomain;
+ if (m_chart && m_chart->chartType() == QChart::ChartTypePolar) {
+ foreach (QAbstractAxis *existingAxis, axes()) {
+ if (existingAxis->orientation() == axis->orientation()) {
+ qWarning() << QObject::tr("Cannot add multiple axes of same orientation to a polar chart!");
+ return;
+ }
+ }
+ newDomain = new XYPolarDomain();
+ } else {
+ newDomain = new XYDomain();
+ }
+
+ QSharedPointer<AbstractDomain> domain(newDomain);
axis->d_ptr->initializeDomain(domain.data());
axis->setParent(this);
@@ -122,6 +153,8 @@ void ChartDataSet::removeSeries(QAbstractSeries *series)
emit seriesRemoved(series);
m_seriesList.removeAll(series);
+ // Reset domain to default
+ series->d_ptr->setDomain(new XYDomain());
series->setParent(0);
series->d_ptr->m_chart = 0;
}
@@ -152,13 +185,13 @@ void ChartDataSet::removeAxis(QAbstractAxis *axis)
/*
* This method attaches axis to series, return true if success.
*/
-bool ChartDataSet::attachAxis(QAbstractSeries* series,QAbstractAxis *axis)
+bool ChartDataSet::attachAxis(QAbstractSeries *series,QAbstractAxis *axis)
{
Q_ASSERT(series);
Q_ASSERT(axis);
- QList<QAbstractSeries* > attachedSeriesList = axis->d_ptr->m_series;
- QList<QAbstractAxis* > attachedAxisList = series->d_ptr->m_axes;
+ QList<QAbstractSeries *> attachedSeriesList = axis->d_ptr->m_series;
+ QList<QAbstractAxis *> attachedAxisList = series->d_ptr->m_axes;
if (!m_seriesList.contains(series)) {
qWarning() << QObject::tr("Can not find series on the chart.");
@@ -180,25 +213,42 @@ bool ChartDataSet::attachAxis(QAbstractSeries* series,QAbstractAxis *axis)
return false;
}
- AbstractDomain* domain = series->d_ptr->domain();
+ AbstractDomain *domain = series->d_ptr->domain();
AbstractDomain::DomainType type = selectDomain(attachedAxisList<<axis);
- if(type == AbstractDomain::UndefinedDomain) return false;
+ if (type == AbstractDomain::UndefinedDomain) return false;
- if(domain->type()!=type){
+ if (domain->type() != type) {
AbstractDomain *old = domain;
- domain = createDomain(type);
+ domain = createDomain(type);
domain->setRange(old->minX(), old->maxX(), old->minY(), old->maxY());
+ // Initialize domain size to old domain size, as it won't get updated
+ // unless geometry changes.
+ domain->setSize(old->size());
}
- if(!domain) return false;
+ if (!domain)
+ return false;
+
+ if (!domain->attachAxis(axis))
+ return false;
- if(!domain->attachAxis(axis)) return false;
+ QList<AbstractDomain *> blockedDomains;
+ domain->blockRangeSignals(true);
+ blockedDomains << domain;
- if(domain!=series->d_ptr->domain()){
- foreach(QAbstractAxis* axis,series->d_ptr->m_axes){
+ if (domain != series->d_ptr->domain()) {
+ foreach (QAbstractAxis *axis, series->d_ptr->m_axes) {
series->d_ptr->domain()->detachAxis(axis);
domain->attachAxis(axis);
+ foreach (QAbstractSeries *otherSeries, axis->d_ptr->m_series) {
+ if (otherSeries != series && otherSeries->d_ptr->domain()) {
+ if (!otherSeries->d_ptr->domain()->rangeSignalsBlocked()) {
+ otherSeries->d_ptr->domain()->blockRangeSignals(true);
+ blockedDomains << otherSeries->d_ptr->domain();
+ }
+ }
+ }
}
series->d_ptr->setDomain(domain);
series->d_ptr->initializeDomain();
@@ -210,6 +260,9 @@ bool ChartDataSet::attachAxis(QAbstractSeries* series,QAbstractAxis *axis)
series->d_ptr->initializeAxes();
axis->d_ptr->initializeDomain(domain);
+ foreach (AbstractDomain *blockedDomain, blockedDomains)
+ blockedDomain->blockRangeSignals(false);
+
return true;
}
@@ -327,12 +380,12 @@ void ChartDataSet::findMinMaxForSeries(QList<QAbstractSeries *> series,Qt::Orien
{
Q_ASSERT(!series.isEmpty());
- AbstractDomain* domain = series.first()->d_ptr->domain();
+ AbstractDomain *domain = series.first()->d_ptr->domain();
min = (orientation == Qt::Vertical) ? domain->minY() : domain->minX();
max = (orientation == Qt::Vertical) ? domain->maxY() : domain->maxX();
- for(int i = 1; i< series.size(); i++) {
- AbstractDomain* domain = series[i]->d_ptr->domain();
+ for (int i = 1; i< series.size(); i++) {
+ AbstractDomain *domain = series[i]->d_ptr->domain();
min = qMin((orientation == Qt::Vertical) ? domain->minY() : domain->minX(), min);
max = qMax((orientation == Qt::Vertical) ? domain->maxY() : domain->maxX(), max);
}
@@ -437,7 +490,7 @@ QPointF ChartDataSet::mapToPosition(const QPointF &value, QAbstractSeries *serie
return point;
}
-QList<QAbstractAxis*> ChartDataSet::axes() const
+QList<QAbstractAxis *> ChartDataSet::axes() const
{
return m_axisList;
}
@@ -447,7 +500,7 @@ QList<QAbstractSeries *> ChartDataSet::series() const
return m_seriesList;
}
-AbstractDomain::DomainType ChartDataSet::selectDomain(QList<QAbstractAxis*> axes)
+AbstractDomain::DomainType ChartDataSet::selectDomain(QList<QAbstractAxis *> axes)
{
enum Type {
Undefined = 0,
@@ -458,75 +511,95 @@ AbstractDomain::DomainType ChartDataSet::selectDomain(QList<QAbstractAxis*> axes
int horizontal(Undefined);
int vertical(Undefined);
- foreach(QAbstractAxis* axis, axes)
- {
- switch(axis->type()) {
- case QAbstractAxis::AxisTypeLogValue:
-
- if(axis->orientation()==Qt::Horizontal) {
- horizontal|=LogType;
- }
- if(axis->orientation()==Qt::Vertical) {
- vertical|=LogType;
- }
+ // Assume cartesian chart type, unless chart is set
+ QChart::ChartType chartType(QChart::ChartTypeCartesian);
+ if (m_chart)
+ chartType = m_chart->chartType();
+ foreach (QAbstractAxis *axis, axes)
+ {
+ switch (axis->type()) {
+ case QAbstractAxis::AxisTypeLogValue:
+ if (axis->orientation() == Qt::Horizontal)
+ horizontal |= LogType;
+ if (axis->orientation() == Qt::Vertical)
+ vertical |= LogType;
break;
- case QAbstractAxis::AxisTypeValue:
- case QAbstractAxis::AxisTypeBarCategory:
- case QAbstractAxis::AxisTypeCategory:
- case QAbstractAxis::AxisTypeDateTime:
- if(axis->orientation()==Qt::Horizontal) {
- horizontal|=ValueType;
- }
- if(axis->orientation()==Qt::Vertical) {
- vertical|=ValueType;
- }
+ case QAbstractAxis::AxisTypeValue:
+ case QAbstractAxis::AxisTypeBarCategory:
+ case QAbstractAxis::AxisTypeCategory:
+ case QAbstractAxis::AxisTypeDateTime:
+ if (axis->orientation() == Qt::Horizontal)
+ horizontal |= ValueType;
+ if (axis->orientation() == Qt::Vertical)
+ vertical |= ValueType;
break;
- default:
- qWarning()<<"Undefined type";
+ default:
+ qWarning() << "Undefined type";
break;
}
}
- if(vertical==Undefined) vertical=ValueType;
- if(horizontal==Undefined) horizontal=ValueType;
+ if (vertical == Undefined)
+ vertical = ValueType;
+ if (horizontal == Undefined)
+ horizontal = ValueType;
- if(vertical==ValueType && horizontal== ValueType) {
- return AbstractDomain::XYDomain;
+ if (vertical == ValueType && horizontal == ValueType) {
+ if (chartType == QChart::ChartTypeCartesian)
+ return AbstractDomain::XYDomain;
+ else if (chartType == QChart::ChartTypePolar)
+ return AbstractDomain::XYPolarDomain;
}
- if(vertical==LogType && horizontal== ValueType) {
- return AbstractDomain::XLogYDomain;
+ if (vertical == LogType && horizontal == ValueType) {
+ if (chartType == QChart::ChartTypeCartesian)
+ return AbstractDomain::XLogYDomain;
+ if (chartType == QChart::ChartTypePolar)
+ return AbstractDomain::XLogYPolarDomain;
}
- if(vertical==ValueType && horizontal== LogType) {
- return AbstractDomain::LogXYDomain;
+ if (vertical == ValueType && horizontal == LogType) {
+ if (chartType == QChart::ChartTypeCartesian)
+ return AbstractDomain::LogXYDomain;
+ else if (chartType == QChart::ChartTypePolar)
+ return AbstractDomain::LogXYPolarDomain;
}
- if(vertical==LogType && horizontal== LogType) {
- return AbstractDomain::LogXLogYDomain;
+ if (vertical == LogType && horizontal == LogType) {
+ if (chartType == QChart::ChartTypeCartesian)
+ return AbstractDomain::LogXLogYDomain;
+ else if (chartType == QChart::ChartTypePolar)
+ return AbstractDomain::LogXLogYPolarDomain;
}
return AbstractDomain::UndefinedDomain;
}
-
//refactor create factory
AbstractDomain* ChartDataSet::createDomain(AbstractDomain::DomainType type)
{
- switch(type)
- {
- case AbstractDomain::LogXLogYDomain:
- return new LogXLogYDomain();
- case AbstractDomain::XYDomain:
- return new XYDomain();
- case AbstractDomain::XLogYDomain:
- return new XLogYDomain();
- case AbstractDomain::LogXYDomain:
- return new LogXYDomain();
- default:
- return 0;
- }
+ switch (type)
+ {
+ case AbstractDomain::LogXLogYDomain:
+ return new LogXLogYDomain();
+ case AbstractDomain::XYDomain:
+ return new XYDomain();
+ case AbstractDomain::XLogYDomain:
+ return new XLogYDomain();
+ case AbstractDomain::LogXYDomain:
+ return new LogXYDomain();
+ case AbstractDomain::XYPolarDomain:
+ return new XYPolarDomain();
+ case AbstractDomain::XLogYPolarDomain:
+ return new XLogYPolarDomain();
+ case AbstractDomain::LogXYPolarDomain:
+ return new LogXYPolarDomain();
+ case AbstractDomain::LogXLogYPolarDomain:
+ return new LogXLogYPolarDomain();
+ default:
+ return 0;
+ }
}
#include "moc_chartdataset_p.cpp"
diff --git a/src/chartpresenter.cpp b/src/chartpresenter.cpp
index 8194f084..f8242aac 100644
--- a/src/chartpresenter.cpp
+++ b/src/chartpresenter.cpp
@@ -27,24 +27,28 @@
#include "chartanimation_p.h"
#include "qabstractseries_p.h"
#include "qareaseries.h"
-#include "chartaxis_p.h"
+#include "chartaxiselement_p.h"
#include "chartbackground_p.h"
-#include "chartlayout_p.h"
+#include "cartesianchartlayout_p.h"
+#include "polarchartlayout_p.h"
#include "charttitle_p.h"
#include <QTimer>
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ChartPresenter::ChartPresenter(QChart *chart)
+ChartPresenter::ChartPresenter(QChart *chart, QChart::ChartType type)
: QObject(chart),
m_chart(chart),
m_options(QChart::NoAnimation),
m_state(ShowState),
- m_layout(new ChartLayout(this)),
m_background(0),
m_title(0)
{
-
+ if (type == QChart::ChartTypeCartesian)
+ m_layout = new CartesianChartLayout(this);
+ else if (type == QChart::ChartTypePolar)
+ m_layout = new PolarChartLayout(this);
+ Q_ASSERT(m_layout);
}
ChartPresenter::~ChartPresenter()
@@ -54,25 +58,25 @@ ChartPresenter::~ChartPresenter()
void ChartPresenter::setGeometry(const QRectF rect)
{
- if(m_rect != rect) {
- m_rect=rect;
- foreach (ChartItem *chart, m_chartItems){
- chart->domain()->setSize(rect.size());
- chart->setPos(rect.topLeft());
- }
- }
+ if (m_rect != rect) {
+ m_rect = rect;
+ foreach (ChartItem *chart, m_chartItems) {
+ chart->domain()->setSize(rect.size());
+ chart->setPos(rect.topLeft());
+ }
+ }
}
QRectF ChartPresenter::geometry() const
{
- return m_rect;
+ return m_rect;
}
void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
{
axis->d_ptr->initializeGraphics(rootItem());
axis->d_ptr->initializeAnimations(m_options);
- ChartAxis *item = axis->d_ptr->axisItem();
+ ChartAxisElement *item = axis->d_ptr->axisItem();
item->setPresenter(this);
item->setThemeManager(m_chart->d_ptr->m_themeManager);
m_axisItems<<item;
@@ -82,7 +86,7 @@ void ChartPresenter::handleAxisAdded(QAbstractAxis *axis)
void ChartPresenter::handleAxisRemoved(QAbstractAxis *axis)
{
- ChartAxis *item = axis->d_ptr->m_item.take();
+ ChartAxisElement *item = axis->d_ptr->m_item.take();
item->hide();
item->disconnect();
item->deleteLater();
@@ -275,7 +279,7 @@ bool ChartPresenter::isBackgroundDropShadowEnabled() const
}
-ChartLayout *ChartPresenter::layout()
+AbstractChartLayout *ChartPresenter::layout()
{
return m_layout;
}
@@ -295,7 +299,7 @@ ChartBackground *ChartPresenter::backgroundElement()
return m_background;
}
-QList<ChartAxis *> ChartPresenter::axisItems() const
+QList<ChartAxisElement *> ChartPresenter::axisItems() const
{
return m_axisItems;
}
diff --git a/src/chartpresenter_p.h b/src/chartpresenter_p.h
index 9f1c8b89..19bc5c42 100644
--- a/src/chartpresenter_p.h
+++ b/src/chartpresenter_p.h
@@ -42,12 +42,12 @@ class AxisItem;
class QAbstractSeries;
class ChartDataSet;
class AbstractDomain;
-class ChartAxis;
+class ChartAxisElement;
class ChartAnimator;
class ChartBackground;
class ChartTitle;
class ChartAnimation;
-class ChartLayout;
+class AbstractChartLayout;
class ChartPresenter: public QObject
{
@@ -78,7 +78,7 @@ public:
ZoomOutState
};
- ChartPresenter(QChart *chart);
+ ChartPresenter(QChart *chart, QChart::ChartType type);
virtual ~ChartPresenter();
@@ -88,12 +88,9 @@ public:
QGraphicsItem *rootItem(){ return m_chart; }
ChartBackground *backgroundElement();
ChartTitle *titleElement();
- QList<ChartAxis *> axisItems() const;
+ QList<ChartAxisElement *> axisItems() const;
QList<ChartItem *> chartItems() const;
- ChartItem* chartElement(QAbstractSeries* series) const;
- ChartAxis* chartElement(QAbstractAxis* axis) const;
-
QLegend *legend();
void setBackgroundBrush(const QBrush &brush);
@@ -128,7 +125,9 @@ public:
void setState(State state,QPointF point);
State state() const { return m_state; }
QPointF statePoint() const { return m_statePoint; }
- ChartLayout *layout();
+ AbstractChartLayout *layout();
+
+ QChart::ChartType chartType() const { return m_chart->chartType(); }
private:
void createBackgroundItem();
@@ -149,14 +148,14 @@ Q_SIGNALS:
private:
QChart *m_chart;
QList<ChartItem *> m_chartItems;
- QList<ChartAxis *> m_axisItems;
+ QList<ChartAxisElement *> m_axisItems;
QList<QAbstractSeries *> m_series;
QList<QAbstractAxis *> m_axes;
QChart::AnimationOptions m_options;
State m_state;
QPointF m_statePoint;
QList<ChartAnimation *> m_animations;
- ChartLayout *m_layout;
+ AbstractChartLayout *m_layout;
ChartBackground *m_background;
ChartTitle *m_title;
QRectF m_rect;
diff --git a/src/domain/abstractdomain.cpp b/src/domain/abstractdomain.cpp
index bcaa5164..277472d1 100644
--- a/src/domain/abstractdomain.cpp
+++ b/src/domain/abstractdomain.cpp
@@ -38,7 +38,7 @@ AbstractDomain::~AbstractDomain()
{
}
-void AbstractDomain::setSize(const QSizeF& size)
+void AbstractDomain::setSize(const QSizeF &size)
{
if(m_size!=size)
{
@@ -122,9 +122,9 @@ void AbstractDomain::handleHorizontalAxisRangeChanged(qreal min, qreal max)
void AbstractDomain::blockRangeSignals(bool block)
{
- if(m_signalsBlocked!=block){
+ if (m_signalsBlocked!=block) {
m_signalsBlocked=block;
- if(!block) {
+ if (!block) {
emit rangeHorizontalChanged(m_minX,m_maxX);
emit rangeVerticalChanged(m_minY,m_maxY);
}
@@ -165,14 +165,14 @@ qreal AbstractDomain::niceNumber(qreal x, bool ceiling)
return q * z;
}
-bool AbstractDomain::attachAxis(QAbstractAxis* axis)
+bool AbstractDomain::attachAxis(QAbstractAxis *axis)
{
- if(axis->orientation()==Qt::Vertical) {
+ if (axis->orientation() == Qt::Vertical) {
QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleVerticalAxisRangeChanged(qreal,qreal)));
QObject::connect(this, SIGNAL(rangeVerticalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal)));
}
- if(axis->orientation()==Qt::Horizontal) {
+ if (axis->orientation() == Qt::Horizontal) {
QObject::connect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleHorizontalAxisRangeChanged(qreal,qreal)));
QObject::connect(this, SIGNAL(rangeHorizontalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal)));
}
@@ -180,14 +180,14 @@ bool AbstractDomain::attachAxis(QAbstractAxis* axis)
return true;
}
-bool AbstractDomain::detachAxis(QAbstractAxis* axis)
+bool AbstractDomain::detachAxis(QAbstractAxis *axis)
{
- if(axis->orientation()==Qt::Vertical) {
+ if (axis->orientation() == Qt::Vertical) {
QObject::disconnect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleVerticalAxisRangeChanged(qreal,qreal)));
QObject::disconnect(this, SIGNAL(rangeVerticalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal)));
}
- if(axis->orientation()==Qt::Horizontal) {
+ if (axis->orientation() == Qt::Horizontal) {
QObject::disconnect(axis->d_ptr.data(), SIGNAL(rangeChanged(qreal,qreal)), this, SLOT(handleHorizontalAxisRangeChanged(qreal,qreal)));
QObject::disconnect(this, SIGNAL(rangeHorizontalChanged(qreal,qreal)), axis->d_ptr.data(), SLOT(handleRangeChanged(qreal,qreal)));
}
@@ -199,10 +199,10 @@ bool AbstractDomain::detachAxis(QAbstractAxis* axis)
bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const AbstractDomain &domain1, const AbstractDomain &domain2)
{
- return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) &&
- qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) &&
- qFuzzyIsNull(domain1.m_minX - domain2.m_minX) &&
- qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
+ return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX)
+ && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY)
+ && qFuzzyIsNull(domain1.m_minX - domain2.m_minX)
+ && qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
}
@@ -218,6 +218,17 @@ QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const AbstractDo
return dbg.maybeSpace();
}
+// This function adjusts min/max ranges to failsafe values if negative/zero values are attempted.
+void AbstractDomain::adjustLogDomainRanges(qreal &min, qreal &max)
+{
+ if (min <= 0) {
+ min = 1.0;
+ if (max <= min)
+ max = min + 1.0;
+ }
+}
+
+
#include "moc_abstractdomain_p.cpp"
QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/domain/abstractdomain_p.h b/src/domain/abstractdomain_p.h
index 907cccff..cf7c2bac 100644
--- a/src/domain/abstractdomain_p.h
+++ b/src/domain/abstractdomain_p.h
@@ -42,12 +42,20 @@ class QTCOMMERCIALCHART_AUTOTEST_EXPORT AbstractDomain: public QObject
{
Q_OBJECT
public:
- enum DomainType { UndefinedDomain, XYDomain, XLogYDomain, LogXYDomain, LogXLogYDomain };
+ enum DomainType { UndefinedDomain,
+ XYDomain,
+ XLogYDomain,
+ LogXYDomain,
+ LogXLogYDomain,
+ XYPolarDomain,
+ XLogYPolarDomain,
+ LogXYPolarDomain,
+ LogXLogYPolarDomain };
public:
explicit AbstractDomain(QObject *object = 0);
virtual ~AbstractDomain();
- void setSize(const QSizeF& size);
+ virtual void setSize(const QSizeF &size);
QSizeF size() const;
virtual DomainType type() = 0;
@@ -82,10 +90,10 @@ public:
virtual QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const = 0;
virtual QPointF calculateDomainPoint(const QPointF &point) const = 0;
- virtual QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const = 0;
+ virtual QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const = 0;
- virtual bool attachAxis(QAbstractAxis* axis);
- virtual bool detachAxis(QAbstractAxis* axis);
+ virtual bool attachAxis(QAbstractAxis *axis);
+ virtual bool detachAxis(QAbstractAxis *axis);
static void looseNiceNumbers(qreal &min, qreal &max, int &ticksCount);
static qreal niceNumber(qreal x, bool ceiling);
@@ -100,6 +108,8 @@ public Q_SLOTS:
void handleHorizontalAxisRangeChanged(qreal min,qreal max);
protected:
+ void adjustLogDomainRanges(qreal &min, qreal &max);
+
qreal m_minX;
qreal m_maxX;
qreal m_minY;
diff --git a/src/domain/domain.pri b/src/domain/domain.pri
index 1d5823d1..ab4fcfce 100644
--- a/src/domain/domain.pri
+++ b/src/domain/domain.pri
@@ -5,14 +5,24 @@ DEPENDPATH += $$PWD
SOURCES += \
$$PWD/abstractdomain.cpp \
+ $$PWD/polardomain.cpp \
$$PWD/xydomain.cpp \
+ $$PWD/xypolardomain.cpp \
$$PWD/xlogydomain.cpp \
+ $$PWD/xlogypolardomain.cpp \
$$PWD/logxydomain.cpp \
- $$PWD/logxlogydomain.cpp
+ $$PWD/logxypolardomain.cpp \
+ $$PWD/logxlogydomain.cpp \
+ $$PWD/logxlogypolardomain.cpp
PRIVATE_HEADERS += \
$$PWD/abstractdomain_p.h \
+ $$PWD/polardomain_p.h \
$$PWD/xydomain_p.h \
+ $$PWD/xypolardomain_p.h \
$$PWD/xlogydomain_p.h \
+ $$PWD/xlogypolardomain_p.h \
$$PWD/logxydomain_p.h \
- $$PWD/logxlogydomain_p.h
+ $$PWD/logxypolardomain_p.h \
+ $$PWD/logxlogydomain_p.h \
+ $$PWD/logxlogypolardomain_p.h
diff --git a/src/domain/logxlogydomain.cpp b/src/domain/logxlogydomain.cpp
index 7032d137..adb9bc1d 100644
--- a/src/domain/logxlogydomain.cpp
+++ b/src/domain/logxlogydomain.cpp
@@ -45,6 +45,9 @@ void LogXLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
bool axisXChanged = false;
bool axisYChanged = false;
+ adjustLogDomainRanges(minX, maxX);
+ adjustLogDomainRanges(minY, maxY);
+
if (!qFuzzyIsNull(m_minX - minX) || !qFuzzyIsNull(m_maxX - maxX)) {
m_minX = minX;
m_maxX = maxX;
@@ -65,7 +68,7 @@ void LogXLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
qreal logMaxY = log10(m_maxY) / log10(m_logBaseY);
m_logLeftY = logMinY < logMaxY ? logMinY : logMaxY;
m_logRightY = logMinY > logMaxY ? logMinY : logMaxY;
- if(!m_signalsBlocked)
+ if (!m_signalsBlocked)
emit rangeVerticalChanged(m_minY, m_maxY);
}
@@ -141,13 +144,13 @@ QPointF LogXLogYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) c
ok = true;
return QPointF(x, y);
} else {
- qWarning() << "Logarithm of negative value is undefined. Empty layout returned";
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
ok = false;
return QPointF();
}
}
-QVector<QPointF> LogXLogYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const
+QVector<QPointF> LogXLogYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const
{
const qreal deltaX = m_size.width() / qAbs(m_logRightX - m_logLeftX);
const qreal deltaY = m_size.height() / qAbs(m_logRightY - m_logLeftY);
@@ -162,7 +165,7 @@ QVector<QPointF> LogXLogYDomain::calculateGeometryPoints(const QList<QPointF>& v
result[i].setX(x);
result[i].setY(y);
} else {
- qWarning() << "Logarithm of negative value is undefined. Empty layout returned";
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
return QVector<QPointF>();
}
}
@@ -178,17 +181,17 @@ QPointF LogXLogYDomain::calculateDomainPoint(const QPointF &point) const
return QPointF(x, y);
}
-bool LogXLogYDomain::attachAxis(QAbstractAxis* axis)
+bool LogXLogYDomain::attachAxis(QAbstractAxis *axis)
{
AbstractDomain::attachAxis(axis);
QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
- if(logAxis && logAxis->orientation()==Qt::Vertical) {
+ if (logAxis && logAxis->orientation() == Qt::Vertical) {
QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
handleVerticalAxisBaseChanged(logAxis->base());
}
- if(logAxis && logAxis->orientation()==Qt::Horizontal) {
+ if (logAxis && logAxis->orientation() == Qt::Horizontal) {
QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
handleHorizontalAxisBaseChanged(logAxis->base());
}
@@ -196,15 +199,15 @@ bool LogXLogYDomain::attachAxis(QAbstractAxis* axis)
return true;
}
-bool LogXLogYDomain::detachAxis(QAbstractAxis* axis)
+bool LogXLogYDomain::detachAxis(QAbstractAxis *axis)
{
AbstractDomain::detachAxis(axis);
QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
- if(logAxis && logAxis->orientation()==Qt::Vertical)
+ if (logAxis && logAxis->orientation() == Qt::Vertical)
QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
- if(logAxis && logAxis->orientation()==Qt::Horizontal)
+ if (logAxis && logAxis->orientation() == Qt::Horizontal)
QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
return true;
@@ -234,10 +237,10 @@ void LogXLogYDomain::handleHorizontalAxisBaseChanged(qreal baseX)
bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXLogYDomain &domain1, const LogXLogYDomain &domain2)
{
- return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) &&
- qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) &&
- qFuzzyIsNull(domain1.m_minX - domain2.m_minX) &&
- qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
+ return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX)
+ && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY)
+ && qFuzzyIsNull(domain1.m_minX - domain2.m_minX)
+ && qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
}
diff --git a/src/domain/logxlogydomain_p.h b/src/domain/logxlogydomain_p.h
index 2d604163..014bf803 100644
--- a/src/domain/logxlogydomain_p.h
+++ b/src/domain/logxlogydomain_p.h
@@ -56,10 +56,10 @@ public:
QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const;
QPointF calculateDomainPoint(const QPointF &point) const;
- QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const;
+ QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const;
- bool attachAxis(QAbstractAxis* axis);
- bool detachAxis(QAbstractAxis* axis);
+ bool attachAxis(QAbstractAxis *axis);
+ bool detachAxis(QAbstractAxis *axis);
public Q_SLOTS:
void handleVerticalAxisBaseChanged(qreal baseY);
diff --git a/src/domain/logxlogypolardomain.cpp b/src/domain/logxlogypolardomain.cpp
new file mode 100644
index 00000000..a193ce11
--- /dev/null
+++ b/src/domain/logxlogypolardomain.cpp
@@ -0,0 +1,267 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "logxlogypolardomain_p.h"
+#include "qabstractaxis_p.h"
+#include "qlogvalueaxis.h"
+#include <qmath.h>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+LogXLogYPolarDomain::LogXLogYPolarDomain(QObject *parent)
+ : PolarDomain(parent),
+ m_logLeftX(0),
+ m_logRightX(1),
+ m_logBaseX(10),
+ m_logInnerY(0),
+ m_logOuterY(1),
+ m_logBaseY(10)
+{
+}
+
+LogXLogYPolarDomain::~LogXLogYPolarDomain()
+{
+}
+
+void LogXLogYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
+{
+ bool axisXChanged = false;
+ bool axisYChanged = false;
+
+ adjustLogDomainRanges(minX, maxX);
+ adjustLogDomainRanges(minY, maxY);
+
+ if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) {
+ m_minX = minX;
+ m_maxX = maxX;
+ axisXChanged = true;
+ qreal logMinX = log10(m_minX) / log10(m_logBaseX);
+ qreal logMaxX = log10(m_maxX) / log10(m_logBaseX);
+ m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX;
+ m_logRightX = logMinX > logMaxX ? logMinX : logMaxX;
+ if (!m_signalsBlocked)
+ emit rangeHorizontalChanged(m_minX, m_maxX);
+ }
+
+ if (!qFuzzyIsNull(m_minY - minY) || !qFuzzyIsNull(m_maxY - maxY)) {
+ m_minY = minY;
+ m_maxY = maxY;
+ axisYChanged = true;
+ qreal logMinY = log10(m_minY) / log10(m_logBaseY);
+ qreal logMaxY = log10(m_maxY) / log10(m_logBaseY);
+ m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY;
+ m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY;
+ if (!m_signalsBlocked)
+ emit rangeVerticalChanged(m_minY, m_maxY);
+ }
+
+ if (axisXChanged || axisYChanged)
+ emit updated();
+}
+
+void LogXLogYPolarDomain::zoomIn(const QRectF &rect)
+{
+ qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX;
+ qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX;
+ qreal leftX = qPow(m_logBaseX, logLeftX);
+ qreal rightX = qPow(m_logBaseX, logRightX);
+ qreal minX = leftX < rightX ? leftX : rightX;
+ qreal maxX = leftX > rightX ? leftX : rightX;
+
+ qreal logLeftY = m_logOuterY - rect.bottom() * (m_logOuterY - m_logInnerY) / m_size.height();
+ qreal logRightY = m_logOuterY - rect.top() * (m_logOuterY - m_logInnerY) / m_size.height();
+ qreal leftY = qPow(m_logBaseY, logLeftY);
+ qreal rightY = qPow(m_logBaseY, logRightY);
+ qreal minY = leftY < rightY ? leftY : rightY;
+ qreal maxY = leftY > rightY ? leftY : rightY;
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void LogXLogYPolarDomain::zoomOut(const QRectF &rect)
+{
+ const qreal factorX = m_size.width() / rect.width();
+
+ qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 - factorX);
+ qreal logRIghtX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 + factorX);
+ qreal leftX = qPow(m_logBaseX, logLeftX);
+ qreal rightX = qPow(m_logBaseX, logRIghtX);
+ qreal minX = leftX < rightX ? leftX : rightX;
+ qreal maxX = leftX > rightX ? leftX : rightX;
+
+ const qreal factorY = m_size.height() / rect.height();
+ qreal newLogMinY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 - factorY);
+ qreal newLogMaxY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 + factorY);
+ qreal leftY = qPow(m_logBaseY, newLogMinY);
+ qreal rightY = qPow(m_logBaseY, newLogMaxY);
+ qreal minY = leftY < rightY ? leftY : rightY;
+ qreal maxY = leftY > rightY ? leftY : rightY;
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void LogXLogYPolarDomain::move(qreal dx, qreal dy)
+{
+ qreal stepX = dx * (m_logRightX - m_logLeftX) / m_size.width();
+ qreal leftX = qPow(m_logBaseX, m_logLeftX + stepX);
+ qreal rightX = qPow(m_logBaseX, m_logRightX + stepX);
+ qreal minX = leftX < rightX ? leftX : rightX;
+ qreal maxX = leftX > rightX ? leftX : rightX;
+
+ qreal stepY = dy * (m_logOuterY - m_logInnerY) / m_radius;
+ qreal leftY = qPow(m_logBaseY, m_logInnerY + stepY);
+ qreal rightY = qPow(m_logBaseY, m_logOuterY + stepY);
+ qreal minY = leftY < rightY ? leftY : rightY;
+ qreal maxY = leftY > rightY ? leftY : rightY;
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+qreal LogXLogYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const
+{
+ qreal retVal;
+ if (value <= 0) {
+ ok = false;
+ retVal = 0.0;
+ } else {
+ ok = true;
+ const qreal tickSpan = 360.0 / qAbs(m_logRightX - m_logLeftX);
+ const qreal logValue = log10(value) / log10(m_logBaseX);
+ const qreal valueDelta = logValue - m_logLeftX;
+
+ retVal = valueDelta * tickSpan;
+ }
+ return retVal;
+}
+
+qreal LogXLogYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const
+{
+ qreal retVal;
+ if (value <= 0) {
+ ok = false;
+ retVal = 0.0;
+ } else {
+ ok = true;
+ const qreal tickSpan = m_radius / qAbs(m_logOuterY - m_logInnerY);
+ const qreal logValue = log10(value) / log10(m_logBaseY);
+ const qreal valueDelta = logValue - m_logInnerY;
+
+ retVal = valueDelta * tickSpan;
+
+ if (retVal < 0.0)
+ retVal = 0.0;
+ }
+ return retVal;
+}
+
+QPointF LogXLogYPolarDomain::calculateDomainPoint(const QPointF &point) const
+{
+ if (point == m_center)
+ return QPointF(0.0, m_minY);
+
+ QLineF line(m_center, point);
+ qreal a = 90.0 - line.angle();
+ if (a < 0.0)
+ a += 360.0;
+
+ const qreal deltaX = 360.0 / qAbs(m_logRightX - m_logLeftX);
+ a = qPow(m_logBaseX, m_logLeftX + (a / deltaX));
+
+ const qreal deltaY = m_radius / qAbs(m_logOuterY - m_logInnerY);
+ qreal r = qPow(m_logBaseY, m_logInnerY + (line.length() / deltaY));
+
+ return QPointF(a, r);
+}
+
+bool LogXLogYPolarDomain::attachAxis(QAbstractAxis *axis)
+{
+ AbstractDomain::attachAxis(axis);
+ QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
+
+ if (logAxis && logAxis->orientation() == Qt::Horizontal) {
+ QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
+ handleHorizontalAxisBaseChanged(logAxis->base());
+ } else if (logAxis && logAxis->orientation() == Qt::Vertical){
+ QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
+ handleVerticalAxisBaseChanged(logAxis->base());
+ }
+
+ return true;
+}
+
+bool LogXLogYPolarDomain::detachAxis(QAbstractAxis *axis)
+{
+ AbstractDomain::detachAxis(axis);
+ QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
+
+ if (logAxis && logAxis->orientation() == Qt::Horizontal)
+ QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
+ else if (logAxis && logAxis->orientation() == Qt::Vertical)
+ QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
+
+ return true;
+}
+
+void LogXLogYPolarDomain::handleHorizontalAxisBaseChanged(qreal baseX)
+{
+ m_logBaseX = baseX;
+ qreal logMinX = log10(m_minX) / log10(m_logBaseX);
+ qreal logMaxX = log10(m_maxX) / log10(m_logBaseX);
+ m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX;
+ m_logRightX = logMinX > logMaxX ? logMinX : logMaxX;
+ emit updated();
+}
+
+void LogXLogYPolarDomain::handleVerticalAxisBaseChanged(qreal baseY)
+{
+ m_logBaseY = baseY;
+ qreal logMinY = log10(m_minY) / log10(m_logBaseY);
+ qreal logMaxY = log10(m_maxY) / log10(m_logBaseY);
+ m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY;
+ m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY;
+ emit updated();
+}
+
+// operators
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2)
+{
+ return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX)
+ && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY)
+ && qFuzzyIsNull(domain1.m_minX - domain2.m_minX)
+ && qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
+}
+
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2)
+{
+ return !(domain1 == domain2);
+}
+
+
+QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXLogYPolarDomain &domain)
+{
+ dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size;
+ return dbg.maybeSpace();
+}
+
+#include "moc_logxlogypolardomain_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/domain/logxlogypolardomain_p.h b/src/domain/logxlogypolardomain_p.h
new file mode 100644
index 00000000..106f58a6
--- /dev/null
+++ b/src/domain/logxlogypolardomain_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef LOGXLOGYPOLARDOMAIN_H
+#define LOGXLOGYPOLARDOMAIN_H
+#include "polardomain_p.h"
+#include <QRectF>
+#include <QSizeF>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QTCOMMERCIALCHART_AUTOTEST_EXPORT LogXLogYPolarDomain: public PolarDomain
+{
+ Q_OBJECT
+public:
+ explicit LogXLogYPolarDomain(QObject *object = 0);
+ virtual ~LogXLogYPolarDomain();
+
+ DomainType type() { return AbstractDomain::LogXLogYPolarDomain; }
+
+ void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY);
+
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2);
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXLogYPolarDomain &domain1, const LogXLogYPolarDomain &domain2);
+ friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXLogYPolarDomain &domain);
+
+ void zoomIn(const QRectF &rect);
+ void zoomOut(const QRectF &rect);
+ void move(qreal dx, qreal dy);
+
+ QPointF calculateDomainPoint(const QPointF &point) const;
+
+ bool attachAxis(QAbstractAxis *axis);
+ bool detachAxis(QAbstractAxis *axis);
+
+public Q_SLOTS:
+ void handleVerticalAxisBaseChanged(qreal baseY);
+ void handleHorizontalAxisBaseChanged(qreal baseX);
+
+protected:
+ qreal toAngularCoordinate(qreal value, bool &ok) const;
+ qreal toRadialCoordinate(qreal value, bool &ok) const;
+
+private:
+ qreal m_logLeftX;
+ qreal m_logRightX;
+ qreal m_logBaseX;
+ qreal m_logInnerY;
+ qreal m_logOuterY;
+ qreal m_logBaseY;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // LOGXLOGYPOLARDOMAIN_H
diff --git a/src/domain/logxydomain.cpp b/src/domain/logxydomain.cpp
index ffa739bf..da6e210a 100644
--- a/src/domain/logxydomain.cpp
+++ b/src/domain/logxydomain.cpp
@@ -42,6 +42,8 @@ void LogXYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
bool axisXChanged = false;
bool axisYChanged = false;
+ adjustLogDomainRanges(minX, maxX);
+
if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) {
m_minX = minX;
m_maxX = maxX;
@@ -58,7 +60,7 @@ void LogXYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
m_minY = minY;
m_maxY = maxY;
axisYChanged = true;
- if(!m_signalsBlocked)
+ if (!m_signalsBlocked)
emit rangeVerticalChanged(m_minY, m_maxY);
}
@@ -137,13 +139,13 @@ QPointF LogXYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) cons
ok = true;
return QPointF(x, y);
} else {
- qWarning() << "Logarithm of negative value is undefined. Empty layout returned";
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
ok = false;
return QPointF();
}
}
-QVector<QPointF> LogXYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const
+QVector<QPointF> LogXYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const
{
const qreal deltaX = m_size.width() / (m_logRightX - m_logLeftX);
const qreal deltaY = m_size.height() / (m_maxY - m_minY);
@@ -158,7 +160,7 @@ QVector<QPointF> LogXYDomain::calculateGeometryPoints(const QList<QPointF>& vect
result[i].setX(x);
result[i].setY(y);
} else {
- qWarning() << "Logarithm of negative value is undefined. Empty layout returned";
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
return QVector<QPointF>();
}
}
@@ -174,12 +176,12 @@ QPointF LogXYDomain::calculateDomainPoint(const QPointF &point) const
return QPointF(x, y);
}
-bool LogXYDomain::attachAxis(QAbstractAxis* axis)
+bool LogXYDomain::attachAxis(QAbstractAxis *axis)
{
AbstractDomain::attachAxis(axis);
QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
- if(logAxis && logAxis->orientation()==Qt::Horizontal) {
+ if (logAxis && logAxis->orientation() == Qt::Horizontal) {
QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
handleHorizontalAxisBaseChanged(logAxis->base());
}
@@ -187,12 +189,12 @@ bool LogXYDomain::attachAxis(QAbstractAxis* axis)
return true;
}
-bool LogXYDomain::detachAxis(QAbstractAxis* axis)
+bool LogXYDomain::detachAxis(QAbstractAxis *axis)
{
AbstractDomain::detachAxis(axis);
QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
- if(logAxis && logAxis->orientation()==Qt::Horizontal)
+ if (logAxis && logAxis->orientation() == Qt::Horizontal)
QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
return true;
@@ -212,10 +214,10 @@ void LogXYDomain::handleHorizontalAxisBaseChanged(qreal baseX)
bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXYDomain &domain1, const LogXYDomain &domain2)
{
- return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) &&
- qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) &&
- qFuzzyIsNull(domain1.m_minX - domain2.m_minX) &&
- qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
+ return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX)
+ && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY)
+ && qFuzzyIsNull(domain1.m_minX - domain2.m_minX)
+ && qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
}
diff --git a/src/domain/logxydomain_p.h b/src/domain/logxydomain_p.h
index cbc59e18..2f0e49ea 100644
--- a/src/domain/logxydomain_p.h
+++ b/src/domain/logxydomain_p.h
@@ -56,10 +56,10 @@ public:
QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const;
QPointF calculateDomainPoint(const QPointF &point) const;
- QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const;
+ QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const;
- bool attachAxis(QAbstractAxis* axis);
- bool detachAxis(QAbstractAxis* axis);
+ bool attachAxis(QAbstractAxis *axis);
+ bool detachAxis(QAbstractAxis *axis);
public Q_SLOTS:
void handleHorizontalAxisBaseChanged(qreal baseX);
diff --git a/src/domain/logxypolardomain.cpp b/src/domain/logxypolardomain.cpp
new file mode 100644
index 00000000..b08f6a04
--- /dev/null
+++ b/src/domain/logxypolardomain.cpp
@@ -0,0 +1,236 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "logxypolardomain_p.h"
+#include "qabstractaxis_p.h"
+#include "qlogvalueaxis.h"
+#include <qmath.h>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+LogXYPolarDomain::LogXYPolarDomain(QObject *parent)
+ : PolarDomain(parent),
+ m_logLeftX(0),
+ m_logRightX(1),
+ m_logBaseX(10)
+{
+}
+
+LogXYPolarDomain::~LogXYPolarDomain()
+{
+}
+
+void LogXYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
+{
+ bool axisXChanged = false;
+ bool axisYChanged = false;
+
+ adjustLogDomainRanges(minX, maxX);
+
+ if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) {
+ m_minX = minX;
+ m_maxX = maxX;
+ axisXChanged = true;
+ qreal logMinX = log10(m_minX) / log10(m_logBaseX);
+ qreal logMaxX = log10(m_maxX) / log10(m_logBaseX);
+ m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX;
+ m_logRightX = logMinX > logMaxX ? logMinX : logMaxX;
+ if (!m_signalsBlocked)
+ emit rangeHorizontalChanged(m_minX, m_maxX);
+ }
+
+ if (!qFuzzyIsNull(m_minY - minY) || !qFuzzyIsNull(m_maxY - maxY)) {
+ m_minY = minY;
+ m_maxY = maxY;
+ axisYChanged = true;
+ if (!m_signalsBlocked)
+ emit rangeVerticalChanged(m_minY, m_maxY);
+ }
+
+ if (axisXChanged || axisYChanged)
+ emit updated();
+}
+
+void LogXYPolarDomain::zoomIn(const QRectF &rect)
+{
+ qreal logLeftX = rect.left() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX;
+ qreal logRightX = rect.right() * (m_logRightX - m_logLeftX) / m_size.width() + m_logLeftX;
+ qreal leftX = qPow(m_logBaseX, logLeftX);
+ qreal rightX = qPow(m_logBaseX, logRightX);
+ qreal minX = leftX < rightX ? leftX : rightX;
+ qreal maxX = leftX > rightX ? leftX : rightX;
+
+ qreal dy = spanY() / m_size.height();
+ qreal minY = m_minY;
+ qreal maxY = m_maxY;
+
+ minY = maxY - dy * rect.bottom();
+ maxY = maxY - dy * rect.top();
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void LogXYPolarDomain::zoomOut(const QRectF &rect)
+{
+ const qreal factorX = m_size.width() / rect.width();
+
+ qreal logLeftX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 - factorX);
+ qreal logRIghtX = m_logLeftX + (m_logRightX - m_logLeftX) / 2.0 * (1.0 + factorX);
+ qreal leftX = qPow(m_logBaseX, logLeftX);
+ qreal rightX = qPow(m_logBaseX, logRIghtX);
+ qreal minX = leftX < rightX ? leftX : rightX;
+ qreal maxX = leftX > rightX ? leftX : rightX;
+
+ qreal dy = spanY() / rect.height();
+ qreal minY = m_minY;
+ qreal maxY = m_maxY;
+
+ maxY = minY + dy * rect.bottom();
+ minY = maxY - dy * m_size.height();
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void LogXYPolarDomain::move(qreal dx, qreal dy)
+{
+ qreal stepX = dx * (m_logRightX - m_logLeftX) / m_size.width();
+ qreal leftX = qPow(m_logBaseX, m_logLeftX + stepX);
+ qreal rightX = qPow(m_logBaseX, m_logRightX + stepX);
+ qreal minX = leftX < rightX ? leftX : rightX;
+ qreal maxX = leftX > rightX ? leftX : rightX;
+
+ qreal y = spanY() / m_radius;
+ qreal minY = m_minY;
+ qreal maxY = m_maxY;
+
+ if (dy != 0) {
+ minY = minY + y * dy;
+ maxY = maxY + y * dy;
+ }
+ setRange(minX, maxX, minY, maxY);
+}
+
+qreal LogXYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const
+{
+ qreal retVal;
+ if (value <= 0) {
+ ok = false;
+ retVal = 0.0;
+ } else {
+ ok = true;
+ const qreal tickSpan = 360.0 / qAbs(m_logRightX - m_logLeftX);
+ const qreal logValue = log10(value) / log10(m_logBaseX);
+ const qreal valueDelta = logValue - m_logLeftX;
+
+ retVal = valueDelta * tickSpan;
+ }
+ return retVal;
+}
+
+qreal LogXYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const
+{
+ ok = true;
+ if (value < m_minY)
+ value = m_minY;
+
+ // Dont limit the max. The drawing should clip the stuff that goes out of the grid
+ qreal f = (value - m_minY) / (m_maxY - m_minY);
+
+ return f * m_radius;
+}
+
+QPointF LogXYPolarDomain::calculateDomainPoint(const QPointF &point) const
+{
+ if (point == m_center)
+ return QPointF(0.0, m_minY);
+
+ QLineF line(m_center, point);
+ qreal a = 90.0 - line.angle();
+ if (a < 0.0)
+ a += 360.0;
+
+ const qreal deltaX = 360.0 / qAbs(m_logRightX - m_logLeftX);
+ a = qPow(m_logBaseX, m_logLeftX + (a / deltaX));
+
+ qreal r = m_minY + ((m_maxY - m_minY) * (line.length() / m_radius));
+
+ return QPointF(a, r);
+}
+
+bool LogXYPolarDomain::attachAxis(QAbstractAxis *axis)
+{
+ AbstractDomain::attachAxis(axis);
+ QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
+
+ if (logAxis && logAxis->orientation() == Qt::Horizontal) {
+ QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
+ handleHorizontalAxisBaseChanged(logAxis->base());
+ }
+
+ return true;
+}
+
+bool LogXYPolarDomain::detachAxis(QAbstractAxis *axis)
+{
+ AbstractDomain::detachAxis(axis);
+ QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
+
+ if (logAxis && logAxis->orientation() == Qt::Horizontal)
+ QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleHorizontalAxisBaseChanged(qreal)));
+
+ return true;
+}
+
+void LogXYPolarDomain::handleHorizontalAxisBaseChanged(qreal baseX)
+{
+ m_logBaseX = baseX;
+ qreal logMinX = log10(m_minX) / log10(m_logBaseX);
+ qreal logMaxX = log10(m_maxX) / log10(m_logBaseX);
+ m_logLeftX = logMinX < logMaxX ? logMinX : logMaxX;
+ m_logRightX = logMinX > logMaxX ? logMinX : logMaxX;
+ emit updated();
+}
+
+// operators
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2)
+{
+ return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX)
+ && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY)
+ && qFuzzyIsNull(domain1.m_minX - domain2.m_minX)
+ && qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
+}
+
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2)
+{
+ return !(domain1 == domain2);
+}
+
+
+QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXYPolarDomain &domain)
+{
+ dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size;
+ return dbg.maybeSpace();
+}
+
+#include "moc_logxypolardomain_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/domain/logxypolardomain_p.h b/src/domain/logxypolardomain_p.h
new file mode 100644
index 00000000..c7468ab9
--- /dev/null
+++ b/src/domain/logxypolardomain_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef LOGXYPOLARDOMAIN_H
+#define LOGXYPOLARDOMAIN_H
+#include "polardomain_p.h"
+#include <QRectF>
+#include <QSizeF>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QTCOMMERCIALCHART_AUTOTEST_EXPORT LogXYPolarDomain: public PolarDomain
+{
+ Q_OBJECT
+public:
+ explicit LogXYPolarDomain(QObject *object = 0);
+ virtual ~LogXYPolarDomain();
+
+ DomainType type() { return AbstractDomain::LogXYPolarDomain; }
+
+ void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY);
+
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2);
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const LogXYPolarDomain &domain1, const LogXYPolarDomain &domain2);
+ friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const LogXYPolarDomain &domain);
+
+ void zoomIn(const QRectF &rect);
+ void zoomOut(const QRectF &rect);
+ void move(qreal dx, qreal dy);
+
+ QPointF calculateDomainPoint(const QPointF &point) const;
+
+ bool attachAxis(QAbstractAxis *axis);
+ bool detachAxis(QAbstractAxis *axis);
+
+public Q_SLOTS:
+ void handleHorizontalAxisBaseChanged(qreal baseX);
+
+protected:
+ qreal toAngularCoordinate(qreal value, bool &ok) const;
+ qreal toRadialCoordinate(qreal value, bool &ok) const;
+
+private:
+ qreal m_logLeftX;
+ qreal m_logRightX;
+ qreal m_logBaseX;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // LOGXYPOLARDOMAIN_H
diff --git a/src/domain/polardomain.cpp b/src/domain/polardomain.cpp
new file mode 100644
index 00000000..d9a9d48f
--- /dev/null
+++ b/src/domain/polardomain.cpp
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polardomain_p.h"
+#include "qabstractaxis_p.h"
+#include <qmath.h>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+PolarDomain::PolarDomain(QObject *parent)
+ : AbstractDomain(parent)
+{
+}
+
+PolarDomain::~PolarDomain()
+{
+}
+
+void PolarDomain::setSize(const QSizeF &size)
+{
+ Q_ASSERT(size.width() == size.height());
+ m_radius = size.height() / 2;
+ m_center = QPointF(m_radius, m_radius);
+ AbstractDomain::setSize(size);
+}
+
+QPointF PolarDomain::calculateGeometryPoint(const QPointF &point, bool &ok) const
+{
+ qreal r;
+ qreal a = toAngularCoordinate(point.x(), ok);
+ if (ok)
+ r = toRadialCoordinate(point.y(), ok);
+ if (ok) {
+ return m_center + polarCoordinateToPoint(a, r);
+ } else {
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
+ return QPointF();
+ }
+}
+
+QVector<QPointF> PolarDomain::calculateGeometryPoints(const QList<QPointF> &vector) const
+{
+ QVector<QPointF> result;
+ result.resize(vector.count());
+ bool ok;
+ qreal r;
+ qreal a;
+
+ for (int i = 0; i < vector.count(); ++i) {
+ a = toAngularCoordinate(vector[i].x(), ok);
+ if (ok)
+ r = toRadialCoordinate(vector[i].y(), ok);
+ if (ok) {
+ result[i] = m_center + polarCoordinateToPoint(a, r);
+ } else {
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
+ return QVector<QPointF>();
+ }
+ }
+
+ return result;
+}
+
+QPointF PolarDomain::polarCoordinateToPoint(qreal angularCoordinate, qreal radialCoordinate) const
+{
+ qreal dx = qSin(angularCoordinate * (M_PI / 180)) * radialCoordinate;
+ qreal dy = qCos(angularCoordinate * (M_PI / 180)) * radialCoordinate;
+
+ return QPointF(dx, -dy);
+}
+
+#include "moc_polardomain_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/domain/polardomain_p.h b/src/domain/polardomain_p.h
new file mode 100644
index 00000000..81e921d5
--- /dev/null
+++ b/src/domain/polardomain_p.h
@@ -0,0 +1,62 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARDOMAIN_H
+#define POLARDOMAIN_H
+#include "abstractdomain_p.h"
+#include <QRectF>
+#include <QSizeF>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QTCOMMERCIALCHART_AUTOTEST_EXPORT PolarDomain: public AbstractDomain
+{
+ Q_OBJECT
+public:
+ explicit PolarDomain(QObject *object = 0);
+ virtual ~PolarDomain();
+
+ void setSize(const QSizeF &size);
+
+ QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const;
+ QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const;
+
+ virtual qreal toAngularCoordinate(qreal value, bool &ok) const = 0;
+ virtual qreal toRadialCoordinate(qreal value, bool &ok) const = 0;
+
+protected:
+ QPointF polarCoordinateToPoint(qreal angularCoordinate, qreal radialCoordinate) const;
+
+ QPointF m_center;
+ qreal m_radius;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARDOMAIN_H
diff --git a/src/domain/xlogydomain.cpp b/src/domain/xlogydomain.cpp
index 42e7edae..850eb99b 100644
--- a/src/domain/xlogydomain.cpp
+++ b/src/domain/xlogydomain.cpp
@@ -42,6 +42,8 @@ void XLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
bool axisXChanged = false;
bool axisYChanged = false;
+ adjustLogDomainRanges(minY, maxY);
+
if (!qFuzzyIsNull(m_minX - minX) || !qFuzzyIsNull(m_maxX - maxX)) {
m_minX = minX;
m_maxX = maxX;
@@ -58,7 +60,7 @@ void XLogYDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
qreal logMaxY = log10(m_maxY) / log10(m_logBaseY);
m_logLeftY = logMinY < logMaxY ? logMinY : logMaxY;
m_logRightY = logMinY > logMaxY ? logMinY : logMaxY;
- if(!m_signalsBlocked)
+ if (!m_signalsBlocked)
emit rangeVerticalChanged(m_minY, m_maxY);
}
@@ -136,13 +138,13 @@ QPointF XLogYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) cons
ok = true;
return QPointF(x, y);
} else {
- qWarning() << "Logarithm of negative value is undefined. Empty layout returned";
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
ok = false;
return QPointF();
}
}
-QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const
+QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const
{
const qreal deltaX = m_size.width() / (m_maxX - m_minX);
const qreal deltaY = m_size.height() / qAbs(m_logRightY - m_logLeftY);
@@ -157,7 +159,7 @@ QVector<QPointF> XLogYDomain::calculateGeometryPoints(const QList<QPointF>& vect
result[i].setX(x);
result[i].setY(y);
} else {
- qWarning() << "Logarithm of negative value is undefined. Empty layout returned";
+ qWarning() << "Logarithm of negative value is undefined. Empty layout returned.";
return QVector<QPointF>();
}
}
@@ -173,22 +175,22 @@ QPointF XLogYDomain::calculateDomainPoint(const QPointF &point) const
return QPointF(x, y);
}
-bool XLogYDomain::attachAxis(QAbstractAxis* axis)
+bool XLogYDomain::attachAxis(QAbstractAxis *axis)
{
QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
- if(logAxis && logAxis->orientation()==Qt::Vertical){
+ if (logAxis && logAxis->orientation() == Qt::Vertical) {
QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
handleVerticalAxisBaseChanged(logAxis->base());
}
return AbstractDomain::attachAxis(axis);
}
-bool XLogYDomain::detachAxis(QAbstractAxis* axis)
+bool XLogYDomain::detachAxis(QAbstractAxis *axis)
{
QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
- if(logAxis && logAxis->orientation()==Qt::Vertical)
+ if (logAxis && logAxis->orientation() == Qt::Vertical)
QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
return AbstractDomain::detachAxis(axis);
@@ -208,10 +210,10 @@ void XLogYDomain::handleVerticalAxisBaseChanged(qreal baseY)
bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XLogYDomain &domain1, const XLogYDomain &domain2)
{
- return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX) &&
- qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY) &&
- qFuzzyIsNull(domain1.m_minX - domain2.m_minX) &&
- qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
+ return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX)
+ && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY)
+ && qFuzzyIsNull(domain1.m_minX - domain2.m_minX)
+ && qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
}
diff --git a/src/domain/xlogydomain_p.h b/src/domain/xlogydomain_p.h
index 88dd989f..68ac6f81 100644
--- a/src/domain/xlogydomain_p.h
+++ b/src/domain/xlogydomain_p.h
@@ -56,10 +56,10 @@ public:
QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const;
QPointF calculateDomainPoint(const QPointF &point) const;
- QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const;
+ QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const;
- bool attachAxis(QAbstractAxis* axis);
- bool detachAxis(QAbstractAxis* axis);
+ bool attachAxis(QAbstractAxis *axis);
+ bool detachAxis(QAbstractAxis *axis);
public Q_SLOTS:
void handleVerticalAxisBaseChanged(qreal baseY);
diff --git a/src/domain/xlogypolardomain.cpp b/src/domain/xlogypolardomain.cpp
new file mode 100644
index 00000000..730a9dcd
--- /dev/null
+++ b/src/domain/xlogypolardomain.cpp
@@ -0,0 +1,231 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "xlogypolardomain_p.h"
+#include "qabstractaxis_p.h"
+#include "qlogvalueaxis.h"
+#include <qmath.h>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+XLogYPolarDomain::XLogYPolarDomain(QObject *parent)
+ : PolarDomain(parent),
+ m_logInnerY(0),
+ m_logOuterY(1),
+ m_logBaseY(10)
+{
+}
+
+XLogYPolarDomain::~XLogYPolarDomain()
+{
+}
+
+void XLogYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
+{
+ bool axisXChanged = false;
+ bool axisYChanged = false;
+
+ adjustLogDomainRanges(minY, maxY);
+
+ if (!qFuzzyIsNull(m_minX - minX) || !qFuzzyIsNull(m_maxX - maxX)) {
+ m_minX = minX;
+ m_maxX = maxX;
+ axisXChanged = true;
+ if (!m_signalsBlocked)
+ emit rangeHorizontalChanged(m_minX, m_maxX);
+ }
+
+ if (!qFuzzyIsNull(m_minY - minY) || !qFuzzyIsNull(m_maxY - maxY)) {
+ m_minY = minY;
+ m_maxY = maxY;
+ axisYChanged = true;
+ qreal logMinY = log10(m_minY) / log10(m_logBaseY);
+ qreal logMaxY = log10(m_maxY) / log10(m_logBaseY);
+ m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY;
+ m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY;
+ if (!m_signalsBlocked)
+ emit rangeVerticalChanged(m_minY, m_maxY);
+ }
+
+ if (axisXChanged || axisYChanged)
+ emit updated();
+}
+
+void XLogYPolarDomain::zoomIn(const QRectF &rect)
+{
+ qreal dx = spanX() / m_size.width();
+ qreal maxX = m_maxX;
+ qreal minX = m_minX;
+
+ maxX = minX + dx * rect.right();
+ minX = minX + dx * rect.left();
+
+ qreal logLeftY = m_logOuterY - rect.bottom() * (m_logOuterY - m_logInnerY) / m_size.height();
+ qreal logRightY = m_logOuterY - rect.top() * (m_logOuterY - m_logInnerY) / m_size.height();
+ qreal leftY = qPow(m_logBaseY, logLeftY);
+ qreal rightY = qPow(m_logBaseY, logRightY);
+ qreal minY = leftY < rightY ? leftY : rightY;
+ qreal maxY = leftY > rightY ? leftY : rightY;
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void XLogYPolarDomain::zoomOut(const QRectF &rect)
+{
+ qreal dx = spanX() / rect.width();
+ qreal maxX = m_maxX;
+ qreal minX = m_minX;
+
+ minX = maxX - dx * rect.right();
+ maxX = minX + dx * m_size.width();
+
+ const qreal factorY = m_size.height() / rect.height();
+ qreal newLogMinY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 - factorY);
+ qreal newLogMaxY = m_logInnerY + (m_logOuterY - m_logInnerY) / 2.0 * (1.0 + factorY);
+ qreal leftY = qPow(m_logBaseY, newLogMinY);
+ qreal rightY = qPow(m_logBaseY, newLogMaxY);
+ qreal minY = leftY < rightY ? leftY : rightY;
+ qreal maxY = leftY > rightY ? leftY : rightY;
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void XLogYPolarDomain::move(qreal dx, qreal dy)
+{
+ qreal x = spanX() / 360.0;
+
+ qreal maxX = m_maxX;
+ qreal minX = m_minX;
+
+ if (dx != 0) {
+ minX = minX + x * dx;
+ maxX = maxX + x * dx;
+ }
+
+ qreal stepY = dy * (m_logOuterY - m_logInnerY) / m_radius;
+ qreal leftY = qPow(m_logBaseY, m_logInnerY + stepY);
+ qreal rightY = qPow(m_logBaseY, m_logOuterY + stepY);
+ qreal minY = leftY < rightY ? leftY : rightY;
+ qreal maxY = leftY > rightY ? leftY : rightY;
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+qreal XLogYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const
+{
+ ok = true;
+ qreal f = (value - m_minX) / (m_maxX - m_minX);
+ return f * 360.0;
+}
+
+qreal XLogYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const
+{
+ qreal retVal;
+ if (value <= 0) {
+ ok = false;
+ retVal = 0.0;
+ } else {
+ ok = true;
+ const qreal tickSpan = m_radius / qAbs(m_logOuterY - m_logInnerY);
+ const qreal logValue = log10(value) / log10(m_logBaseY);
+ const qreal valueDelta = logValue - m_logInnerY;
+
+ retVal = valueDelta * tickSpan;
+
+ if (retVal < 0.0)
+ retVal = 0.0;
+ }
+ return retVal;
+}
+
+QPointF XLogYPolarDomain::calculateDomainPoint(const QPointF &point) const
+{
+ if (point == m_center)
+ return QPointF(0.0, m_minY);
+
+ QLineF line(m_center, point);
+ qreal a = 90.0 - line.angle();
+ if (a < 0.0)
+ a += 360.0;
+ a = ((a / 360.0) * (m_maxX - m_minX)) + m_minX;
+
+ const qreal deltaY = m_radius / qAbs(m_logOuterY - m_logInnerY);
+ qreal r = qPow(m_logBaseY, m_logInnerY + (line.length() / deltaY));
+
+ return QPointF(a, r);
+}
+
+bool XLogYPolarDomain::attachAxis(QAbstractAxis *axis)
+{
+ QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
+
+ if (logAxis && logAxis->orientation() == Qt::Vertical) {
+ QObject::connect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
+ handleVerticalAxisBaseChanged(logAxis->base());
+ }
+ return AbstractDomain::attachAxis(axis);
+}
+
+bool XLogYPolarDomain::detachAxis(QAbstractAxis *axis)
+{
+ QLogValueAxis *logAxis = qobject_cast<QLogValueAxis *>(axis);
+
+ if (logAxis && logAxis->orientation() == Qt::Vertical)
+ QObject::disconnect(logAxis, SIGNAL(baseChanged(qreal)), this, SLOT(handleVerticalAxisBaseChanged(qreal)));
+
+ return AbstractDomain::detachAxis(axis);
+}
+
+void XLogYPolarDomain::handleVerticalAxisBaseChanged(qreal baseY)
+{
+ m_logBaseY = baseY;
+ qreal logMinY = log10(m_minY) / log10(m_logBaseY);
+ qreal logMaxY = log10(m_maxY) / log10(m_logBaseY);
+ m_logInnerY = logMinY < logMaxY ? logMinY : logMaxY;
+ m_logOuterY = logMinY > logMaxY ? logMinY : logMaxY;
+ emit updated();
+}
+
+// operators
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2)
+{
+ return (qFuzzyIsNull(domain1.m_maxX - domain2.m_maxX)
+ && qFuzzyIsNull(domain1.m_maxY - domain2.m_maxY)
+ && qFuzzyIsNull(domain1.m_minX - domain2.m_minX)
+ && qFuzzyIsNull(domain1.m_minY - domain2.m_minY));
+}
+
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2)
+{
+ return !(domain1 == domain2);
+}
+
+
+QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XLogYPolarDomain &domain)
+{
+ dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size;
+ return dbg.maybeSpace();
+}
+
+#include "moc_xlogypolardomain_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/domain/xlogypolardomain_p.h b/src/domain/xlogypolardomain_p.h
new file mode 100644
index 00000000..3c3a45b7
--- /dev/null
+++ b/src/domain/xlogypolardomain_p.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef XLOGYPOLARDOMAIN_H
+#define XLOGYPOLARDOMAIN_H
+#include "polardomain_p.h"
+#include <QRectF>
+#include <QSizeF>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QTCOMMERCIALCHART_AUTOTEST_EXPORT XLogYPolarDomain: public PolarDomain
+{
+ Q_OBJECT
+public:
+ explicit XLogYPolarDomain(QObject *object = 0);
+ virtual ~XLogYPolarDomain();
+
+ DomainType type() { return AbstractDomain::XLogYPolarDomain; }
+
+ void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY);
+
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2);
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XLogYPolarDomain &domain1, const XLogYPolarDomain &domain2);
+ friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XLogYPolarDomain &domain);
+
+ void zoomIn(const QRectF &rect);
+ void zoomOut(const QRectF &rect);
+ void move(qreal dx, qreal dy);
+
+ QPointF calculateDomainPoint(const QPointF &point) const;
+
+ bool attachAxis(QAbstractAxis *axis);
+ bool detachAxis(QAbstractAxis *axis);
+
+public Q_SLOTS:
+ void handleVerticalAxisBaseChanged(qreal baseY);
+
+protected:
+ qreal toAngularCoordinate(qreal value, bool &ok) const;
+ qreal toRadialCoordinate(qreal value, bool &ok) const;
+
+private:
+ qreal m_logInnerY;
+ qreal m_logOuterY;
+ qreal m_logBaseY;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // XLOGYPOLARDOMAIN_H
diff --git a/src/domain/xydomain.cpp b/src/domain/xydomain.cpp
index 26f82a15..8ac1f0a0 100644
--- a/src/domain/xydomain.cpp
+++ b/src/domain/xydomain.cpp
@@ -126,7 +126,7 @@ QPointF XYDomain::calculateGeometryPoint(const QPointF &point, bool &ok) const
return QPointF(x, y);
}
-QVector<QPointF> XYDomain::calculateGeometryPoints(const QList<QPointF>& vector) const
+QVector<QPointF> XYDomain::calculateGeometryPoints(const QList<QPointF> &vector) const
{
const qreal deltaX = m_size.width() / (m_maxX - m_minX);
const qreal deltaY = m_size.height() / (m_maxY - m_minY);
@@ -156,10 +156,10 @@ QPointF XYDomain::calculateDomainPoint(const QPointF &point) const
bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XYDomain &domain1, const XYDomain &domain2)
{
- return (qFuzzyCompare(domain1.m_maxX, domain2.m_maxX) &&
- qFuzzyCompare(domain1.m_maxY, domain2.m_maxY) &&
- qFuzzyCompare(domain1.m_minX, domain2.m_minX) &&
- qFuzzyCompare(domain1.m_minY, domain2.m_minY));
+ return (qFuzzyCompare(domain1.m_maxX, domain2.m_maxX)
+ && qFuzzyCompare(domain1.m_maxY, domain2.m_maxY)
+ && qFuzzyCompare(domain1.m_minX, domain2.m_minX)
+ && qFuzzyCompare(domain1.m_minY, domain2.m_minY));
}
diff --git a/src/domain/xydomain_p.h b/src/domain/xydomain_p.h
index 0a990388..657377b2 100644
--- a/src/domain/xydomain_p.h
+++ b/src/domain/xydomain_p.h
@@ -56,7 +56,7 @@ public:
QPointF calculateGeometryPoint(const QPointF &point, bool &ok) const;
QPointF calculateDomainPoint(const QPointF &point) const;
- QVector<QPointF> calculateGeometryPoints(const QList<QPointF>& vector) const;
+ QVector<QPointF> calculateGeometryPoints(const QList<QPointF> &vector) const;
};
QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/domain/xypolardomain.cpp b/src/domain/xypolardomain.cpp
new file mode 100644
index 00000000..e9471293
--- /dev/null
+++ b/src/domain/xypolardomain.cpp
@@ -0,0 +1,178 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "xypolardomain_p.h"
+#include "qabstractaxis_p.h"
+#include <qmath.h>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+XYPolarDomain::XYPolarDomain(QObject *parent)
+ : PolarDomain(parent)
+{
+}
+
+XYPolarDomain::~XYPolarDomain()
+{
+}
+
+void XYPolarDomain::setRange(qreal minX, qreal maxX, qreal minY, qreal maxY)
+{
+ bool axisXChanged = false;
+ bool axisYChanged = false;
+
+ if (!qFuzzyCompare(m_minX, minX) || !qFuzzyCompare(m_maxX, maxX)) {
+ m_minX = minX;
+ m_maxX = maxX;
+ axisXChanged = true;
+ if (!m_signalsBlocked)
+ emit rangeHorizontalChanged(m_minX, m_maxX);
+ }
+
+ if (!qFuzzyCompare(m_minY, minY) || !qFuzzyCompare(m_maxY, maxY)) {
+ m_minY = minY;
+ m_maxY = maxY;
+ axisYChanged = true;
+ if (!m_signalsBlocked)
+ emit rangeVerticalChanged(m_minY, m_maxY);
+ }
+
+ if (axisXChanged || axisYChanged)
+ emit updated();
+}
+
+
+void XYPolarDomain::zoomIn(const QRectF &rect)
+{
+ qreal dx = spanX() / m_size.width();
+ qreal dy = spanY() / m_size.height();
+
+ qreal maxX = m_maxX;
+ qreal minX = m_minX;
+ qreal minY = m_minY;
+ qreal maxY = m_maxY;
+
+ maxX = minX + dx * rect.right();
+ minX = minX + dx * rect.left();
+ minY = maxY - dy * rect.bottom();
+ maxY = maxY - dy * rect.top();
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void XYPolarDomain::zoomOut(const QRectF &rect)
+{
+ qreal dx = spanX() / rect.width();
+ qreal dy = spanY() / rect.height();
+
+ qreal maxX = m_maxX;
+ qreal minX = m_minX;
+ qreal minY = m_minY;
+ qreal maxY = m_maxY;
+
+ minX = maxX - dx * rect.right();
+ maxX = minX + dx * m_size.width();
+ maxY = minY + dy * rect.bottom();
+ minY = maxY - dy * m_size.height();
+
+ setRange(minX, maxX, minY, maxY);
+}
+
+void XYPolarDomain::move(qreal dx, qreal dy)
+{
+ // One unit scrolls one degree angular and one pixel radial
+ qreal x = spanX() / 360.0;
+ qreal y = spanY() / m_radius;
+
+ qreal maxX = m_maxX;
+ qreal minX = m_minX;
+ qreal minY = m_minY;
+ qreal maxY = m_maxY;
+
+ if (dx != 0) {
+ minX = minX + x * dx;
+ maxX = maxX + x * dx;
+ }
+ if (dy != 0) {
+ minY = minY + y * dy;
+ maxY = maxY + y * dy;
+ }
+ setRange(minX, maxX, minY, maxY);
+}
+
+QPointF XYPolarDomain::calculateDomainPoint(const QPointF &point) const
+{
+ if (point == m_center)
+ return QPointF(0.0, m_minX);
+
+ QLineF line(m_center, point);
+ qreal a = 90.0 - line.angle();
+ if (a < 0.0)
+ a += 360.0;
+ a = ((a / 360.0) * (m_maxX - m_minX)) + m_minX;
+ qreal r = m_minY + ((m_maxY - m_minY) * (line.length() / m_radius));
+ return QPointF(a, r);
+}
+
+qreal XYPolarDomain::toAngularCoordinate(qreal value, bool &ok) const
+{
+ ok = true;
+ qreal f = (value - m_minX) / (m_maxX - m_minX);
+ return f * 360.0;
+}
+
+qreal XYPolarDomain::toRadialCoordinate(qreal value, bool &ok) const
+{
+ ok = true;
+ if (value < m_minY)
+ value = m_minY;
+
+ // Dont limit the max. The drawing should clip the stuff that goes out of the grid
+ qreal f = (value - m_minY) / (m_maxY - m_minY);
+
+ return f * m_radius;
+}
+
+// operators
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XYPolarDomain &domain1, const XYPolarDomain &domain2)
+{
+ return (qFuzzyCompare(domain1.m_maxX, domain2.m_maxX)
+ && qFuzzyCompare(domain1.m_maxY, domain2.m_maxY)
+ && qFuzzyCompare(domain1.m_minX, domain2.m_minX)
+ && qFuzzyCompare(domain1.m_minY, domain2.m_minY));
+}
+
+
+bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XYPolarDomain &domain1, const XYPolarDomain &domain2)
+{
+ return !(domain1 == domain2);
+}
+
+
+QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XYPolarDomain &domain)
+{
+ dbg.nospace() << "AbstractDomain(" << domain.m_minX << ',' << domain.m_maxX << ',' << domain.m_minY << ',' << domain.m_maxY << ')' << domain.m_size;
+ return dbg.maybeSpace();
+}
+
+#include "moc_xypolardomain_p.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/domain/xypolardomain_p.h b/src/domain/xypolardomain_p.h
new file mode 100644
index 00000000..662cc5ee
--- /dev/null
+++ b/src/domain/xypolardomain_p.h
@@ -0,0 +1,65 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef XYPOLARDOMAIN_H
+#define XYPOLARDOMAIN_H
+#include "polardomain_p.h"
+#include <QRectF>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QTCOMMERCIALCHART_AUTOTEST_EXPORT XYPolarDomain: public PolarDomain
+{
+ Q_OBJECT
+public:
+ explicit XYPolarDomain(QObject *object = 0);
+ virtual ~XYPolarDomain();
+
+ DomainType type(){ return AbstractDomain::XYPolarDomain;}
+
+ void setRange(qreal minX, qreal maxX, qreal minY, qreal maxY);
+
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator== (const XYPolarDomain &Domain1, const XYPolarDomain &Domain2);
+ friend bool QTCOMMERCIALCHART_AUTOTEST_EXPORT operator!= (const XYPolarDomain &Domain1, const XYPolarDomain &Domain2);
+ friend QDebug QTCOMMERCIALCHART_AUTOTEST_EXPORT operator<<(QDebug dbg, const XYPolarDomain &AbstractDomain);
+
+ void zoomIn(const QRectF &rect);
+ void zoomOut(const QRectF &rect);
+ void move(qreal dx, qreal dy);
+
+ QPointF calculateDomainPoint(const QPointF &point) const;
+
+protected:
+ qreal toAngularCoordinate(qreal value, bool &ok) const;
+ qreal toRadialCoordinate(qreal value, bool &ok) const;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // XYPOLARDOMAIN_H
diff --git a/src/layout/abstractchartlayout.cpp b/src/layout/abstractchartlayout.cpp
new file mode 100644
index 00000000..092e8c0c
--- /dev/null
+++ b/src/layout/abstractchartlayout.cpp
@@ -0,0 +1,197 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "abstractchartlayout_p.h"
+#include "chartpresenter_p.h"
+#include "qlegend_p.h"
+#include "chartaxiselement_p.h"
+#include "charttitle_p.h"
+#include "chartbackground_p.h"
+#include <QDebug>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+static const qreal golden_ratio = 0.4;
+
+AbstractChartLayout::AbstractChartLayout(ChartPresenter *presenter)
+ : m_presenter(presenter),
+ m_margins(20, 20, 20, 20),
+ m_minChartRect(0, 0, 200, 200)
+{
+}
+
+AbstractChartLayout::~AbstractChartLayout()
+{
+}
+
+void AbstractChartLayout::setGeometry(const QRectF &rect)
+{
+ if (!rect.isValid())
+ return;
+
+ QList<ChartAxisElement *> axes = m_presenter->axisItems();
+ ChartTitle *title = m_presenter->titleElement();
+ QLegend *legend = m_presenter->legend();
+ ChartBackground *background = m_presenter->backgroundElement();
+
+ QRectF contentGeometry = calculateBackgroundGeometry(rect, background);
+
+ contentGeometry = calculateContentGeometry(contentGeometry);
+
+ if (title && title->isVisible())
+ contentGeometry = calculateTitleGeometry(contentGeometry, title);
+
+ if (legend->isAttachedToChart() && legend->isVisible())
+ contentGeometry = calculateLegendGeometry(contentGeometry, legend);
+
+ contentGeometry = calculateAxisGeometry(contentGeometry, axes);
+
+ m_presenter->setGeometry(contentGeometry);
+
+ QGraphicsLayout::setGeometry(rect);
+}
+
+QRectF AbstractChartLayout::calculateContentGeometry(const QRectF &geometry) const
+{
+ return geometry.adjusted(m_margins.left(), m_margins.top(), -m_margins.right(), -m_margins.bottom());
+}
+
+QRectF AbstractChartLayout::calculateContentMinimum(const QRectF &minimum) const
+{
+ return minimum.adjusted(0, 0, m_margins.left() + m_margins.right(), m_margins.top() + m_margins.bottom());
+}
+
+
+QRectF AbstractChartLayout::calculateBackgroundGeometry(const QRectF &geometry, ChartBackground *background) const
+{
+ qreal left;
+ qreal top;
+ qreal right;
+ qreal bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+ QRectF backgroundGeometry = geometry.adjusted(left, top, -right, -bottom);
+ if (background)
+ background->setRect(backgroundGeometry);
+ return backgroundGeometry;
+}
+
+QRectF AbstractChartLayout::calculateBackgroundMinimum(const QRectF &minimum) const
+{
+ qreal left;
+ qreal top;
+ qreal right;
+ qreal bottom;
+ getContentsMargins(&left, &top, &right, &bottom);
+ return minimum.adjusted(0, 0, left + right, top + bottom);
+}
+
+QRectF AbstractChartLayout::calculateLegendGeometry(const QRectF &geometry, QLegend *legend) const
+{
+ QSizeF size = legend->effectiveSizeHint(Qt::PreferredSize, QSizeF(-1, -1));
+ QRectF legendRect;
+ QRectF result;
+
+ switch (legend->alignment()) {
+ case Qt::AlignTop: {
+ legendRect = QRectF(geometry.topLeft(), QSizeF(geometry.width(), size.height()));
+ result = geometry.adjusted(0, legendRect.height(), 0, 0);
+ break;
+ }
+ case Qt::AlignBottom: {
+ legendRect = QRectF(QPointF(geometry.left(), geometry.bottom() - size.height()), QSizeF(geometry.width(), size.height()));
+ result = geometry.adjusted(0, 0, 0, -legendRect.height());
+ break;
+ }
+ case Qt::AlignLeft: {
+ qreal width = qMin(size.width(), geometry.width() * golden_ratio);
+ legendRect = QRectF(geometry.topLeft(), QSizeF(width, geometry.height()));
+ result = geometry.adjusted(width, 0, 0, 0);
+ break;
+ }
+ case Qt::AlignRight: {
+ qreal width = qMin(size.width(), geometry.width() * golden_ratio);
+ legendRect = QRectF(QPointF(geometry.right() - width, geometry.top()), QSizeF(width, geometry.height()));
+ result = geometry.adjusted(0, 0, -width, 0);
+ break;
+ }
+ default: {
+ legendRect = QRectF(0, 0, 0, 0);
+ result = geometry;
+ break;
+ }
+ }
+
+ legend->setGeometry(legendRect);
+
+ return result;
+}
+
+QRectF AbstractChartLayout::calculateLegendMinimum(const QRectF &geometry, QLegend *legend) const
+{
+ QSizeF minSize = legend->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, -1));
+ return geometry.adjusted(0, 0, minSize.width(), minSize.height());
+}
+
+QRectF AbstractChartLayout::calculateTitleGeometry(const QRectF &geometry, ChartTitle *title) const
+{
+ title->setGeometry(geometry);
+ QPointF center = geometry.center() - title->boundingRect().center();
+ title->setPos(center.x(), title->pos().y());
+ return geometry.adjusted(0, title->boundingRect().height()+1, 0, 0);
+}
+
+QRectF AbstractChartLayout::calculateTitleMinimum(const QRectF &minimum, ChartTitle *title) const
+{
+ QSizeF min = title->sizeHint(Qt::MinimumSize);
+ return minimum.adjusted(0, 0, min.width(), min.height());
+}
+
+QSizeF AbstractChartLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
+{
+ Q_UNUSED(constraint);
+ if (which == Qt::MinimumSize) {
+ QList<ChartAxisElement *> axes = m_presenter->axisItems();
+ ChartTitle *title = m_presenter->titleElement();
+ QLegend *legend = m_presenter->legend();
+ QRectF minimumRect(0, 0, 0, 0);
+ minimumRect = calculateBackgroundMinimum(minimumRect);
+ minimumRect = calculateContentMinimum(minimumRect);
+ minimumRect = calculateTitleMinimum(minimumRect, title);
+ minimumRect = calculateLegendMinimum(minimumRect, legend);
+ minimumRect = calculateAxisMinimum(minimumRect, axes);
+ return minimumRect.united(m_minChartRect).size().toSize();
+ }
+ return QSize(-1, -1);
+}
+
+void AbstractChartLayout::setMargins(const QMargins &margins)
+{
+ if (m_margins != margins) {
+ m_margins = margins;
+ updateGeometry();
+ }
+}
+
+QMargins AbstractChartLayout::margins() const
+{
+ return m_margins;
+}
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/chartlayout_p.h b/src/layout/abstractchartlayout_p.h
index 5b8d38a8..d28af3d2 100644
--- a/src/chartlayout_p.h
+++ b/src/layout/abstractchartlayout_p.h
@@ -27,51 +27,50 @@
//
// We mean it.
-#ifndef CHARTLAYOUT_H
-#define CHARTLAYOUT_H
+#ifndef ABSTRACTCHARTLAYOUT_H
+#define ABSTRACTCHARTLAYOUT_H
+
#include <QGraphicsLayout>
#include <QMargins>
#include "qchartglobal.h"
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-class ChartPresenter;
class ChartTitle;
+class ChartAxisElement;
+class ChartPresenter;
class QLegend;
-class ChartAxis;
class ChartBackground;
-class ChartLayout : public QGraphicsLayout
+class AbstractChartLayout : public QGraphicsLayout
{
public:
+ AbstractChartLayout(ChartPresenter *presenter);
+ virtual ~AbstractChartLayout();
- ChartLayout(ChartPresenter *presenter);
- virtual ~ChartLayout();
+ virtual void setMargins(const QMargins &margins);
+ virtual QMargins margins() const;
+ virtual void setGeometry(const QRectF &rect);
- void setMargins(const QMargins &margins);
- QMargins margins() const;
+protected:
+ virtual QRectF calculateBackgroundGeometry(const QRectF &geometry, ChartBackground *background) const;
+ virtual QRectF calculateBackgroundMinimum(const QRectF &minimum) const;
+ virtual QRectF calculateContentGeometry(const QRectF &geometry) const;
+ virtual QRectF calculateContentMinimum(const QRectF &minimum) const;
+ virtual QRectF calculateTitleGeometry(const QRectF &geometry, ChartTitle *title) const;
+ virtual QRectF calculateTitleMinimum(const QRectF &minimum, ChartTitle *title) const;
+ virtual QRectF calculateLegendGeometry(const QRectF &geometry, QLegend *legend) const;
+ virtual QRectF calculateLegendMinimum(const QRectF &minimum, QLegend *legend) const;
- void setGeometry(const QRectF &rect);
+ virtual QRectF calculateAxisGeometry(const QRectF &geometry, const QList<ChartAxisElement *>& axes) const = 0;
+ virtual QRectF calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxisElement *>& axes) const = 0;
-protected:
+ // from QGraphicsLayout
QSizeF sizeHint(Qt::SizeHint which, const QSizeF &constraint = QSizeF()) const;
int count() const { return 0; }
QGraphicsLayoutItem *itemAt(int) const { return 0; };
void removeAt(int) {};
-private:
- QRectF calculateBackgroundGeometry(const QRectF &geometry, ChartBackground *background) const;
- QRectF calculateContentGeometry(const QRectF &geometry) const;
- QRectF calculateTitleGeometry(const QRectF &geometry, ChartTitle *title) const;
- QRectF calculateLegendGeometry(const QRectF &geometry, QLegend *legend) const;
- QRectF calculateAxisGeometry(const QRectF &geometry, const QList<ChartAxis *>& axes) const;
- QRectF calculateBackgroundMinimum(const QRectF &minimum) const;
- QRectF calculateContentMinimum(const QRectF &minimum) const;
- QRectF calculateTitleMinimum(const QRectF &minimum, ChartTitle *title) const;
- QRectF calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxis *>& axes) const;
- QRectF calculateLegendMinimum(const QRectF &minimum, QLegend *legend) const;
-
-private:
ChartPresenter *m_presenter;
QMargins m_margins;
QRectF m_minChartRect;
@@ -80,4 +79,4 @@ private:
QTCOMMERCIALCHART_END_NAMESPACE
-#endif
+#endif // ABSTRACTCHARTLAYOUT_H
diff --git a/src/chartlayout.cpp b/src/layout/cartesianchartlayout.cpp
index bd885ba9..f5317752 100644
--- a/src/chartlayout.cpp
+++ b/src/layout/cartesianchartlayout.cpp
@@ -18,88 +18,25 @@
**
****************************************************************************/
-#include "chartlayout_p.h"
+#include "cartesianchartlayout_p.h"
#include "chartpresenter_p.h"
-#include "qlegend_p.h"
-#include "chartaxis_p.h"
-#include "charttitle_p.h"
-#include "chartbackground_p.h"
+#include "chartaxiselement_p.h"
#include <QDebug>
QTCOMMERCIALCHART_BEGIN_NAMESPACE
static const qreal maxAxisPortion = 0.4;
-ChartLayout::ChartLayout(ChartPresenter *presenter)
- : m_presenter(presenter),
- m_margins(20, 20, 20, 20),
- m_minChartRect(0, 0, 200, 200)
+CartesianChartLayout::CartesianChartLayout(ChartPresenter *presenter)
+ : AbstractChartLayout(presenter)
{
-
-}
-
-ChartLayout::~ChartLayout()
-{
-
-}
-
-void ChartLayout::setGeometry(const QRectF &rect)
-{
- if (!rect.isValid())
- return;
-
- QList<ChartAxis *> axes = m_presenter->axisItems();
- ChartTitle *title = m_presenter->titleElement();
- QLegend *legend = m_presenter->legend();
- ChartBackground *background = m_presenter->backgroundElement();
-
- QRectF contentGeometry = calculateBackgroundGeometry(rect, background);
-
- contentGeometry = calculateContentGeometry(contentGeometry);
-
- if (title && title->isVisible())
- contentGeometry = calculateTitleGeometry(contentGeometry, title);
-
- if (legend->isAttachedToChart() && legend->isVisible())
- contentGeometry = calculateLegendGeometry(contentGeometry, legend);
-
- contentGeometry = calculateAxisGeometry(contentGeometry, axes);
-
- m_presenter->setGeometry(contentGeometry);
-
- QGraphicsLayout::setGeometry(rect);
}
-QRectF ChartLayout::calculateContentGeometry(const QRectF &geometry) const
+CartesianChartLayout::~CartesianChartLayout()
{
- return geometry.adjusted(m_margins.left(), m_margins.top(), -m_margins.right(), -m_margins.bottom());
}
-QRectF ChartLayout::calculateContentMinimum(const QRectF &minimum) const
-{
- return minimum.adjusted(0, 0, m_margins.left() + m_margins.right(), m_margins.top() + m_margins.bottom());
-}
-
-
-QRectF ChartLayout::calculateBackgroundGeometry(const QRectF &geometry, ChartBackground *background) const
-{
- qreal left, top, right, bottom;
- getContentsMargins(&left, &top, &right, &bottom);
- QRectF backgroundGeometry = geometry.adjusted(left, top, -right, -bottom);
- if (background)
- background->setRect(backgroundGeometry);
- return backgroundGeometry;
-}
-
-QRectF ChartLayout::calculateBackgroundMinimum(const QRectF &minimum) const
-{
- qreal left, top, right, bottom;
- getContentsMargins(&left, &top, &right, &bottom);
- return minimum.adjusted(0, 0, left + right, top + bottom);
-}
-
-
-QRectF ChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<ChartAxis *>& axes) const
+QRectF CartesianChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<ChartAxisElement *> &axes) const
{
QSizeF left(0,0);
QSizeF minLeft(0,0);
@@ -115,16 +52,17 @@ QRectF ChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<Ch
int topCount = 0;
int bottomCount = 0;
- foreach (ChartAxis *axis , axes) {
+ foreach (ChartAxisElement *axis , axes) {
if (!axis->isVisible())
continue;
+
QSizeF size = axis->effectiveSizeHint(Qt::PreferredSize);
//this is used to get single thick font size
QSizeF minSize = axis->effectiveSizeHint(Qt::MinimumSize);
- switch (axis->alignment()) {
+ switch (axis->axis()->alignment()) {
case Qt::AlignLeft:
left.setWidth(left.width()+size.width());
left.setHeight(qMax(left.height(),size.height()));
@@ -163,7 +101,7 @@ QRectF ChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<Ch
}
}
- int totalVerticalAxes = leftCount + rightCount;
+ qreal totalVerticalAxes = leftCount + rightCount;
qreal leftSqueezeRatio = 1.0;
qreal rightSqueezeRatio = 1.0;
qreal vratio = 0;
@@ -186,7 +124,7 @@ QRectF ChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<Ch
}
}
- int totalHorizontalAxes = topCount + bottomCount;
+ qreal totalHorizontalAxes = topCount + bottomCount;
qreal topSqueezeRatio = 1.0;
qreal bottomSqueezeRatio = 1.0;
qreal hratio = 0;
@@ -225,15 +163,14 @@ QRectF ChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<Ch
qreal topOffset = 0;
qreal bottomOffset = 0;
- foreach(ChartElement *axisElement , axes) {
- ChartAxis* axis = qobject_cast<ChartAxis*>(axisElement);
+ foreach (ChartAxisElement *axis , axes) {
if (!axis->isVisible())
continue;
QSizeF size = axis->effectiveSizeHint(Qt::PreferredSize);
- switch(axis->alignment()){
+ switch (axis->axis()->alignment()){
case Qt::AlignLeft:{
qreal width = size.width();
if (leftSqueezeRatio < 1.0)
@@ -271,21 +208,20 @@ QRectF ChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<Ch
return chartRect;
}
-QRectF ChartLayout::calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxis *>& axes) const
+QRectF CartesianChartLayout::calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxisElement *> &axes) const
{
QSizeF left;
QSizeF right;
QSizeF bottom;
QSizeF top;
- foreach (ChartAxis *axis, axes) {
-
+ foreach (ChartAxisElement *axis, axes) {
QSizeF size = axis->effectiveSizeHint(Qt::MinimumSize);
if (!axis->isVisible())
continue;
- switch (axis->alignment()) {
+ switch (axis->axis()->alignment()) {
case Qt::AlignLeft:
left.setWidth(left.width() + size.width());
left.setHeight(qMax(left.height() * 2, size.height()));
@@ -307,96 +243,4 @@ QRectF ChartLayout::calculateAxisMinimum(const QRectF &minimum, const QList<Char
return minimum.adjusted(0, 0, left.width() + right.width() + qMax(top.width(), bottom.width()), top.height() + bottom.height() + qMax(left.height(), right.height()));
}
-QRectF ChartLayout::calculateLegendGeometry(const QRectF &geometry, QLegend *legend) const
-{
- QSizeF size = legend->effectiveSizeHint(Qt::PreferredSize, QSizeF(-1, -1));
- QRectF legendRect;
- QRectF result;
-
- switch (legend->alignment()) {
- case Qt::AlignTop: {
- legendRect = QRectF(geometry.topLeft(), QSizeF(geometry.width(), size.height()));
- result = geometry.adjusted(0, legendRect.height(), 0, 0);
- break;
- }
- case Qt::AlignBottom: {
- legendRect = QRectF(QPointF(geometry.left(), geometry.bottom() - size.height()), QSizeF(geometry.width(), size.height()));
- result = geometry.adjusted(0, 0, 0, -legendRect.height());
- break;
- }
- case Qt::AlignLeft: {
- qreal width = qMin(size.width(), geometry.width() * maxAxisPortion);
- legendRect = QRectF(geometry.topLeft(), QSizeF(width, geometry.height()));
- result = geometry.adjusted(width, 0, 0, 0);
- break;
- }
- case Qt::AlignRight: {
- qreal width = qMin(size.width(), geometry.width() * maxAxisPortion);
- legendRect = QRectF(QPointF(geometry.right() - width, geometry.top()), QSizeF(width, geometry.height()));
- result = geometry.adjusted(0, 0, -width, 0);
- break;
- }
- default: {
- legendRect = QRectF(0, 0, 0, 0);
- result = geometry;
- break;
- }
- }
-
- legend->setGeometry(legendRect);
-
- return result;
-}
-
-QRectF ChartLayout::calculateLegendMinimum(const QRectF &geometry, QLegend *legend) const
-{
- QSizeF minSize = legend->effectiveSizeHint(Qt::MinimumSize, QSizeF(-1, -1));
- return geometry.adjusted(0, 0, minSize.width(), minSize.height());
-}
-
-QRectF ChartLayout::calculateTitleGeometry(const QRectF &geometry, ChartTitle *title) const
-{
- title->setGeometry(geometry);
- QPointF center = geometry.center() - title->boundingRect().center();
- title->setPos(center.x(),title->pos().y());
- return geometry.adjusted(0,title->boundingRect().height()+1,0,0);
-}
-
-QRectF ChartLayout::calculateTitleMinimum(const QRectF &minimum, ChartTitle *title) const
-{
- QSizeF min = title->sizeHint(Qt::MinimumSize);
- return minimum.adjusted(0, 0, min.width(), min.height());
-}
-
-QSizeF ChartLayout::sizeHint(Qt::SizeHint which, const QSizeF &constraint) const
-{
- Q_UNUSED(constraint);
- if (which == Qt::MinimumSize) {
- QList<ChartAxis *> axes = m_presenter->axisItems();
- ChartTitle *title = m_presenter->titleElement();
- QLegend *legend = m_presenter->legend();
- QRectF minimumRect(0, 0, 0, 0);
- minimumRect = calculateBackgroundMinimum(minimumRect);
- minimumRect = calculateContentMinimum(minimumRect);
- minimumRect = calculateTitleMinimum(minimumRect, title);
- minimumRect = calculateLegendMinimum(minimumRect, legend);
- minimumRect = calculateAxisMinimum(minimumRect, axes);
- return minimumRect.united(m_minChartRect).size().toSize();
- }
- return QSize(-1, -1);
-}
-
-void ChartLayout::setMargins(const QMargins &margins)
-{
- if (m_margins != margins) {
- m_margins = margins;
- updateGeometry();
- }
-}
-
-QMargins ChartLayout::margins() const
-{
- return m_margins;
-}
-
QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/layout/cartesianchartlayout_p.h b/src/layout/cartesianchartlayout_p.h
new file mode 100644
index 00000000..88d540b0
--- /dev/null
+++ b/src/layout/cartesianchartlayout_p.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef CARTESIANCHARTLAYOUT_H
+#define CARTESIANCHARTLAYOUT_H
+
+#include "abstractchartlayout_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class CartesianChartLayout : public AbstractChartLayout
+{
+public:
+ CartesianChartLayout(ChartPresenter *presenter);
+ virtual ~CartesianChartLayout();
+
+ // from AbstractChartLayout
+ QRectF calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxisElement *> &axes) const;
+ QRectF calculateAxisGeometry(const QRectF &geometry, const QList<ChartAxisElement *> &axes) const;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // CARTESIANCHARTLAYOUT_H
diff --git a/src/layout/layout.pri b/src/layout/layout.pri
new file mode 100644
index 00000000..159eab13
--- /dev/null
+++ b/src/layout/layout.pri
@@ -0,0 +1,12 @@
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+
+SOURCES += \
+ $$PWD/abstractchartlayout.cpp \
+ $$PWD/cartesianchartlayout.cpp \
+ $$PWD/polarchartlayout.cpp
+
+PRIVATE_HEADERS += \
+ $$PWD/abstractchartlayout_p.h \
+ $$PWD/cartesianchartlayout_p.h \
+ $$PWD/polarchartlayout_p.h
diff --git a/src/layout/polarchartlayout.cpp b/src/layout/polarchartlayout.cpp
new file mode 100644
index 00000000..ad48244a
--- /dev/null
+++ b/src/layout/polarchartlayout.cpp
@@ -0,0 +1,83 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "polarchartlayout_p.h"
+#include "chartpresenter_p.h"
+#include "polarchartaxis_p.h"
+#include <QDebug>
+#include <QFontMetrics>
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+static const qreal golden_ratio = 0.4;
+
+PolarChartLayout::PolarChartLayout(ChartPresenter *presenter)
+ : AbstractChartLayout(presenter)
+{
+}
+
+PolarChartLayout::~PolarChartLayout()
+{
+}
+
+QRectF PolarChartLayout::calculateAxisGeometry(const QRectF &geometry, const QList<ChartAxisElement *> &axes) const
+{
+ // How to handle multiple angular/radial axes?
+ qreal axisRadius = geometry.height() / 2.0;
+ if (geometry.width() < geometry.height())
+ axisRadius = geometry.width() / 2.0;
+
+ int titleHeight = 0;
+ foreach (ChartAxisElement *chartAxis, axes) {
+ if (!chartAxis->isVisible())
+ continue;
+
+ PolarChartAxis *polarChartAxis = static_cast<PolarChartAxis *>(chartAxis);
+ qreal radius = polarChartAxis->preferredAxisRadius(geometry.size());
+ if (radius < axisRadius)
+ axisRadius = radius;
+
+ if (chartAxis->axis()->orientation() == Qt::Horizontal
+ && chartAxis->axis()->isTitleVisible()
+ && !chartAxis->axis()->titleText().isEmpty()) {
+ // If axis has angular title, adjust geometry down by the space title takes
+ QFontMetrics titleMetrics(chartAxis->axis()->titleFont());
+ titleHeight = (titleMetrics.boundingRect(chartAxis->axis()->titleText()).height() / 2) + chartAxis->titlePadding();
+ }
+ }
+
+ QRectF axisRect;
+ axisRect.setSize(QSizeF(axisRadius * 2.0, axisRadius * 2.0));
+ axisRect.moveCenter(geometry.center());
+ axisRect.adjust(0, titleHeight, 0, titleHeight);
+
+ foreach (ChartAxisElement *chartAxis, axes)
+ chartAxis->setGeometry(axisRect, QRectF());
+
+ return axisRect;
+}
+
+QRectF PolarChartLayout::calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxisElement *> &axes) const
+{
+ Q_UNUSED(axes);
+ return minimum;
+}
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/layout/polarchartlayout_p.h b/src/layout/polarchartlayout_p.h
new file mode 100644
index 00000000..e8d5db44
--- /dev/null
+++ b/src/layout/polarchartlayout_p.h
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+// W A R N I N G
+// -------------
+//
+// This file is not part of the QtCommercial Chart API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+
+#ifndef POLARCHARTLAYOUT_H
+#define POLARCHARTLAYOUT_H
+
+#include "abstractchartlayout_p.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class PolarChartLayout : public AbstractChartLayout
+{
+public:
+ PolarChartLayout(ChartPresenter *presenter);
+ virtual ~PolarChartLayout();
+
+ // from AbstractChartLayout
+ QRectF calculateAxisMinimum(const QRectF &minimum, const QList<ChartAxisElement *> &axes) const;
+ QRectF calculateAxisGeometry(const QRectF &geometry, const QList<ChartAxisElement *> &axes) const;
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // POLARCHARTLAYOUT_H
diff --git a/src/legend/legendlayout.cpp b/src/legend/legendlayout.cpp
index e405c793..6d5f8328 100644
--- a/src/legend/legendlayout.cpp
+++ b/src/legend/legendlayout.cpp
@@ -21,7 +21,7 @@
#include "legendlayout_p.h"
#include "chartpresenter_p.h"
#include "qlegend_p.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include "qlegendmarker_p.h"
#include "legendmarkeritem_p.h"
diff --git a/src/legend/qlegend.cpp b/src/legend/qlegend.cpp
index 8a34afe3..1920d258 100644
--- a/src/legend/qlegend.cpp
+++ b/src/legend/qlegend.cpp
@@ -25,7 +25,7 @@
#include "qchart_p.h"
#include "legendlayout_p.h"
#include "chartpresenter_p.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include "qlegendmarker.h"
#include "qlegendmarker_p.h"
#include "legendmarkeritem_p.h"
diff --git a/src/linechart/linechartitem.cpp b/src/linechart/linechartitem.cpp
index 1f10d53e..dd5f540d 100644
--- a/src/linechart/linechartitem.cpp
+++ b/src/linechart/linechartitem.cpp
@@ -22,7 +22,7 @@
#include "qlineseries.h"
#include "qlineseries_p.h"
#include "chartpresenter_p.h"
-#include "abstractdomain_p.h"
+#include "polardomain_p.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
@@ -30,10 +30,11 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
const qreal mouseEventMinWidth(12);
-LineChartItem::LineChartItem(QLineSeries *series,QGraphicsItem* item)
+LineChartItem::LineChartItem(QLineSeries *series, QGraphicsItem *item)
: XYChart(series,item),
m_series(series),
- m_pointsVisible(false)
+ m_pointsVisible(false),
+ m_chartType(QChart::ChartTypeUndefined)
{
setAcceptHoverEvents(true);
setZValue(ChartPresenter::LineChartZValue);
@@ -50,54 +51,235 @@ QRectF LineChartItem::boundingRect() const
QPainterPath LineChartItem::shape() const
{
- return m_path;
+ return m_shapePath;
}
void LineChartItem::updateGeometry()
{
m_points = geometryPoints();
+ const QVector<QPointF> &points = m_points;
- if (m_points.size() == 0) {
+ if (points.size() == 0) {
prepareGeometryChange();
- m_path = QPainterPath();
+ m_fullPath = QPainterPath();
m_linePath = QPainterPath();
m_rect = QRect();
return;
}
- QPainterPath linePath(m_points.at(0));
+ QPainterPath linePath;
+ QPainterPath fullPath;
+ // Use worst case scenario to determine required margin.
+ qreal margin = m_linePen.width() * 1.42;
- if (m_pointsVisible) {
+ // Area series use component line series that aren't necessarily added to the chart themselves,
+ // so check if chart type is forced before trying to obtain it from the chart.
+ QChart::ChartType chartType = m_chartType;
+ if (chartType == QChart::ChartTypeUndefined)
+ chartType = m_series->chart()->chartType();
+ // For polar charts, we need special handling for angular (horizontal)
+ // points that are off-grid.
+ if (chartType == QChart::ChartTypePolar) {
+ QPainterPath linePathLeft;
+ QPainterPath linePathRight;
+ QPainterPath *currentSegmentPath = 0;
+ QPainterPath *previousSegmentPath = 0;
+ qreal minX = domain()->minX();
+ qreal maxX = domain()->maxX();
+ qreal minY = domain()->minY();
+ QPointF currentSeriesPoint = m_series->pointAt(0);
+ QPointF currentGeometryPoint = points.at(0);
+ QPointF previousGeometryPoint = points.at(0);
int size = m_linePen.width();
- linePath.addEllipse(m_points.at(0), size, size);
- linePath.moveTo(m_points.at(0));
- for (int i = 1; i < m_points.size(); i++) {
- linePath.lineTo(m_points.at(i));
- linePath.addEllipse(m_points.at(i), size, size);
- linePath.moveTo(m_points.at(i));
+ bool pointOffGrid = false;
+ bool previousPointWasOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
+
+ qreal domainRadius = domain()->size().height() / 2.0;
+ const QPointF centerPoint(domainRadius, domainRadius);
+
+ if (!previousPointWasOffGrid) {
+ fullPath.moveTo(points.at(0));
+ if (m_pointsVisible && currentSeriesPoint.y() >= minY) {
+ // Do not draw ellipses for points below minimum Y.
+ linePath.addEllipse(points.at(0), size, size);
+ fullPath.addEllipse(points.at(0), size, size);
+ linePath.moveTo(points.at(0));
+ fullPath.moveTo(points.at(0));
+ }
}
- } else {
- for (int i = 1; i < m_points.size(); i++)
- linePath.lineTo(m_points.at(i));
- }
+ qreal leftMarginLine = centerPoint.x() - margin;
+ qreal rightMarginLine = centerPoint.x() + margin;
+ qreal horizontal = centerPoint.y();
- m_linePath = linePath;
+ for (int i = 1; i < points.size(); i++) {
+ // Interpolating line fragments would be ugly when thick pen is used,
+ // so we work around it by utilizing three separate
+ // paths for line segments and clip those with custom regions at paint time.
+ // "Right" path contains segments that cross the axis line with visible point on the
+ // right side of the axis line, as well as segments that have one point within the margin
+ // on the right side of the axis line and another point on the right side of the chart.
+ // "Left" path contains points with similarly on the left side.
+ // "Full" path contains rest of the points.
+ // This doesn't yield perfect results always. E.g. when segment covers more than 90
+ // degrees and both of the points are within the margin, one in the top half and one in the
+ // bottom half of the chart, the bottom one gets clipped incorrectly.
+ // However, this should be rare occurrence in any sensible chart.
+ currentSeriesPoint = m_series->pointAt(i);
+ currentGeometryPoint = points.at(i);
+ pointOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
+
+ // Draw something unless both off-grid
+ if (!pointOffGrid || !previousPointWasOffGrid) {
+ QPointF intersectionPoint;
+ qreal y;
+ if (pointOffGrid != previousPointWasOffGrid) {
+ if (currentGeometryPoint.x() == previousGeometryPoint.x()) {
+ y = currentGeometryPoint.y() + (currentGeometryPoint.y() - previousGeometryPoint.y()) / 2.0;
+ } else {
+ qreal ratio = (centerPoint.x() - currentGeometryPoint.x()) / (currentGeometryPoint.x() - previousGeometryPoint.x());
+ y = currentGeometryPoint.y() + (currentGeometryPoint.y() - previousGeometryPoint.y()) * ratio;
+ }
+ intersectionPoint = QPointF(centerPoint.x(), y);
+ }
+
+ bool dummyOk; // We know points are ok, but this is needed
+ qreal currentAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(currentSeriesPoint.x(), dummyOk);
+ qreal previousAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(m_series->pointAt(i - 1).x(), dummyOk);
+
+ if ((qAbs(currentAngle - previousAngle) > 180.0)) {
+ // If the angle between two points is over 180 degrees (half X range),
+ // any direct segment between them becomes meaningless.
+ // In this case two line segments are drawn instead, from previous
+ // point to the center and from center to current point.
+ if ((previousAngle < 0.0 || (previousAngle <= 180.0 && previousGeometryPoint.x() < rightMarginLine))
+ && previousGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &linePathRight;
+ } else if ((previousAngle > 360.0 || (previousAngle > 180.0 && previousGeometryPoint.x() > leftMarginLine))
+ && previousGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &linePathLeft;
+ } else if (previousAngle > 0.0 && previousAngle < 360.0) {
+ currentSegmentPath = &linePath;
+ } else {
+ currentSegmentPath = 0;
+ }
+
+ if (currentSegmentPath) {
+ if (previousSegmentPath != currentSegmentPath)
+ currentSegmentPath->moveTo(previousGeometryPoint);
+ if (previousPointWasOffGrid)
+ fullPath.moveTo(intersectionPoint);
+
+ currentSegmentPath->lineTo(centerPoint);
+ fullPath.lineTo(centerPoint);
+ }
+
+ previousSegmentPath = currentSegmentPath;
+
+ if ((currentAngle < 0.0 || (currentAngle <= 180.0 && currentGeometryPoint.x() < rightMarginLine))
+ && currentGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &linePathRight;
+ } else if ((currentAngle > 360.0 || (currentAngle > 180.0 &&currentGeometryPoint.x() > leftMarginLine))
+ && currentGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &linePathLeft;
+ } else if (currentAngle > 0.0 && currentAngle < 360.0) {
+ currentSegmentPath = &linePath;
+ } else {
+ currentSegmentPath = 0;
+ }
+
+ if (currentSegmentPath) {
+ if (previousSegmentPath != currentSegmentPath)
+ currentSegmentPath->moveTo(centerPoint);
+ if (!previousSegmentPath)
+ fullPath.moveTo(centerPoint);
+
+ currentSegmentPath->lineTo(currentGeometryPoint);
+ if (pointOffGrid)
+ fullPath.lineTo(intersectionPoint);
+ else
+ fullPath.lineTo(currentGeometryPoint);
+ }
+ } else {
+ if (previousAngle < 0.0 || currentAngle < 0.0
+ || ((previousAngle <= 180.0 && currentAngle <= 180.0)
+ && ((previousGeometryPoint.x() < rightMarginLine && previousGeometryPoint.y() < horizontal)
+ || (currentGeometryPoint.x() < rightMarginLine && currentGeometryPoint.y() < horizontal)))) {
+ currentSegmentPath = &linePathRight;
+ } else if (previousAngle > 360.0 || currentAngle > 360.0
+ || ((previousAngle > 180.0 && currentAngle > 180.0)
+ && ((previousGeometryPoint.x() > leftMarginLine && previousGeometryPoint.y() < horizontal)
+ || (currentGeometryPoint.x() > leftMarginLine && currentGeometryPoint.y() < horizontal)))) {
+ currentSegmentPath = &linePathLeft;
+ } else {
+ currentSegmentPath = &linePath;
+ }
+
+ if (currentSegmentPath != previousSegmentPath)
+ currentSegmentPath->moveTo(previousGeometryPoint);
+ if (previousPointWasOffGrid)
+ fullPath.moveTo(intersectionPoint);
+
+ if (pointOffGrid)
+ fullPath.lineTo(intersectionPoint);
+ else
+ fullPath.lineTo(currentGeometryPoint);
+ currentSegmentPath->lineTo(currentGeometryPoint);
+ }
+ } else {
+ currentSegmentPath = 0;
+ }
+
+ previousPointWasOffGrid = pointOffGrid;
+ if (m_pointsVisible && !pointOffGrid && currentSeriesPoint.y() >= minY) {
+ linePath.addEllipse(points.at(i), size, size);
+ fullPath.addEllipse(points.at(i), size, size);
+ linePath.moveTo(points.at(i));
+ fullPath.moveTo(points.at(i));
+ }
+ previousSegmentPath = currentSegmentPath;
+ previousGeometryPoint = currentGeometryPoint;
+ }
+ m_linePathPolarRight = linePathRight;
+ m_linePathPolarLeft = linePathLeft;
+ // Note: This construction of m_fullpath is not perfect. The partial segments that are
+ // outside left/right clip regions at axis boundary still generate hover/click events,
+ // because shape doesn't get clipped. It doesn't seem possible to do sensibly.
+ } else { // not polar
+ linePath.moveTo(points.at(0));
+ if (m_pointsVisible) {
+ int size = m_linePen.width();
+ linePath.addEllipse(points.at(0), size, size);
+ linePath.moveTo(points.at(0));
+ for (int i = 1; i < points.size(); i++) {
+ linePath.lineTo(points.at(i));
+ linePath.addEllipse(points.at(i), size, size);
+ linePath.moveTo(points.at(i));
+ }
+ } else {
+ for (int i = 1; i < points.size(); i++)
+ linePath.lineTo(points.at(i));
+ }
+ fullPath = linePath;
+ }
QPainterPathStroker stroker;
// QPainter::drawLine does not respect join styles, for example BevelJoin becomes MiterJoin.
// This is why we are prepared for the "worst case" scenario, i.e. use always MiterJoin and
// multiply line width with square root of two when defining shape and bounding rectangle.
- stroker.setWidth(m_linePen.width() * 1.42);
+ stroker.setWidth(margin);
stroker.setJoinStyle(Qt::MiterJoin);
stroker.setCapStyle(Qt::SquareCap);
stroker.setMiterLimit(m_linePen.miterLimit());
prepareGeometryChange();
- m_path = stroker.createStroke(linePath);
- m_rect = m_path.boundingRect();
+ m_linePath = linePath;
+ m_fullPath = fullPath;
+ m_shapePath = stroker.createStroke(fullPath);
+
+ m_rect = m_shapePath.boundingRect();
}
void LineChartItem::handleUpdated()
@@ -121,16 +303,35 @@ void LineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt
Q_UNUSED(widget)
Q_UNUSED(option)
+ QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
+
painter->save();
painter->setPen(m_linePen);
- painter->setClipRect(QRectF(QPointF(0,0),domain()->size()));
+ bool alwaysUsePath = false;
+
+ if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
+ qreal halfWidth = domain()->size().width() / 2.0;
+ QRectF clipRectLeft = QRectF(0, 0, halfWidth, domain()->size().height());
+ QRectF clipRectRight = QRectF(halfWidth, 0, halfWidth, domain()->size().height());
+ QRegion fullPolarClipRegion(clipRect.toRect(), QRegion::Ellipse);
+ QRegion clipRegionLeft(fullPolarClipRegion.intersected(clipRectLeft.toRect()));
+ QRegion clipRegionRight(fullPolarClipRegion.intersected(clipRectRight.toRect()));
+ painter->setClipRegion(clipRegionLeft);
+ painter->drawPath(m_linePathPolarLeft);
+ painter->setClipRegion(clipRegionRight);
+ painter->drawPath(m_linePathPolarRight);
+ painter->setClipRegion(fullPolarClipRegion);
+ alwaysUsePath = true; // required for proper clipping
+ } else {
+ painter->setClipRect(clipRect);
+ }
if (m_pointsVisible) {
painter->setBrush(m_linePen.color());
painter->drawPath(m_linePath);
} else {
painter->setBrush(QBrush(Qt::NoBrush));
- if (m_linePen.style() != Qt::SolidLine) {
+ if (m_linePen.style() != Qt::SolidLine || alwaysUsePath) {
// If pen style is not solid line, always fall back to path painting
// to ensure proper continuity of the pattern
painter->drawPath(m_linePath);
diff --git a/src/linechart/linechartitem_p.h b/src/linechart/linechartitem_p.h
index 6db4ccfb..2a728f3b 100644
--- a/src/linechart/linechartitem_p.h
+++ b/src/linechart/linechartitem_p.h
@@ -32,6 +32,7 @@
#include "qchartglobal.h"
#include "xychart_p.h"
+#include "qchart.h"
#include <QPen>
QTCOMMERCIALCHART_BEGIN_NAMESPACE
@@ -44,7 +45,7 @@ class LineChartItem : public XYChart
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
- explicit LineChartItem(QLineSeries *series, QGraphicsItem* item = 0);
+ explicit LineChartItem(QLineSeries *series, QGraphicsItem *item = 0);
~LineChartItem() {}
//from QGraphicsItem
@@ -52,7 +53,7 @@ public:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
QPainterPath shape() const;
- QPainterPath path() const { return m_linePath; }
+ QPainterPath path() const { return m_fullPath; }
public Q_SLOTS:
void handleUpdated();
@@ -63,15 +64,21 @@ protected:
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
void suppressPoints() { m_pointsVisible = false; }
+ void forceChartType(QChart::ChartType chartType) { m_chartType = chartType; }
private:
QLineSeries *m_series;
- QPainterPath m_path;
QPainterPath m_linePath;
+ QPainterPath m_linePathPolarRight;
+ QPainterPath m_linePathPolarLeft;
+ QPainterPath m_fullPath;
+ QPainterPath m_shapePath;
+
QVector<QPointF> m_points;
QRectF m_rect;
QPen m_linePen;
bool m_pointsVisible;
+ QChart::ChartType m_chartType;
};
QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/qchart.cpp b/src/qchart.cpp
index 8ab736ec..f2fd1b67 100644
--- a/src/qchart.cpp
+++ b/src/qchart.cpp
@@ -24,7 +24,7 @@
#include "qlegend_p.h"
#include "chartbackground_p.h"
#include "qabstractaxis.h"
-#include "chartlayout_p.h"
+#include "abstractchartlayout_p.h"
#include "charttheme_p.h"
#include "chartpresenter_p.h"
#include "chartdataset_p.h"
@@ -59,6 +59,16 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
*/
/*!
+ \enum QChart::ChartType
+
+ This enum describes the chart type.
+
+ \value ChartTypeUndefined
+ \value ChartTypeCartesian
+ \value ChartTypePolar
+ */
+
+/*!
\class QChart
\brief QtCommercial chart API.
@@ -110,15 +120,34 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
*/
/*!
- Constructs a chart object which is a child of a\a parent. Parameter \a wFlags is passed to the QGraphicsWidget constructor.
+ \property QChart::chartType
+ Chart type indicates if the chart is a cartesian chart or a polar chart.
+ This property is set internally and is read only.
+ \sa QPolarChart
+ */
+
+/*!
+ \internal
+ Constructs a chart object of \a type which is a child of a \a parent.
+ Parameter \a wFlags is passed to the QGraphicsWidget constructor.
+ This constructor is called only by subclasses.
+*/
+QChart::QChart(QChart::ChartType type, QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QGraphicsWidget(parent, wFlags),
+ d_ptr(new QChartPrivate(this, type))
+{
+ d_ptr->init();
+}
+
+/*!
+ Constructs a chart object which is a child of a \a parent.
+ Parameter \a wFlags is passed to the QGraphicsWidget constructor.
*/
QChart::QChart(QGraphicsItem *parent, Qt::WindowFlags wFlags)
: QGraphicsWidget(parent, wFlags),
- d_ptr(new QChartPrivate(this))
+ d_ptr(new QChartPrivate(this, ChartTypeCartesian))
{
- d_ptr->m_legend = new LegendScroller(this);
- setTheme(QChart::ChartThemeLight);
- setLayout(d_ptr->m_presenter->layout());
+ d_ptr->init();
}
/*!
@@ -269,9 +298,12 @@ void QChart::zoomIn()
/*!
Zooms in the view to a maximum level at which \a rect is still fully visible.
+ \note This is not supported for polar charts.
*/
void QChart::zoomIn(const QRectF &rect)
{
+ if (d_ptr->m_type == QChart::ChartTypePolar)
+ return;
d_ptr->zoomIn(rect);
}
@@ -306,8 +338,8 @@ void QChart::zoom(qreal factor)
}
/*!
- Returns the pointer to the x axis object of the chart asociated with the specified \a series
- If no series is provided then pointer to currently visible axis is provided
+ Returns the pointer to the x axis object of the chart associated with the specified \a series.
+ If no series is provided then pointer to currently visible axis is provided.
*/
QAbstractAxis *QChart::axisX(QAbstractSeries *series) const
{
@@ -318,8 +350,8 @@ QAbstractAxis *QChart::axisX(QAbstractSeries *series) const
}
/*!
- Returns the pointer to the y axis object of the chart asociated with the specified \a series
- If no series is provided then pointer to currently visible axis is provided
+ Returns the pointer to the y axis object of the chart associated with the specified \a series.
+ If no series is provided then pointer to currently visible axis is provided.
*/
QAbstractAxis *QChart::axisY(QAbstractSeries *series) const
{
@@ -438,6 +470,11 @@ QMargins QChart::margins() const
return d_ptr->m_presenter->layout()->margins();
}
+QChart::ChartType QChart::chartType() const
+{
+ return d_ptr->m_type;
+}
+
/*!
Returns the the rect within which the drawing of the chart is done.
It does not include the area defines by margins.
@@ -471,6 +508,8 @@ QChart::AnimationOptions QChart::animationOptions() const
/*!
Scrolls the visible area of the chart by the distance defined in the \a dx and \a dy.
+
+ For polar charts, \a dx indicates the angle along angular axis instead of distance.
*/
void QChart::scroll(qreal dx, qreal dy)
{
@@ -581,11 +620,12 @@ QPointF QChart::mapToPosition(const QPointF &value, QAbstractSeries *series)
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-QChartPrivate::QChartPrivate(QChart *q):
+QChartPrivate::QChartPrivate(QChart *q, QChart::ChartType type):
q_ptr(q),
+ m_type(type),
m_legend(0),
m_dataset(new ChartDataSet(q)),
- m_presenter(new ChartPresenter(q)),
+ m_presenter(new ChartPresenter(q, type)),
m_themeManager(new ChartThemeManager(q))
{
QObject::connect(m_dataset, SIGNAL(seriesAdded(QAbstractSeries*)), m_presenter, SLOT(handleSeriesAdded(QAbstractSeries*)));
@@ -603,6 +643,13 @@ QChartPrivate::~QChartPrivate()
}
+void QChartPrivate::init()
+{
+ m_legend = new LegendScroller(q_ptr);
+ q_ptr->setTheme(QChart::ChartThemeLight);
+ q_ptr->setLayout(m_presenter->layout());
+}
+
void QChartPrivate::zoomIn(qreal factor)
{
QRectF rect = m_presenter->geometry();
diff --git a/src/qchart.h b/src/qchart.h
index e18b127f..3f026732 100644
--- a/src/qchart.h
+++ b/src/qchart.h
@@ -45,10 +45,18 @@ class QTCOMMERCIALCHART_EXPORT QChart : public QGraphicsWidget
Q_PROPERTY(QChart::AnimationOptions animationOptions READ animationOptions WRITE setAnimationOptions)
Q_PROPERTY(QMargins minimumMargins READ minimumMargins WRITE setMinimumMargins)
Q_PROPERTY(QMargins margins READ margins WRITE setMargins)
+ Q_PROPERTY(QChart::ChartType chartType READ chartType)
Q_ENUMS(ChartTheme)
Q_ENUMS(AnimationOption)
+ Q_ENUMS(ChartType)
public:
+ enum ChartType {
+ ChartTypeUndefined = 0,
+ ChartTypeCartesian,
+ ChartTypePolar
+ };
+
enum ChartTheme {
ChartThemeLight = 0,
ChartThemeBlueCerulean,
@@ -84,7 +92,7 @@ public:
QAbstractAxis *axisY(QAbstractSeries *series = 0) const;
// ******************
- void addAxis(QAbstractAxis *axis,Qt::Alignment alignment);
+ void addAxis(QAbstractAxis *axis, Qt::Alignment alignment);
void removeAxis(QAbstractAxis *axis);
QList<QAbstractAxis*> axes(Qt::Orientations orientation = Qt::Horizontal|Qt::Vertical, QAbstractSeries *series = 0) const;
@@ -133,7 +141,10 @@ public:
QPointF mapToValue(const QPointF &position, QAbstractSeries *series = 0);
QPointF mapToPosition(const QPointF &value, QAbstractSeries *series = 0);
+ ChartType chartType() const;
+
protected:
+ explicit QChart(QChart::ChartType type, QGraphicsItem *parent, Qt::WindowFlags wFlags);
QScopedPointer<QChartPrivate> d_ptr;
friend class QLegend;
friend class DeclarativeChart;
diff --git a/src/qchart_p.h b/src/qchart_p.h
index f26a3600..e715bc63 100644
--- a/src/qchart_p.h
+++ b/src/qchart_p.h
@@ -31,10 +31,10 @@
#define QCHART_P_H
#include "qchartglobal.h"
+#include "qchart.h"
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-class QChart;
class ChartThemeManager;
class ChartPresenter;
class QLegend;
@@ -44,14 +44,16 @@ class QChartPrivate
{
public:
- QChartPrivate(QChart *q);
+ QChartPrivate(QChart *q, QChart::ChartType type);
~QChartPrivate();
QChart *q_ptr;
QLegend *m_legend;
ChartDataSet *m_dataset;
ChartPresenter *m_presenter;
ChartThemeManager *m_themeManager;
+ QChart::ChartType m_type;
+ void init();
void zoomIn(qreal factor);
void zoomOut(qreal factor);
void zoomIn(const QRectF &rect);
diff --git a/src/qpolarchart.cpp b/src/qpolarchart.cpp
new file mode 100644
index 00000000..1d93d35e
--- /dev/null
+++ b/src/qpolarchart.cpp
@@ -0,0 +1,126 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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 "qpolarchart.h"
+#include "qabstractaxis.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+/*!
+ \enum QPolarChart::PolarOrientation
+
+ This type is used to signify the polar orientation of an axis.
+
+ \value PolarOrientationRadial
+ \value PolarOrientationAngular
+*/
+
+/*!
+ \class QPolarChart
+ \brief QtCommercial chart API.
+
+ QPolarChart is a specialization of QChart to show a polar chart.
+
+ Polar charts support line, spline, area, and scatter series, and all axis types
+ supported by those series.
+
+ \note When setting ticks to an angular QValueAxis, keep in mind that the first and last tick
+ are co-located at 0/360 degree angle.
+
+ \note If the angular distance between two consecutive points in a series is more than 180 degrees,
+ any line connecting the two points becomes meaningless, so choose the axis ranges accordingly
+ when displaying line, spline, or area series.
+
+ \note Polar charts do not support multiple axes of same orientation.
+
+ \sa QChart
+ */
+
+/*!
+ Constructs a polar chart as a child of a \a parent.
+ Parameter \a wFlags is passed to the QChart constructor.
+ */
+QPolarChart::QPolarChart(QGraphicsItem *parent, Qt::WindowFlags wFlags)
+ : QChart(QChart::ChartTypePolar, parent, wFlags)
+{
+}
+
+/*!
+ Destroys the object and it's children, like series and axis objects added to it.
+ */
+QPolarChart::~QPolarChart()
+{
+}
+
+/*!
+ Returns the axes added for the \a series with \a polarOrientation. If no series is provided, then any axis with the
+ specified polar orientation is returned.
+ \sa addAxis()
+ */
+QList<QAbstractAxis *> QPolarChart::axes(PolarOrientations polarOrientation, QAbstractSeries *series) const
+{
+ Qt::Orientations orientation(0);
+ if (polarOrientation.testFlag(PolarOrientationAngular))
+ orientation |= Qt::Horizontal;
+ if (polarOrientation.testFlag(PolarOrientationRadial))
+ orientation |= Qt::Vertical;
+
+ return QChart::axes(orientation, series);
+}
+
+/*!
+ This convenience method adds \a axis to the polar chart with \a polarOrientation.
+ The chart takes the ownership of the axis.
+
+ \note Axes can be added to a polar chart also with QChart::addAxis() instead of this method.
+ The specified alignment determines the polar orientation: horizontal alignments indicate angular
+ axis and vertical alignments indicate radial axis.
+ \sa QChart::removeAxis(), QChart::createDefaultAxes(), QAbstractSeries::attachAxis(), QChart::addAxis()
+*/
+void QPolarChart::addAxis(QAbstractAxis *axis, PolarOrientation polarOrientation)
+{
+ if (!axis || axis->type() == QAbstractAxis::AxisTypeBarCategory) {
+ qWarning("QAbstractAxis::AxisTypeBarCategory is not a supported axis type for polar charts.");
+ } else {
+ Qt::Alignment alignment = Qt::AlignLeft;
+ if (polarOrientation == PolarOrientationAngular)
+ alignment = Qt::AlignBottom;
+ QChart::addAxis(axis, alignment);
+ }
+}
+
+/*!
+ Angular axes of a polar chart report horizontal orientation and radial axes report
+ vertical orientation.
+ This function is a convenience function for converting the orientation of an \a axis to
+ corresponding polar orientation. If the \a axis is NULL or not added to a polar chart,
+ the return value is meaningless.
+*/
+QPolarChart::PolarOrientation QPolarChart::axisPolarOrientation(QAbstractAxis *axis)
+{
+ if (axis && axis->orientation() == Qt::Horizontal)
+ return PolarOrientationAngular;
+ else
+ return PolarOrientationRadial;
+}
+
+#include "moc_qpolarchart.cpp"
+
+QTCOMMERCIALCHART_END_NAMESPACE
diff --git a/src/qpolarchart.h b/src/qpolarchart.h
new file mode 100644
index 00000000..123eb578
--- /dev/null
+++ b/src/qpolarchart.h
@@ -0,0 +1,60 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 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$
+**
+****************************************************************************/
+
+#ifndef QPOLARCHART_H
+#define QPOLARCHART_H
+
+#include "qchart.h"
+
+QTCOMMERCIALCHART_BEGIN_NAMESPACE
+
+class QAbstractSeries;
+class QAbstractAxis;
+
+class QTCOMMERCIALCHART_EXPORT QPolarChart : public QChart
+{
+ Q_OBJECT
+ Q_ENUMS(PolarOrientation)
+ Q_FLAGS(PolarOrientations)
+
+public:
+ enum PolarOrientation {
+ PolarOrientationRadial = 0x1,
+ PolarOrientationAngular = 0x2
+ };
+ Q_DECLARE_FLAGS(PolarOrientations, PolarOrientation)
+
+public:
+ explicit QPolarChart(QGraphicsItem *parent = 0, Qt::WindowFlags wFlags = 0);
+ ~QPolarChart();
+
+ void addAxis(QAbstractAxis *axis, PolarOrientation polarOrientation);
+
+ QList<QAbstractAxis*> axes(PolarOrientations polarOrientation = PolarOrientations(PolarOrientationRadial | PolarOrientationAngular), QAbstractSeries *series = 0) const;
+
+ static PolarOrientation axisPolarOrientation(QAbstractAxis *axis);
+
+protected:
+ Q_DISABLE_COPY(QPolarChart)
+};
+
+QTCOMMERCIALCHART_END_NAMESPACE
+
+#endif // QCHART_H
diff --git a/src/scatterchart/scatterchartitem.cpp b/src/scatterchart/scatterchartitem.cpp
index 93761ed1..fecbeb1b 100644
--- a/src/scatterchart/scatterchartitem.cpp
+++ b/src/scatterchart/scatterchartitem.cpp
@@ -23,6 +23,7 @@
#include "qscatterseries_p.h"
#include "chartpresenter_p.h"
#include "abstractdomain_p.h"
+#include "qchart.h"
#include <QPainter>
#include <QGraphicsScene>
#include <QDebug>
@@ -30,7 +31,7 @@
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem* item)
+ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *item)
: XYChart(series,item),
m_series(series),
m_items(this),
@@ -93,12 +94,12 @@ void ScatterChartItem::deletePoints(int count)
void ScatterChartItem::markerSelected(QGraphicsItem *marker)
{
- emit XYChart::clicked(domain()->calculateDomainPoint(m_markerMap[marker]));
+ emit XYChart::clicked(m_markerMap[marker]);
}
void ScatterChartItem::markerHovered(QGraphicsItem *marker, bool state)
{
- emit XYChart::hovered(domain()->calculateDomainPoint(m_markerMap[marker]), state);
+ emit XYChart::hovered(m_markerMap[marker], state);
}
void ScatterChartItem::updateGeometry()
@@ -125,13 +126,16 @@ void ScatterChartItem::updateGeometry()
QRectF clipRect(QPointF(0,0),domain()->size());
+ QVector<bool> offGridStatus = offGridStatusVector();
+
for (int i = 0; i < points.size(); i++) {
QGraphicsItem *item = items.at(i);
const QPointF &point = points.at(i);
const QRectF &rect = item->boundingRect();
- m_markerMap[item] = point;
+ m_markerMap[item] = m_series->pointAt(i);
item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2);
- if (!m_visible || !clipRect.contains(point))
+
+ if (!m_visible || offGridStatus.at(i))
item->setVisible(false);
else
item->setVisible(true);
diff --git a/src/scatterchart/scatterchartitem_p.h b/src/scatterchart/scatterchartitem_p.h
index 6e8010bc..e00404a4 100644
--- a/src/scatterchart/scatterchartitem_p.h
+++ b/src/scatterchart/scatterchartitem_p.h
@@ -44,7 +44,7 @@ class ScatterChartItem : public XYChart
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
- explicit ScatterChartItem(QScatterSeries *series, QGraphicsItem* item = 0);
+ explicit ScatterChartItem(QScatterSeries *series, QGraphicsItem *item = 0);
public:
//from QGraphicsItem
diff --git a/src/splinechart/splinechartitem.cpp b/src/splinechart/splinechartitem.cpp
index 261a753f..4a46a724 100644
--- a/src/splinechart/splinechartitem.cpp
+++ b/src/splinechart/splinechartitem.cpp
@@ -22,13 +22,13 @@
#include "qsplineseries_p.h"
#include "chartpresenter_p.h"
#include "splineanimation_p.h"
-#include "abstractdomain_p.h"
+#include "polardomain_p.h"
#include <QPainter>
#include <QGraphicsSceneMouseEvent>
QTCOMMERCIALCHART_BEGIN_NAMESPACE
-SplineChartItem::SplineChartItem(QSplineSeries *series, QGraphicsItem* item)
+SplineChartItem::SplineChartItem(QSplineSeries *series, QGraphicsItem *item)
: XYChart(series,item),
m_series(series),
m_pointsVisible(false),
@@ -49,8 +49,7 @@ QRectF SplineChartItem::boundingRect() const
QPainterPath SplineChartItem::shape() const
{
- QPainterPathStroker stroker;
- return stroker.createStroke(m_path);
+ return m_fullPath;
}
void SplineChartItem::setAnimation(SplineAnimation *animation)
@@ -107,20 +106,179 @@ void SplineChartItem::updateGeometry()
Q_ASSERT(points.count() * 2 - 2 == controlPoints.count());
- QPainterPath splinePath(points.at(0));
+ QPainterPath splinePath;
+ QPainterPath fullPath;
+ // Use worst case scenario to determine required margin.
+ qreal margin = m_linePen.width() * 1.42;
+
+ if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
+ QPainterPath splinePathLeft;
+ QPainterPath splinePathRight;
+ QPainterPath *currentSegmentPath = 0;
+ QPainterPath *previousSegmentPath = 0;
+ qreal minX = domain()->minX();
+ qreal maxX = domain()->maxX();
+ qreal minY = domain()->minY();
+ QPointF currentSeriesPoint = m_series->pointAt(0);
+ QPointF currentGeometryPoint = points.at(0);
+ QPointF previousGeometryPoint = points.at(0);
+ bool pointOffGrid = false;
+ bool previousPointWasOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
+ m_visiblePoints.clear();
+ m_visiblePoints.reserve(points.size());
+
+ qreal domainRadius = domain()->size().height() / 2.0;
+ const QPointF centerPoint(domainRadius, domainRadius);
+
+ if (!previousPointWasOffGrid) {
+ fullPath.moveTo(points.at(0));
+ // Do not draw points for points below minimum Y.
+ if (m_pointsVisible && currentSeriesPoint.y() >= minY)
+ m_visiblePoints.append(currentGeometryPoint);
+ }
+
+ qreal leftMarginLine = centerPoint.x() - margin;
+ qreal rightMarginLine = centerPoint.x() + margin;
+ qreal horizontal = centerPoint.y();
+
+ for (int i = 1; i < points.size(); i++) {
+ // Interpolating spline fragments accurately is not trivial, and would anyway be ugly
+ // when thick pen is used, so we work around it by utilizing three separate
+ // paths for spline segments and clip those with custom regions at paint time.
+ // "Right" path contains segments that cross the axis line with visible point on the
+ // right side of the axis line, as well as segments that have one point within the margin
+ // on the right side of the axis line and another point on the right side of the chart.
+ // "Left" path contains points with similarly on the left side.
+ // "Full" path contains rest of the points.
+ // This doesn't yield perfect results always. E.g. when segment covers more than 90
+ // degrees and both of the points are within the margin, one in the top half and one in the
+ // bottom half of the chart, the bottom one gets clipped incorrectly.
+ // However, this should be rare occurrence in any sensible chart.
+ currentSeriesPoint = m_series->pointAt(i);
+ currentGeometryPoint = points.at(i);
+ pointOffGrid = (currentSeriesPoint.x() < minX || currentSeriesPoint.x() > maxX);
+
+ // Draw something unless both off-grid
+ if (!pointOffGrid || !previousPointWasOffGrid) {
+ bool dummyOk; // We know points are ok, but this is needed
+ qreal currentAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(currentSeriesPoint.x(), dummyOk);
+ qreal previousAngle = static_cast<PolarDomain *>(domain())->toAngularCoordinate(m_series->pointAt(i - 1).x(), dummyOk);
+
+ if ((qAbs(currentAngle - previousAngle) > 180.0)) {
+ // If the angle between two points is over 180 degrees (half X range),
+ // any direct segment between them becomes meaningless.
+ // In this case two line segments are drawn instead, from previous
+ // point to the center and from center to current point.
+ if ((previousAngle < 0.0 || (previousAngle <= 180.0 && previousGeometryPoint.x() < rightMarginLine))
+ && previousGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &splinePathRight;
+ } else if ((previousAngle > 360.0 || (previousAngle > 180.0 && previousGeometryPoint.x() > leftMarginLine))
+ && previousGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &splinePathLeft;
+ } else if (previousAngle > 0.0 && previousAngle < 360.0) {
+ currentSegmentPath = &splinePath;
+ } else {
+ currentSegmentPath = 0;
+ }
+
+ if (currentSegmentPath) {
+ if (previousSegmentPath != currentSegmentPath)
+ currentSegmentPath->moveTo(previousGeometryPoint);
+ if (!previousSegmentPath)
+ fullPath.moveTo(previousGeometryPoint);
+
+ currentSegmentPath->lineTo(centerPoint);
+ fullPath.lineTo(centerPoint);
+ }
+
+ previousSegmentPath = currentSegmentPath;
+
+ if ((currentAngle < 0.0 || (currentAngle <= 180.0 && currentGeometryPoint.x() < rightMarginLine))
+ && currentGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &splinePathRight;
+ } else if ((currentAngle > 360.0 || (currentAngle > 180.0 &&currentGeometryPoint.x() > leftMarginLine))
+ && currentGeometryPoint.y() < horizontal) {
+ currentSegmentPath = &splinePathLeft;
+ } else if (currentAngle > 0.0 && currentAngle < 360.0) {
+ currentSegmentPath = &splinePath;
+ } else {
+ currentSegmentPath = 0;
+ }
+
+ if (currentSegmentPath) {
+ if (previousSegmentPath != currentSegmentPath)
+ currentSegmentPath->moveTo(centerPoint);
+ if (!previousSegmentPath)
+ fullPath.moveTo(centerPoint);
+
+ currentSegmentPath->lineTo(currentGeometryPoint);
+ fullPath.lineTo(currentGeometryPoint);
+ }
+ } else {
+ QPointF cp1 = controlPoints[2 * (i - 1)];
+ QPointF cp2 = controlPoints[(2 * i) - 1];
+
+ if (previousAngle < 0.0 || currentAngle < 0.0
+ || ((previousAngle <= 180.0 && currentAngle <= 180.0)
+ && ((previousGeometryPoint.x() < rightMarginLine && previousGeometryPoint.y() < horizontal)
+ || (currentGeometryPoint.x() < rightMarginLine && currentGeometryPoint.y() < horizontal)))) {
+ currentSegmentPath = &splinePathRight;
+ } else if (previousAngle > 360.0 || currentAngle > 360.0
+ || ((previousAngle > 180.0 && currentAngle > 180.0)
+ && ((previousGeometryPoint.x() > leftMarginLine && previousGeometryPoint.y() < horizontal)
+ || (currentGeometryPoint.x() > leftMarginLine && currentGeometryPoint.y() < horizontal)))) {
+ currentSegmentPath = &splinePathLeft;
+ } else {
+ currentSegmentPath = &splinePath;
+ }
+
+ if (currentSegmentPath != previousSegmentPath)
+ currentSegmentPath->moveTo(previousGeometryPoint);
+ if (!previousSegmentPath)
+ fullPath.moveTo(previousGeometryPoint);
+
+ fullPath.cubicTo(cp1, cp2, currentGeometryPoint);
+ currentSegmentPath->cubicTo(cp1, cp2, currentGeometryPoint);
+ }
+ } else {
+ currentSegmentPath = 0;
+ }
+
+ previousPointWasOffGrid = pointOffGrid;
+ if (!pointOffGrid && m_pointsVisible && currentSeriesPoint.y() >= minY)
+ m_visiblePoints.append(currentGeometryPoint);
+ previousSegmentPath = currentSegmentPath;
+ previousGeometryPoint = currentGeometryPoint;
+ }
- for (int i = 0; i < points.size() - 1; i++) {
- const QPointF &point = points.at(i + 1);
- splinePath.cubicTo(controlPoints[2 * i], controlPoints[2 * i + 1], point);
+ m_pathPolarRight = splinePathRight;
+ m_pathPolarLeft = splinePathLeft;
+ // Note: This construction of m_fullpath is not perfect. The partial segments that are
+ // outside left/right clip regions at axis boundary still generate hover/click events,
+ // because shape doesn't get clipped. It doesn't seem possible to do sensibly.
+ } else { // not polar
+ splinePath.moveTo(points.at(0));
+ for (int i = 0; i < points.size() - 1; i++) {
+ const QPointF &point = points.at(i + 1);
+ splinePath.cubicTo(controlPoints[2 * i], controlPoints[2 * i + 1], point);
+ }
+ fullPath = splinePath;
}
+ m_path = splinePath;
+
+ QPainterPathStroker stroker;
+ // The full path is comprised of three separate paths.
+ // This is why we are prepared for the "worst case" scenario, i.e. use always MiterJoin and
+ // multiply line width with square root of two when defining shape and bounding rectangle.
+ stroker.setWidth(margin);
+ stroker.setJoinStyle(Qt::MiterJoin);
+ stroker.setCapStyle(Qt::SquareCap);
+ stroker.setMiterLimit(m_linePen.miterLimit());
prepareGeometryChange();
- // QPainterPathStroker stroker;
- // stroker.setWidth(m_linePen.width() / 2.0);
- // m_path = stroker.createStroke(splinePath);
- m_path = splinePath;
- m_rect = splinePath.boundingRect();
+ m_fullPath = stroker.createStroke(fullPath);
+ m_rect = m_fullPath.boundingRect();
}
/*!
@@ -240,16 +398,38 @@ void SplineChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *o
Q_UNUSED(widget)
Q_UNUSED(option)
+ QRectF clipRect = QRectF(QPointF(0, 0), domain()->size());
+
painter->save();
- painter->setClipRect(QRectF(QPointF(0,0),domain()->size()));
painter->setPen(m_linePen);
- // painter->setBrush(m_linePen.color());
+ painter->setBrush(Qt::NoBrush);
+
+ if (m_series->chart()->chartType() == QChart::ChartTypePolar) {
+ qreal halfWidth = domain()->size().width() / 2.0;
+ QRectF clipRectLeft = QRectF(0, 0, halfWidth, domain()->size().height());
+ QRectF clipRectRight = QRectF(halfWidth, 0, halfWidth, domain()->size().height());
+ QRegion fullPolarClipRegion(clipRect.toRect(), QRegion::Ellipse);
+ QRegion clipRegionLeft(fullPolarClipRegion.intersected(clipRectLeft.toRect()));
+ QRegion clipRegionRight(fullPolarClipRegion.intersected(clipRectRight.toRect()));
+ painter->setClipRegion(clipRegionLeft);
+ painter->drawPath(m_pathPolarLeft);
+ painter->setClipRegion(clipRegionRight);
+ painter->drawPath(m_pathPolarRight);
+ painter->setClipRegion(fullPolarClipRegion);
+ } else {
+ painter->setClipRect(clipRect);
+ }
painter->drawPath(m_path);
+
if (m_pointsVisible) {
painter->setPen(m_pointPen);
- painter->drawPoints(geometryPoints());
+ if (m_series->chart()->chartType() == QChart::ChartTypePolar)
+ painter->drawPoints(m_visiblePoints);
+ else
+ painter->drawPoints(geometryPoints());
}
+
painter->restore();
}
diff --git a/src/splinechart/splinechartitem_p.h b/src/splinechart/splinechartitem_p.h
index a15b6c6a..37e1b52d 100644
--- a/src/splinechart/splinechartitem_p.h
+++ b/src/splinechart/splinechartitem_p.h
@@ -42,7 +42,7 @@ class SplineChartItem : public XYChart
Q_OBJECT
Q_INTERFACES(QGraphicsItem)
public:
- SplineChartItem(QSplineSeries *series, QGraphicsItem* item = 0);
+ SplineChartItem(QSplineSeries *series, QGraphicsItem *item = 0);
//from QGraphicsItem
QRectF boundingRect() const;
@@ -70,11 +70,15 @@ protected:
private:
QSplineSeries *m_series;
QPainterPath m_path;
+ QPainterPath m_pathPolarRight;
+ QPainterPath m_pathPolarLeft;
+ QPainterPath m_fullPath;
QRectF m_rect;
QPen m_linePen;
QPen m_pointPen;
bool m_pointsVisible;
QVector<QPointF> m_controlPoints;
+ QVector<QPointF> m_visiblePoints;
SplineAnimation *m_animation;
friend class SplineAnimation;
diff --git a/src/src.pro b/src/src.pro
index bfb90ba0..a60a6cf2 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -39,8 +39,8 @@ SOURCES += \
$$PWD/chartelement.cpp \
$$PWD/chartitem.cpp \
$$PWD/scroller.cpp \
- $$PWD/chartlayout.cpp \
- $$PWD/charttitle.cpp
+ $$PWD/charttitle.cpp \
+ $$PWD/qpolarchart.cpp
PRIVATE_HEADERS += \
$$PWD/chartdataset_p.h \
$$PWD/chartitem_p.h \
@@ -53,7 +53,6 @@ PRIVATE_HEADERS += \
$$PWD/qchartview_p.h \
$$PWD/scroller_p.h \
$$PWD/qabstractseries_p.h \
- $$PWD/chartlayout_p.h \
$$PWD/charttitle_p.h \
$$PWD/charthelpers_p.h
PUBLIC_HEADERS += \
@@ -61,7 +60,8 @@ PUBLIC_HEADERS += \
$$PWD/qchartglobal.h \
$$PWD/qabstractseries.h \
$$PWD/qchartview.h \
- $$PWD/chartsnamespace.h
+ $$PWD/chartsnamespace.h \
+ $$PWD/qpolarchart.h
include(animations/animations.pri)
include(areachart/areachart.pri)
@@ -75,6 +75,7 @@ include(scatterchart/scatter.pri)
include(splinechart/splinechart.pri)
include(themes/themes.pri)
include(xychart/xychart.pri)
+include(layout/layout.pri)
HEADERS += $$PUBLIC_HEADERS
HEADERS += $$PRIVATE_HEADERS
diff --git a/src/xychart/qxyseries.cpp b/src/xychart/qxyseries.cpp
index 3d5f7eec..285c078d 100644
--- a/src/xychart/qxyseries.cpp
+++ b/src/xychart/qxyseries.cpp
@@ -69,6 +69,18 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
*/
/*!
+ \qmlproperty AbstractAxis XYSeries::axisAngular
+ The angular axis used for the series, drawn around the polar chart view.
+ \sa axisX
+*/
+
+/*!
+ \qmlproperty AbstractAxis XYSeries::axisRadial
+ The radial axis used for the series, drawn inside the polar chart view.
+ \sa axisY
+*/
+
+/*!
\property QXYSeries::pointsVisible
Controls if the data points are visible and should be drawn.
*/
@@ -354,6 +366,15 @@ QList<QPointF> QXYSeries::points() const
}
/*!
+ Returns point at \a index in internal points vector.
+*/
+const QPointF &QXYSeries::pointAt(int index) const
+{
+ Q_D(const QXYSeries);
+ return d->m_points.at(index);
+}
+
+/*!
Returns number of data points within series.
*/
int QXYSeries::count() const
diff --git a/src/xychart/qxyseries.h b/src/xychart/qxyseries.h
index d0e6bb48..8eff380e 100644
--- a/src/xychart/qxyseries.h
+++ b/src/xychart/qxyseries.h
@@ -56,6 +56,7 @@ public:
int count() const;
QList<QPointF> points() const;
+ const QPointF &pointAt(int index) const;
QXYSeries &operator << (const QPointF &point);
QXYSeries &operator << (const QList<QPointF> &points);
diff --git a/src/xychart/xychart.cpp b/src/xychart/xychart.cpp
index ecadf676..3d442c5a 100644
--- a/src/xychart/xychart.cpp
+++ b/src/xychart/xychart.cpp
@@ -24,6 +24,7 @@
#include "chartpresenter_p.h"
#include "abstractdomain_p.h"
#include "qxymodelmapper.h"
+#include "qabstractaxis_p.h"
#include <QPainter>
#include <QAbstractItemModel>
@@ -32,7 +33,7 @@ QTCOMMERCIALCHART_BEGIN_NAMESPACE
//TODO: optimize : remove points which are not visible
-XYChart::XYChart(QXYSeries *series,QGraphicsItem* item):
+XYChart::XYChart(QXYSeries *series, QGraphicsItem *item):
ChartItem(series->d_func(),item),
m_series(series),
m_animation(0),
@@ -46,7 +47,7 @@ XYChart::XYChart(QXYSeries *series,QGraphicsItem* item):
QObject::connect(this, SIGNAL(hovered(QPointF,bool)), series, SIGNAL(hovered(QPointF,bool)));
}
-void XYChart::setGeometryPoints(const QVector<QPointF>& points)
+void XYChart::setGeometryPoints(const QVector<QPointF> &points)
{
m_points = points;
}
@@ -61,6 +62,32 @@ void XYChart::setDirty(bool dirty)
m_dirty = dirty;
}
+// Returns a vector with same size as geometryPoints vector, indicating
+// the off grid status of points.
+QVector<bool> XYChart::offGridStatusVector()
+{
+ qreal minX = domain()->minX();
+ qreal maxX = domain()->maxX();
+ qreal minY = domain()->minY();
+ qreal maxY = domain()->maxY();
+
+ QVector<bool> returnVector;
+ returnVector.resize(m_points.size());
+
+ for (int i = 0; i < m_points.size(); i++) {
+ const QPointF &seriesPoint = m_series->pointAt(i);
+ if (seriesPoint.x() < minX
+ || seriesPoint.x() > maxX
+ || seriesPoint.y() < minY
+ || seriesPoint.y() > maxY) {
+ returnVector[i] = true;
+ } else {
+ returnVector[i] = false;
+ }
+ }
+ return returnVector;
+}
+
void XYChart::updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
{
diff --git a/src/xychart/xychart_p.h b/src/xychart/xychart_p.h
index cfdb296b..49c57bc3 100644
--- a/src/xychart/xychart_p.h
+++ b/src/xychart/xychart_p.h
@@ -45,10 +45,10 @@ class XYChart : public ChartItem
{
Q_OBJECT
public:
- explicit XYChart(QXYSeries *series,QGraphicsItem* item = 0);
+ explicit XYChart(QXYSeries *series,QGraphicsItem *item = 0);
~XYChart() {}
- void setGeometryPoints(const QVector<QPointF>& points);
+ void setGeometryPoints(const QVector<QPointF> &points);
QVector<QPointF> geometryPoints() const { return m_points; }
void setAnimation(XYAnimation *animation);
@@ -58,6 +58,9 @@ public:
bool isDirty() const { return m_dirty; }
void setDirty(bool dirty);
+ void getSeriesRanges(qreal &minX, qreal &maxX, qreal &minY, qreal &maxY);
+ QVector<bool> offGridStatusVector();
+
public Q_SLOTS:
void handlePointAdded(int index);
void handlePointRemoved(int index);