1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt Charts module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 or (at your option) any later version
20** approved by the KDE Free Qt Foundation. The licenses are as published by
21** the Free Software Foundation and appearing in the file LICENSE.GPL3
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <private/xychart_p.h>
31#include <QtCharts/QXYSeries>
32#include <private/qxyseries_p.h>
33#include <private/chartpresenter_p.h>
34#include <private/abstractdomain_p.h>
35#include <private/chartdataset_p.h>
36#include <private/glxyseriesdata_p.h>
37#include <QtCharts/QXYModelMapper>
38#include <private/qabstractaxis_p.h>
39#include <QtGui/QPainter>
40#include <QtCore/QAbstractItemModel>
41
42
43QT_CHARTS_BEGIN_NAMESPACE
44
45XYChart::XYChart(QXYSeries *series, QGraphicsItem *item):
46 ChartItem(series->d_func(),item),
47 m_series(series),
48 m_animation(0),
49 m_dirty(true)
50{
51 QObject::connect(sender: series, SIGNAL(pointReplaced(int)), receiver: this, SLOT(handlePointReplaced(int)));
52 QObject::connect(sender: series, SIGNAL(pointsReplaced()), receiver: this, SLOT(handlePointsReplaced()));
53 QObject::connect(sender: series, SIGNAL(pointAdded(int)), receiver: this, SLOT(handlePointAdded(int)));
54 QObject::connect(sender: series, SIGNAL(pointRemoved(int)), receiver: this, SLOT(handlePointRemoved(int)));
55 QObject::connect(sender: series, SIGNAL(pointsRemoved(int, int)), receiver: this, SLOT(handlePointsRemoved(int, int)));
56 QObject::connect(sender: this, SIGNAL(clicked(QPointF)), receiver: series, SIGNAL(clicked(QPointF)));
57 QObject::connect(sender: this, SIGNAL(hovered(QPointF,bool)), receiver: series, SIGNAL(hovered(QPointF,bool)));
58 QObject::connect(sender: this, SIGNAL(pressed(QPointF)), receiver: series, SIGNAL(pressed(QPointF)));
59 QObject::connect(sender: this, SIGNAL(released(QPointF)), receiver: series, SIGNAL(released(QPointF)));
60 QObject::connect(sender: this, SIGNAL(doubleClicked(QPointF)), receiver: series, SIGNAL(doubleClicked(QPointF)));
61 QObject::connect(sender: series, signal: &QAbstractSeries::useOpenGLChanged,
62 receiver: this, slot: &XYChart::handleDomainUpdated);
63}
64
65void XYChart::setGeometryPoints(const QVector<QPointF> &points)
66{
67 m_points = points;
68}
69
70void XYChart::setAnimation(XYAnimation *animation)
71{
72 m_animation = animation;
73}
74
75void XYChart::setDirty(bool dirty)
76{
77 m_dirty = dirty;
78}
79
80// Returns a vector with same size as geometryPoints vector, indicating
81// the off grid status of points.
82QVector<bool> XYChart::offGridStatusVector()
83{
84 qreal minX = domain()->minX();
85 qreal maxX = domain()->maxX();
86 qreal minY = domain()->minY();
87 qreal maxY = domain()->maxY();
88
89 QVector<bool> returnVector;
90 returnVector.resize(size: m_points.size());
91 // During remove animation series may have different number of points,
92 // so ensure we don't go over the index. No need to check for zero points, this
93 // will not be called in such a situation.
94 const int seriesLastIndex = m_series->count() - 1;
95
96 for (int i = 0; i < m_points.size(); i++) {
97 const QPointF &seriesPoint = m_series->at(index: qMin(a: seriesLastIndex, b: i));
98 if (seriesPoint.x() < minX
99 || seriesPoint.x() > maxX
100 || seriesPoint.y() < minY
101 || seriesPoint.y() > maxY) {
102 returnVector[i] = true;
103 } else {
104 returnVector[i] = false;
105 }
106 }
107 return returnVector;
108}
109
110void XYChart::updateChart(QVector<QPointF> &oldPoints, QVector<QPointF> &newPoints, int index)
111{
112
113 if (m_animation) {
114 m_animation->setup(oldPoints, newPoints, index);
115 m_points = newPoints;
116 setDirty(false);
117 presenter()->startAnimation(animation: m_animation);
118 } else {
119 m_points = newPoints;
120 updateGeometry();
121 }
122}
123
124void XYChart::updateGlChart()
125{
126 dataSet()->glXYSeriesDataManager()->setPoints(series: m_series, domain: domain());
127 presenter()->updateGLWidget();
128 updateGeometry();
129}
130
131// Doesn't update gl geometry, but refreshes the chart
132void XYChart::refreshGlChart()
133{
134 if (presenter())
135 presenter()->updateGLWidget();
136}
137
138//handlers
139
140void XYChart::handlePointAdded(int index)
141{
142 Q_ASSERT(index < m_series->count());
143 Q_ASSERT(index >= 0);
144
145 if (m_series->useOpenGL()) {
146 updateGlChart();
147 } else {
148 QVector<QPointF> points;
149 if (m_dirty || m_points.isEmpty()) {
150 points = domain()->calculateGeometryPoints(vector: m_series->pointsVector());
151 } else {
152 points = m_points;
153 QPointF point = domain()->calculateGeometryPoint(point: m_series->pointsVector().at(i: index),
154 ok&: m_validData);
155 if (!m_validData)
156 m_points.clear();
157 else
158 points.insert(i: index, t: point);
159 }
160 updateChart(oldPoints&: m_points, newPoints&: points, index);
161 }
162}
163
164void XYChart::handlePointRemoved(int index)
165{
166 Q_ASSERT(index <= m_series->count());
167 Q_ASSERT(index >= 0);
168
169 if (m_series->useOpenGL()) {
170 updateGlChart();
171 } else {
172 QVector<QPointF> points;
173 if (m_dirty || m_points.isEmpty()) {
174 points = domain()->calculateGeometryPoints(vector: m_series->pointsVector());
175 } else {
176 points = m_points;
177 points.remove(i: index);
178 }
179 updateChart(oldPoints&: m_points, newPoints&: points, index);
180 }
181}
182
183void XYChart::handlePointsRemoved(int index, int count)
184{
185 Q_ASSERT(index <= m_series->count());
186 Q_ASSERT(index >= 0);
187
188 if (m_series->useOpenGL()) {
189 updateGlChart();
190 } else {
191 QVector<QPointF> points;
192 if (m_dirty || m_points.isEmpty()) {
193 points = domain()->calculateGeometryPoints(vector: m_series->pointsVector());
194 } else {
195 points = m_points;
196 points.remove(i: index, n: count);
197 }
198 updateChart(oldPoints&: m_points, newPoints&: points, index);
199 }
200}
201
202void XYChart::handlePointReplaced(int index)
203{
204 Q_ASSERT(index < m_series->count());
205 Q_ASSERT(index >= 0);
206
207 if (m_series->useOpenGL()) {
208 updateGlChart();
209 } else {
210 QVector<QPointF> points;
211 if (m_dirty || m_points.isEmpty()) {
212 points = domain()->calculateGeometryPoints(vector: m_series->pointsVector());
213 } else {
214 QPointF point = domain()->calculateGeometryPoint(point: m_series->pointsVector().at(i: index),
215 ok&: m_validData);
216 if (!m_validData)
217 m_points.clear();
218 points = m_points;
219 if (m_validData)
220 points.replace(i: index, t: point);
221 }
222 updateChart(oldPoints&: m_points, newPoints&: points, index);
223 }
224}
225
226void XYChart::handlePointsReplaced()
227{
228 if (m_series->useOpenGL()) {
229 updateGlChart();
230 } else {
231 // All the points were replaced -> recalculate
232 QVector<QPointF> points = domain()->calculateGeometryPoints(vector: m_series->pointsVector());
233 updateChart(oldPoints&: m_points, newPoints&: points, index: -1);
234 }
235}
236
237void XYChart::handleDomainUpdated()
238{
239 if (m_series->useOpenGL()) {
240 updateGlChart();
241 } else {
242 if (isEmpty()) return;
243 QVector<QPointF> points = domain()->calculateGeometryPoints(vector: m_series->pointsVector());
244 updateChart(oldPoints&: m_points, newPoints&: points);
245 }
246}
247
248bool XYChart::isEmpty()
249{
250 return domain()->isEmpty() || m_series->points().isEmpty();
251}
252
253QT_CHARTS_END_NAMESPACE
254
255#include "moc_xychart_p.cpp"
256

source code of qtcharts/src/charts/xychart/xychart.cpp