##// END OF EJS Templates
Further animation fixes...
Miikka Heikkinen -
r2492:5a6d23b6b72f
parent child
Show More
@@ -0,0 +1,50
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
14 **
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
18 **
19 ****************************************************************************/
20
21 #include "scatteranimation_p.h"
22 #include "scatterchartitem_p.h"
23 #include <QDebug>
24
25 QTCOMMERCIALCHART_BEGIN_NAMESPACE
26
27 ScatterAnimation::ScatterAnimation(ScatterChartItem *item)
28 : XYAnimation(item)
29 {
30 }
31
32 ScatterAnimation::~ScatterAnimation()
33 {
34 }
35
36 void ScatterAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
37 {
38 XYAnimation::updateState(newState, oldState);
39
40 if (oldState == QAbstractAnimation::Running && newState == QAbstractAnimation::Stopped
41 && animationType() == RemovePointAnimation) {
42 // Removing a point from scatter chart will keep extra marker item after animation stops.
43 // Also, if the removed point was not the last one in series, points after the removed one
44 // will report wrong coordinates when clicked. To fix these issues, update geometry after
45 // point removal animation has finished.
46 chartItem()->updateGeometry();
47 }
48 }
49
50 QTCOMMERCIALCHART_END_NAMESPACE
@@ -0,0 +1,50
1 /****************************************************************************
2 **
3 ** Copyright (C) 2013 Digia Plc
4 ** All rights reserved.
5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 **
7 ** This file is part of the Qt Commercial Charts Add-on.
8 **
9 ** $QT_BEGIN_LICENSE$
10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 ** accordance with the Qt Commercial License Agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.
14 **
15 ** If you have questions regarding the use of this file, please use
16 ** contact form at http://qt.digia.com
17 ** $QT_END_LICENSE$
18 **
19 ****************************************************************************/
20
21 // W A R N I N G
22 // -------------
23 //
24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 // implementation detail. This header file may change from version to
26 // version without notice, or even be removed.
27 //
28 // We mean it.
29
30 #ifndef SCATTERANIMATION_P_H
31 #define SCATTERANIMATION_P_H
32 #include "xyanimation_p.h"
33
34 QTCOMMERCIALCHART_BEGIN_NAMESPACE
35
36 class ScatterChartItem;
37
38 class ScatterAnimation : public XYAnimation
39 {
40 public:
41 ScatterAnimation(ScatterChartItem *item);
42 ~ScatterAnimation();
43
44 protected:
45 void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState);
46 };
47
48 QTCOMMERCIALCHART_END_NAMESPACE
49
50 #endif
@@ -1,19 +1,21
1 1 INCLUDEPATH += $$PWD
2 2 DEPENDPATH += $$PWD
3 3
4 4 SOURCES += \
5 5 $$PWD/axisanimation.cpp \
6 6 $$PWD/xyanimation.cpp \
7 7 $$PWD/pieanimation.cpp \
8 8 $$PWD/piesliceanimation.cpp \
9 9 $$PWD/splineanimation.cpp \
10 $$PWD/baranimation.cpp
10 $$PWD/baranimation.cpp \
11 $$PWD/scatteranimation.cpp
11 12
12 13 PRIVATE_HEADERS += \
13 14 $$PWD/axisanimation_p.h \
14 15 $$PWD/chartanimation_p.h \
15 16 $$PWD/xyanimation_p.h \
16 17 $$PWD/pieanimation_p.h \
17 18 $$PWD/piesliceanimation_p.h \
18 19 $$PWD/splineanimation_p.h \
19 $$PWD/baranimation_p.h
20 $$PWD/baranimation_p.h \
21 $$PWD/scatteranimation_p.h
@@ -1,204 +1,210
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "splineanimation_p.h"
22 22 #include "splinechartitem_p.h"
23 23 #include <QDebug>
24 24
25 25 Q_DECLARE_METATYPE(QVector<QPointF>)
26 26 Q_DECLARE_METATYPE(SplineVector)
27 27
28 28 QTCOMMERCIALCHART_BEGIN_NAMESPACE
29 29
30 30 SplineAnimation::SplineAnimation(SplineChartItem *item)
31 31 : XYAnimation(item),
32 32 m_item(item),
33 33 m_valid(false)
34 34 {
35 35 }
36 36
37 37 SplineAnimation::~SplineAnimation()
38 38 {
39 39 }
40 40
41 41 void SplineAnimation::setup(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, QVector<QPointF> &oldControlPoints, QVector<QPointF> &newControlPoints, int index)
42 42 {
43 43 if (newPoints.count() * 2 - 2 != newControlPoints.count() || newControlPoints.count() < 2) {
44 44 m_valid = false;
45 45 m_dirty = false;
46 46 m_item->setGeometryPoints(newPoints);
47 47 m_item->setControlGeometryPoints(newControlPoints);
48 48 m_item->setDirty(false);
49 49 m_item->updateGeometry();
50 50 return;
51 51 }
52 52
53 53 m_type = NewAnimation;
54 54
55 55 if (state() != QAbstractAnimation::Stopped) {
56 56 stop();
57 57 m_dirty = false;
58 58 }
59 59
60 60 if (!m_dirty) {
61 61 m_dirty = true;
62 62 m_oldSpline.first = oldPoints;
63 63 m_oldSpline.second = oldControlPoints;
64 64 }
65 65
66 66 m_newSpline.first = newPoints;
67 67 m_newSpline.second = newControlPoints;
68 68
69 69
70 70 int x = m_oldSpline.first.count();
71 71 int y = m_newSpline.first.count();
72 72
73 73 if (x - y == 1 && index >= 0 && y > 0) {
74 74 //remove point
75 75 if (index > 0) {
76 76 m_newSpline.first.insert(index, newPoints[index - 1]);
77 77 m_newSpline.second.insert((index - 1) * 2, newPoints[index - 1]);
78 78 m_newSpline.second.insert((index - 1) * 2 + 1, newPoints[index - 1]);
79 79 } else {
80 m_newSpline.first.insert(index, newPoints[index]);
81 m_newSpline.second.insert(index * 2, newPoints[index]);
82 m_newSpline.second.insert(index * 2 + 1, newPoints[index]);
80 m_newSpline.first.insert(0, newPoints[index]);
81 m_newSpline.second.insert(0, newPoints[index]);
82 m_newSpline.second.insert(1, newPoints[index]);
83 83 }
84 84 m_index = index;
85 85 m_type = RemovePointAnimation;
86 86 }
87 87
88 88 if (x - y == -1 && index >= 0) {
89 89 //add point
90 90 if (index > 0) {
91 91 m_oldSpline.first.insert(index, newPoints[index - 1]);
92 92 m_oldSpline.second.insert((index - 1) * 2, newPoints[index - 1]);
93 93 m_oldSpline.second.insert((index - 1) * 2 + 1, newPoints[index - 1]);
94 94 } else {
95 m_oldSpline.first.insert(index, newPoints[index]);
96 m_oldSpline.second.insert((index - 1) * 2, newPoints[index]);
97 m_oldSpline.second.insert((index - 1) * 2 + 1, newPoints[index]);
95 m_oldSpline.first.insert(0, newPoints[index]);
96 m_oldSpline.second.insert(0, newPoints[index]);
97 m_oldSpline.second.insert(1, newPoints[index]);
98 98 }
99 99 m_index = index;
100 100 m_type = AddPointAnimation;
101 101 }
102 102
103 103 x = m_oldSpline.first.count();
104 104 y = m_newSpline.first.count();
105 105
106 106 if (x != y) {
107 107 m_type = NewAnimation;
108 108 } else if (m_type == NewAnimation) {
109 109 m_type = ReplacePointAnimation;
110 110 }
111 111
112 112
113 113 setKeyValueAt(0.0, qVariantFromValue(m_oldSpline));
114 114 setKeyValueAt(1.0, qVariantFromValue(m_newSpline));
115 115
116 116 m_valid = true;
117 117
118 118 }
119 119
120 120 QVariant SplineAnimation::interpolated(const QVariant &start, const QVariant &end, qreal progress) const
121 121 {
122 122
123 123 SplineVector startPair = qvariant_cast< SplineVector >(start);
124 124 SplineVector endPair = qvariant_cast< SplineVector >(end);
125 125 SplineVector result;
126 126
127 127 switch (animationType()) {
128 128 case RemovePointAnimation:
129 129 case AddPointAnimation:
130 130 case ReplacePointAnimation: {
131 131 if (startPair.first.count() != endPair.first.count())
132 132 break;
133 133 Q_ASSERT(startPair.first.count() * 2 - 2 == startPair.second.count());
134 134 Q_ASSERT(endPair.first.count() * 2 - 2 == endPair.second.count());
135 135 for (int i = 0; i < endPair.first.count(); i++) {
136 136 qreal x = startPair.first[i].x() + ((endPair.first[i].x() - startPair.first[i].x()) * progress);
137 137 qreal y = startPair.first[i].y() + ((endPair.first[i].y() - startPair.first[i].y()) * progress);
138 138 result.first << QPointF(x, y);
139 139 if (i + 1 >= endPair.first.count())
140 140 continue;
141 141 x = startPair.second[i * 2].x() + ((endPair.second[i * 2].x() - startPair.second[i * 2].x()) * progress);
142 142 y = startPair.second[i * 2].y() + ((endPair.second[i * 2].y() - startPair.second[i * 2].y()) * progress);
143 143 result.second << QPointF(x, y);
144 144 x = startPair.second[i * 2 + 1].x() + ((endPair.second[i * 2 + 1].x() - startPair.second[i * 2 + 1].x()) * progress);
145 145 y = startPair.second[i * 2 + 1].y() + ((endPair.second[i * 2 + 1].y() - startPair.second[i * 2 + 1].y()) * progress);
146 146 result.second << QPointF(x, y);
147 147 }
148 148 }
149 149 break;
150 150 case NewAnimation: {
151 151 Q_ASSERT(endPair.first.count() * 2 - 2 == endPair.second.count());
152 152 int count = endPair.first.count() * qBound(qreal(0), progress, qreal(1));
153 153 for (int i = 0; i < count; i++) {
154 154 result.first << endPair.first[i];
155 155 if (i + 1 == count)
156 156 break;
157 157 result.second << endPair.second[2 * i];
158 158 result.second << endPair.second[2 * i + 1];
159 159 }
160 160 }
161 161 break;
162 162 default:
163 163 qWarning() << "Unknown type of animation";
164 164 break;
165 165 }
166 166
167 167 return qVariantFromValue(result);
168 168 }
169 169
170 170 void SplineAnimation::updateCurrentValue(const QVariant &value)
171 171 {
172 172 if (state() != QAbstractAnimation::Stopped && m_valid) { //workaround
173 173 QPair<QVector<QPointF >, QVector<QPointF > > pair = qvariant_cast< QPair< QVector<QPointF>, QVector<QPointF> > >(value);
174 174 m_item->setGeometryPoints(pair.first);
175 175 m_item->setControlGeometryPoints(pair.second);
176 176 m_item->updateGeometry();
177 177 m_item->setDirty(true);
178 178 m_dirty = false;
179 179 }
180 180 }
181 181
182 182 void SplineAnimation::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState)
183 183 {
184 184 XYAnimation::updateState(newState, oldState);
185 185
186 186 if (oldState == QAbstractAnimation::Running && newState == QAbstractAnimation::Stopped) {
187 187 if (m_item->isDirty() && m_type == RemovePointAnimation) {
188 188 if (!m_newSpline.first.isEmpty()) {
189 m_newSpline.first.remove(m_index);
190 m_newSpline.second.remove((m_index - 1) * 2);
191 m_newSpline.second.remove((m_index - 1) * 2);
189 if (m_index) {
190 m_newSpline.first.remove(m_index);
191 m_newSpline.second.remove((m_index - 1) * 2);
192 m_newSpline.second.remove((m_index - 1) * 2);
193 } else {
194 m_newSpline.first.remove(0);
195 m_newSpline.second.remove(0);
196 m_newSpline.second.remove(0);
197 }
192 198 }
193 199 m_item->setGeometryPoints(m_newSpline.first);
194 200 m_item->setControlGeometryPoints(m_newSpline.second);
195 201 }
196 202 }
197 203
198 204 if (oldState == QAbstractAnimation::Stopped && newState == QAbstractAnimation::Running) {
199 205 if (!m_valid)
200 206 stop();
201 207 }
202 208 }
203 209
204 210 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,66 +1,67
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef XYANIMATION_P_H
31 31 #define XYANIMATION_P_H
32 32
33 33 #include "chartanimation_p.h"
34 34 #include <QPointF>
35 35
36 36 QTCOMMERCIALCHART_BEGIN_NAMESPACE
37 37
38 38 class XYChart;
39 39
40 40 class XYAnimation : public ChartAnimation
41 41 {
42 42 protected:
43 43 enum Animation { AddPointAnimation, RemovePointAnimation, ReplacePointAnimation, NewAnimation };
44 44 public:
45 45 XYAnimation(XYChart *item);
46 46 ~XYAnimation();
47 47 void setup(const QVector<QPointF> &oldPoints, const QVector<QPointF> &newPoints, int index = -1);
48 48 Animation animationType() const { return m_type; };
49 49
50 50 protected:
51 51 QVariant interpolated(const QVariant &start, const QVariant &end, qreal progress) const;
52 52 void updateCurrentValue(const QVariant &value);
53 53 void updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState);
54 XYChart *chartItem() { return m_item; }
54 55 protected:
55 56 Animation m_type;
56 57 bool m_dirty;
57 58 int m_index;
58 59 private:
59 60 XYChart *m_item;
60 61 QVector<QPointF> m_oldPoints;
61 62 QVector<QPointF> m_newPoints;
62 63 };
63 64
64 65 QTCOMMERCIALCHART_END_NAMESPACE
65 66
66 67 #endif
@@ -1,287 +1,301
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "qscatterseries.h"
22 22 #include "qscatterseries_p.h"
23 23 #include "scatterchartitem_p.h"
24 24 #include "chartdataset_p.h"
25 25 #include "charttheme_p.h"
26 #include "scatteranimation_p.h"
26 27
27 28 /*!
28 29 \class QScatterSeries
29 30 \brief The QScatterSeries class is used for making scatter charts.
30 31
31 32 \mainclass
32 33
33 34 The scatter data is displayed as a collection of points on the chart. Each point determines the position on the horizontal axis
34 35 and the vertical axis.
35 36
36 37 \image examples_scatterchart.png
37 38
38 39 Creating basic scatter chart is simple:
39 40 \code
40 41 QScatterSeries* series = new QScatterSeries();
41 42 series->append(0, 6);
42 43 series->append(2, 4);
43 44 ...
44 45 chart->addSeries(series);
45 46 \endcode
46 47 */
47 48 /*!
48 49 \qmlclass ScatterSeries QScatterSeries
49 50 \inherits XYSeries
50 51
51 52 The following QML shows how to create a chart with two simple scatter series:
52 53 \snippet ../demos/qmlchart/qml/qmlchart/View5.qml 1
53 54
54 55 \beginfloatleft
55 56 \image demos_qmlchart5.png
56 57 \endfloat
57 58 \clearfloat
58 59 */
59 60
60 61 /*!
61 62 \enum QScatterSeries::MarkerShape
62 63
63 64 This enum describes the shape used when rendering marker items.
64 65
65 66 \value MarkerShapeCircle
66 67 \value MarkerShapeRectangle
67 68 */
68 69
69 70 /*!
70 71 \property QScatterSeries::color
71 72 Fill (brush) color of the series. This is a convenience property for modifying the color of brush.
72 73 \sa QScatterSeries::brush()
73 74 */
74 75
75 76 /*!
76 77 \property QScatterSeries::borderColor
77 78 Line (pen) color of the series. This is a convenience property for modifying the color of pen.
78 79 \sa QScatterSeries::pen()
79 80 */
80 81 /*!
81 82 \qmlproperty color ScatterSeries::borderColor
82 83 Border (pen) color of the series.
83 84 */
84 85
85 86 /*!
86 87 \qmlproperty real ScatterSeries::borderWidth
87 88 The width of the border line. By default the width is 2.0.
88 89 */
89 90
90 91 /*!
91 92 \property QScatterSeries::markerShape
92 93 Defines the shape of the marker used to draw the points in the series. The default shape is MarkerShapeCircle.
93 94 */
94 95 /*!
95 96 \qmlproperty MarkerShape ScatterSeries::markerShape
96 97 Defines the shape of the marker used to draw the points in the series. One of ScatterSeries
97 98 ScatterSeries.MarkerShapeCircle or ScatterSeries.MarkerShapeRectangle.
98 99 The default shape is ScatterSeries.MarkerShapeCircle.
99 100 */
100 101
101 102 /*!
102 103 \property QScatterSeries::markerSize
103 104 Defines the size of the marker used to draw the points in the series. The default size is 15.0.
104 105 */
105 106 /*!
106 107 \qmlproperty real ScatterSeries::markerSize
107 108 Defines the size of the marker used to draw the points in the series. The default size is 15.0.
108 109 */
109 110
110 111 /*!
111 112 \fn void QScatterSeries::colorChanged(QColor color)
112 113 Signal is emitted when the fill (brush) color has changed to \a color.
113 114 */
114 115
115 116 /*!
116 117 \fn void QScatterSeries::borderColorChanged(QColor color)
117 118 Signal is emitted when the line (pen) color has changed to \a color.
118 119 */
119 120 /*!
120 121 \qmlsignal ScatterSeries::borderColorChanged(color color)
121 122 Signal is emitted when the line (pen) color has changed to \a color.
122 123 */
123 124
124 125 /*!
125 126 \fn QChartSeriesType QScatterSeries::type() const
126 127 Returns QChartSeries::SeriesTypeScatter.
127 128 \sa QAbstractSeries, SeriesType
128 129 */
129 130
130 131 QTCOMMERCIALCHART_BEGIN_NAMESPACE
131 132
132 133 /*!
133 134 Constructs a series object which is a child of \a parent.
134 135 */
135 136 QScatterSeries::QScatterSeries(QObject *parent)
136 137 : QXYSeries(*new QScatterSeriesPrivate(this), parent)
137 138 {
138 139 }
139 140
140 141 /*!
141 142 Destroys the object. Note that adding series to QChart transfers the ownership to the chart.
142 143 */
143 144 QScatterSeries::~QScatterSeries()
144 145 {
145 146 Q_D(QScatterSeries);
146 147 if (d->m_chart)
147 148 d->m_chart->removeSeries(this);
148 149 }
149 150
150 151 QAbstractSeries::SeriesType QScatterSeries::type() const
151 152 {
152 153 return QAbstractSeries::SeriesTypeScatter;
153 154 }
154 155
155 156 /*!
156 157 Sets \a pen used for drawing points' border on the chart. If the pen is not defined, the
157 158 pen from chart theme is used.
158 159 \sa QChart::setTheme()
159 160 */
160 161 void QScatterSeries::setPen(const QPen &pen)
161 162 {
162 163 Q_D(QXYSeries);
163 164 if (d->m_pen != pen) {
164 165 bool emitColorChanged = d->m_pen.color() != pen.color();
165 166 d->m_pen = pen;
166 167 emit d->updated();
167 168 if (emitColorChanged)
168 169 emit borderColorChanged(pen.color());
169 170 }
170 171 }
171 172
172 173 /*!
173 174 Sets \a brush used for drawing points on the chart. If the brush is not defined, brush
174 175 from chart theme setting is used.
175 176 \sa QChart::setTheme()
176 177 */
177 178 void QScatterSeries::setBrush(const QBrush &brush)
178 179 {
179 180 Q_D(QScatterSeries);
180 181 if (d->m_brush != brush) {
181 182 bool emitColorChanged = d->m_brush.color() != brush.color();
182 183 d->m_brush = brush;
183 184 emit d->updated();
184 185 if (emitColorChanged)
185 186 emit colorChanged(brush.color());
186 187 }
187 188 }
188 189
189 190 void QScatterSeries::setColor(const QColor &color)
190 191 {
191 192 QBrush b = brush();
192 193 if (b == QBrush())
193 194 b.setStyle(Qt::SolidPattern);
194 195 b.setColor(color);
195 196 setBrush(b);
196 197 }
197 198
198 199 QColor QScatterSeries::color() const
199 200 {
200 201 return brush().color();
201 202 }
202 203
203 204 void QScatterSeries::setBorderColor(const QColor &color)
204 205 {
205 206 QPen p = pen();
206 207 if (p.color() != color) {
207 208 p.setColor(color);
208 209 setPen(p);
209 210 }
210 211 }
211 212
212 213 QColor QScatterSeries::borderColor() const
213 214 {
214 215 return pen().color();
215 216 }
216 217
217 218 QScatterSeries::MarkerShape QScatterSeries::markerShape() const
218 219 {
219 220 Q_D(const QScatterSeries);
220 221 return d->m_shape;
221 222 }
222 223
223 224 void QScatterSeries::setMarkerShape(MarkerShape shape)
224 225 {
225 226 Q_D(QScatterSeries);
226 227 if (d->m_shape != shape) {
227 228 d->m_shape = shape;
228 229 emit d->updated();
229 230 }
230 231 }
231 232
232 233 qreal QScatterSeries::markerSize() const
233 234 {
234 235 Q_D(const QScatterSeries);
235 236 return d->m_size;
236 237 }
237 238
238 239 void QScatterSeries::setMarkerSize(qreal size)
239 240 {
240 241 Q_D(QScatterSeries);
241 242
242 243 if (!qFuzzyCompare(d->m_size, size)) {
243 244 d->m_size = size;
244 245 emit d->updated();
245 246 }
246 247 }
247 248
248 249 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
249 250
250 251 QScatterSeriesPrivate::QScatterSeriesPrivate(QScatterSeries *q)
251 252 : QXYSeriesPrivate(q),
252 253 m_shape(QScatterSeries::MarkerShapeCircle),
253 254 m_size(15.0)
254 255 {
255 256 }
256 257
257 258 void QScatterSeriesPrivate::initializeGraphics(QGraphicsItem* parent)
258 259 {
259 260 Q_Q(QScatterSeries);
260 261 ScatterChartItem *scatter = new ScatterChartItem(q,parent);
261 262 m_item.reset(scatter);
262 263 QAbstractSeriesPrivate::initializeGraphics(parent);
263 264 }
264 265
265 266 void QScatterSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced)
266 267 {
267 268 Q_Q(QScatterSeries);
268 269 QPen pen;
269 270 QBrush brush;
270 271 const QList<QColor> colors = theme->seriesColors();
271 272 const QList<QGradient> gradients = theme->seriesGradients();
272 273
273 274 if (forced || pen == m_pen) {
274 275 pen.setColor(ChartThemeManager::colorAt(gradients.at(index % gradients.size()), 0.0));
275 276 pen.setWidthF(2);
276 277 q->setPen(pen);
277 278 }
278 279
279 280 if (forced || brush == m_brush) {
280 281 QBrush brush(colors.at(index % colors.size()));
281 282 q->setBrush(brush);
282 283 }
283 284 }
284 285
286 void QScatterSeriesPrivate::initializeAnimations(QChart::AnimationOptions options)
287 {
288 ScatterChartItem *item = static_cast<ScatterChartItem *>(m_item.data());
289 Q_ASSERT(item);
290
291 if (options.testFlag(QChart::SeriesAnimations))
292 item->setAnimation(new ScatterAnimation(item));
293 else
294 item->setAnimation(0);
295
296 QAbstractSeriesPrivate::initializeAnimations(options);
297 }
298
285 299 #include "moc_qscatterseries.cpp"
286 300
287 301 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,52 +1,53
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 // W A R N I N G
22 22 // -------------
23 23 //
24 24 // This file is not part of the QtCommercial Chart API. It exists purely as an
25 25 // implementation detail. This header file may change from version to
26 26 // version without notice, or even be removed.
27 27 //
28 28 // We mean it.
29 29
30 30 #ifndef QSCATTERSERIES_P_H
31 31 #define QSCATTERSERIES_P_H
32 32
33 33 #include "qxyseries_p.h"
34 34
35 35 QTCOMMERCIALCHART_BEGIN_NAMESPACE
36 36
37 37 class QScatterSeriesPrivate: public QXYSeriesPrivate
38 38 {
39 39 public:
40 40 QScatterSeriesPrivate(QScatterSeries *q);
41 41 void initializeGraphics(QGraphicsItem* parent);
42 42 void initializeTheme(int index, ChartTheme* theme, bool forced = false);
43 void initializeAnimations(QtCommercialChart::QChart::AnimationOptions options);
43 44
44 45 private:
45 46 QScatterSeries::MarkerShape m_shape;
46 47 qreal m_size;
47 48 Q_DECLARE_PUBLIC(QScatterSeries)
48 49 };
49 50
50 51 QTCOMMERCIALCHART_END_NAMESPACE
51 52
52 53 #endif
@@ -1,207 +1,207
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "scatterchartitem_p.h"
22 22 #include "qscatterseries.h"
23 23 #include "qscatterseries_p.h"
24 24 #include "chartpresenter_p.h"
25 25 #include "abstractdomain_p.h"
26 26 #include "qchart.h"
27 27 #include <QPainter>
28 28 #include <QGraphicsScene>
29 29 #include <QDebug>
30 30 #include <QGraphicsSceneMouseEvent>
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 ScatterChartItem::ScatterChartItem(QScatterSeries *series, QGraphicsItem *item)
35 35 : XYChart(series,item),
36 36 m_series(series),
37 37 m_items(this),
38 38 m_visible(true),
39 39 m_shape(QScatterSeries::MarkerShapeRectangle),
40 40 m_size(15)
41 41 {
42 42 QObject::connect(m_series->d_func(), SIGNAL(updated()), this, SLOT(handleUpdated()));
43 43 QObject::connect(m_series, SIGNAL(visibleChanged()), this, SLOT(handleUpdated()));
44 44 QObject::connect(m_series, SIGNAL(opacityChanged()), this, SLOT(handleUpdated()));
45 45
46 46 setZValue(ChartPresenter::ScatterSeriesZValue);
47 47 setFlags(QGraphicsItem::ItemClipsChildrenToShape);
48 48
49 49 handleUpdated();
50 50
51 51 m_items.setHandlesChildEvents(false);
52 52 }
53 53
54 54 QRectF ScatterChartItem::boundingRect() const
55 55 {
56 56 return m_rect;
57 57 }
58 58
59 59 void ScatterChartItem::createPoints(int count)
60 60 {
61 61 for (int i = 0; i < count; ++i) {
62 62
63 63 QGraphicsItem *item = 0;
64 64
65 65 switch (m_shape) {
66 66 case QScatterSeries::MarkerShapeCircle: {
67 67 item = new CircleMarker(0, 0, m_size, m_size, this);
68 68 const QRectF &rect = item->boundingRect();
69 69 item->setPos(-rect.width() / 2, -rect.height() / 2);
70 70 break;
71 71 }
72 72 case QScatterSeries::MarkerShapeRectangle:
73 73 item = new RectangleMarker(0, 0, m_size, m_size, this);
74 74 item->setPos(-m_size / 2, -m_size / 2);
75 75 break;
76 76 default:
77 77 qWarning() << "Unsupported marker type";
78 78 break;
79 79 }
80 80 m_items.addToGroup(item);
81 81 }
82 82 }
83 83
84 84 void ScatterChartItem::deletePoints(int count)
85 85 {
86 86 QList<QGraphicsItem *> items = m_items.childItems();
87 87
88 88 for (int i = 0; i < count; ++i) {
89 89 QGraphicsItem *item = items.takeLast();
90 90 m_markerMap.remove(item);
91 91 delete(item);
92 92 }
93 93 }
94 94
95 95 void ScatterChartItem::markerSelected(QGraphicsItem *marker)
96 96 {
97 97 emit XYChart::clicked(m_markerMap[marker]);
98 98 }
99 99
100 100 void ScatterChartItem::markerHovered(QGraphicsItem *marker, bool state)
101 101 {
102 102 emit XYChart::hovered(m_markerMap[marker], state);
103 103 }
104 104
105 105 void ScatterChartItem::updateGeometry()
106 106 {
107 107
108 108 const QVector<QPointF>& points = geometryPoints();
109 109
110 110 if (points.size() == 0) {
111 111 deletePoints(m_items.childItems().count());
112 112 return;
113 113 }
114 114
115 115 int diff = m_items.childItems().size() - points.size();
116 116
117 117 if (diff > 0)
118 118 deletePoints(diff);
119 119 else if (diff < 0)
120 120 createPoints(-diff);
121 121
122 122 if (diff != 0)
123 123 handleUpdated();
124 124
125 125 QList<QGraphicsItem *> items = m_items.childItems();
126 126
127 127 QRectF clipRect(QPointF(0,0),domain()->size());
128 128
129 129 QVector<bool> offGridStatus = offGridStatusVector();
130 130 const int seriesLastIndex = m_series->count() - 1;
131 131
132 132 for (int i = 0; i < points.size(); i++) {
133 133 QGraphicsItem *item = items.at(i);
134 134 const QPointF &point = points.at(i);
135 135 const QRectF &rect = item->boundingRect();
136 // During remove/append animation series may have different number of points,
136 // During remove animation series may have different number of points,
137 137 // so ensure we don't go over the index. Animation handling itself ensures that
138 138 // if there is actually no points in the series, then it won't generate a fake point,
139 139 // so we can be assured there is always at least one point in m_series here.
140 140 // Note that marker map values can be technically incorrect during the animation,
141 141 // if it was caused by an insert, but this shouldn't be a problem as the points are
142 // fake anyway.
142 // fake anyway. After remove animation stops, geometry is updated to correct one.
143 143 m_markerMap[item] = m_series->at(qMin(seriesLastIndex, i));
144 144 item->setPos(point.x() - rect.width() / 2, point.y() - rect.height() / 2);
145 145
146 146 if (!m_visible || offGridStatus.at(i))
147 147 item->setVisible(false);
148 148 else
149 149 item->setVisible(true);
150 150 }
151 151
152 152 prepareGeometryChange();
153 153 m_rect = clipRect;
154 154 }
155 155
156 156 void ScatterChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
157 157 {
158 158 Q_UNUSED(painter)
159 159 Q_UNUSED(option)
160 160 Q_UNUSED(widget)
161 161 }
162 162
163 163 void ScatterChartItem::setPen(const QPen &pen)
164 164 {
165 165 foreach (QGraphicsItem *item , m_items.childItems())
166 166 static_cast<QAbstractGraphicsShapeItem*>(item)->setPen(pen);
167 167 }
168 168
169 169 void ScatterChartItem::setBrush(const QBrush &brush)
170 170 {
171 171 foreach (QGraphicsItem *item , m_items.childItems())
172 172 static_cast<QAbstractGraphicsShapeItem*>(item)->setBrush(brush);
173 173 }
174 174
175 175 void ScatterChartItem::handleUpdated()
176 176 {
177 177 int count = m_items.childItems().count();
178 178
179 179 if (count == 0)
180 180 return;
181 181
182 182 bool recreate = m_visible != m_series->isVisible()
183 183 || m_size != m_series->markerSize()
184 184 || m_shape != m_series->markerShape();
185 185
186 186 m_visible = m_series->isVisible();
187 187 m_size = m_series->markerSize();
188 188 m_shape = m_series->markerShape();
189 189 setOpacity(m_series->opacity());
190 190
191 191 if (recreate) {
192 192 // TODO: optimize handleUpdate to recreate points only in case shape changed
193 193 deletePoints(count);
194 194 createPoints(count);
195 195
196 196 // Updating geometry is now safe, because it won't call handleUpdated unless it creates/deletes points
197 197 updateGeometry();
198 198 }
199 199
200 200 setPen(m_series->pen());
201 201 setBrush(m_series->brush());
202 202 update();
203 203 }
204 204
205 205 #include "moc_scatterchartitem_p.cpp"
206 206
207 207 QTCOMMERCIALCHART_END_NAMESPACE
@@ -1,191 +1,191
1 1 /****************************************************************************
2 2 **
3 3 ** Copyright (C) 2013 Digia Plc
4 4 ** All rights reserved.
5 5 ** For any questions to Digia, please use contact form at http://qt.digia.com
6 6 **
7 7 ** This file is part of the Qt Commercial Charts Add-on.
8 8 **
9 9 ** $QT_BEGIN_LICENSE$
10 10 ** Licensees holding valid Qt Commercial licenses may use this file in
11 11 ** accordance with the Qt Commercial License Agreement provided with the
12 12 ** Software or, alternatively, in accordance with the terms contained in
13 13 ** a written agreement between you and Digia.
14 14 **
15 15 ** If you have questions regarding the use of this file, please use
16 16 ** contact form at http://qt.digia.com
17 17 ** $QT_END_LICENSE$
18 18 **
19 19 ****************************************************************************/
20 20
21 21 #include "xychart_p.h"
22 22 #include "qxyseries.h"
23 23 #include "qxyseries_p.h"
24 24 #include "chartpresenter_p.h"
25 25 #include "abstractdomain_p.h"
26 26 #include "qxymodelmapper.h"
27 27 #include "qabstractaxis_p.h"
28 28 #include <QPainter>
29 29 #include <QAbstractItemModel>
30 30
31 31
32 32 QTCOMMERCIALCHART_BEGIN_NAMESPACE
33 33
34 34 //TODO: optimize : remove points which are not visible
35 35
36 36 XYChart::XYChart(QXYSeries *series, QGraphicsItem *item):
37 37 ChartItem(series->d_func(),item),
38 38 m_series(series),
39 39 m_animation(0),
40 40 m_dirty(true)
41 41 {
42 42 QObject::connect(series, SIGNAL(pointReplaced(int)), this, SLOT(handlePointReplaced(int)));
43 43 QObject::connect(series, SIGNAL(pointsReplaced()), this, SLOT(handlePointsReplaced()));
44 44 QObject::connect(series, SIGNAL(pointAdded(int)), this, SLOT(handlePointAdded(int)));
45 45 QObject::connect(series, SIGNAL(pointRemoved(int)), this, SLOT(handlePointRemoved(int)));
46 46 QObject::connect(this, SIGNAL(clicked(QPointF)), series, SIGNAL(clicked(QPointF)));
47 47 QObject::connect(this, SIGNAL(hovered(QPointF,bool)), series, SIGNAL(hovered(QPointF,bool)));
48 48 }
49 49
50 50 void XYChart::setGeometryPoints(const QVector<QPointF> &points)
51 51 {
52 52 m_points = points;
53 53 }
54 54
55 55 void XYChart::setAnimation(XYAnimation *animation)
56 56 {
57 57 m_animation = animation;
58 58 }
59 59
60 60 void XYChart::setDirty(bool dirty)
61 61 {
62 62 m_dirty = dirty;
63 63 }
64 64
65 65 // Returns a vector with same size as geometryPoints vector, indicating
66 66 // the off grid status of points.
67 67 QVector<bool> XYChart::offGridStatusVector()
68 68 {
69 69 qreal minX = domain()->minX();
70 70 qreal maxX = domain()->maxX();
71 71 qreal minY = domain()->minY();
72 72 qreal maxY = domain()->maxY();
73 73
74 74 QVector<bool> returnVector;
75 75 returnVector.resize(m_points.size());
76 // During remove/append animation series may have different number of points,
76 // During remove animation series may have different number of points,
77 77 // so ensure we don't go over the index. No need to check for zero points, this
78 78 // will not be called in such a situation.
79 79 const int seriesLastIndex = m_series->count() - 1;
80 80
81 81 for (int i = 0; i < m_points.size(); i++) {
82 82 const QPointF &seriesPoint = m_series->at(qMin(seriesLastIndex, i));
83 83 if (seriesPoint.x() < minX
84 84 || seriesPoint.x() > maxX
85 85 || seriesPoint.y() < minY
86 86 || seriesPoint.y() > maxY) {
87 87 returnVector[i] = true;
88 88 } else {
89 89 returnVector[i] = false;
90 90 }
91 91 }
92 92 return returnVector;
93 93 }
94 94
95 95 void XYChart::updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
96 96 {
97 97
98 98 if (m_animation) {
99 99 m_animation->setup(oldPoints, newPoints, index);
100 100 m_points = newPoints;
101 101 setDirty(false);
102 102 presenter()->startAnimation(m_animation);
103 103 } else {
104 104 m_points = newPoints;
105 105 updateGeometry();
106 106 }
107 107 }
108 108
109 109 //handlers
110 110
111 111 void XYChart::handlePointAdded(int index)
112 112 {
113 113 Q_ASSERT(index < m_series->count());
114 114 Q_ASSERT(index >= 0);
115 115
116 116 QVector<QPointF> points;
117 117
118 118 if (m_dirty || m_points.isEmpty()) {
119 119 points = domain()->calculateGeometryPoints(m_series->points());
120 120 } else {
121 121 points = m_points;
122 122 QPointF point = domain()->calculateGeometryPoint(m_series->points()[index], m_validData);
123 123 if (!m_validData)
124 124 m_points.clear();
125 125 else
126 126 points.insert(index, point);
127 127 }
128 128
129 129 updateChart(m_points, points, index);
130 130 }
131 131
132 132 void XYChart::handlePointRemoved(int index)
133 133 {
134 134 Q_ASSERT(index <= m_series->count());
135 135 Q_ASSERT(index >= 0);
136 136
137 137 QVector<QPointF> points;
138 138
139 139 if (m_dirty || m_points.isEmpty()) {
140 140 points = domain()->calculateGeometryPoints(m_series->points());
141 141 } else {
142 142 points = m_points;
143 143 points.remove(index);
144 144 }
145 145
146 146 updateChart(m_points, points, index);
147 147 }
148 148
149 149 void XYChart::handlePointReplaced(int index)
150 150 {
151 151 Q_ASSERT(index < m_series->count());
152 152 Q_ASSERT(index >= 0);
153 153
154 154 QVector<QPointF> points;
155 155
156 156 if (m_dirty || m_points.isEmpty()) {
157 157 points = domain()->calculateGeometryPoints(m_series->points());
158 158 } else {
159 159 QPointF point = domain()->calculateGeometryPoint(m_series->points()[index], m_validData);
160 160 if (!m_validData)
161 161 m_points.clear();
162 162 points = m_points;
163 163 if (m_validData)
164 164 points.replace(index, point);
165 165 }
166 166
167 167 updateChart(m_points, points, index);
168 168 }
169 169
170 170 void XYChart::handlePointsReplaced()
171 171 {
172 172 // All the points were replaced -> recalculate
173 173 QVector<QPointF> points = domain()->calculateGeometryPoints(m_series->points());
174 174 updateChart(m_points, points, -1);
175 175 }
176 176
177 177 void XYChart::handleDomainUpdated()
178 178 {
179 179 if (isEmpty()) return;
180 180 QVector<QPointF> points = domain()->calculateGeometryPoints(m_series->points());
181 181 updateChart(m_points, points);
182 182 }
183 183
184 184 bool XYChart::isEmpty()
185 185 {
186 186 return domain()->isEmpty() || m_series->points().isEmpty();
187 187 }
188 188
189 189 #include "moc_xychart_p.cpp"
190 190
191 191 QTCOMMERCIALCHART_END_NAMESPACE
General Comments 0
You need to be logged in to leave comments. Login now