1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtCharts/QScatterSeries> |
5 | #include <private/qscatterseries_p.h> |
6 | #include <private/scatterchartitem_p.h> |
7 | #include <private/chartdataset_p.h> |
8 | #include <private/charttheme_p.h> |
9 | #include <private/scatteranimation_p.h> |
10 | #include <private/qchart_p.h> |
11 | |
12 | /*! |
13 | \class QScatterSeries |
14 | \inmodule QtCharts |
15 | \brief The QScatterSeries class presents data in scatter charts. |
16 | |
17 | The scatter data is displayed as a collection of points on the chart. For |
18 | each point, two values are specified that determine its position on the |
19 | horizontal axis and the vertical axis. |
20 | |
21 | \image examples_scatterchart.png |
22 | |
23 | The following code snippet illustrates how to create a basic scatter chart: |
24 | \code |
25 | QScatterSeries* series = new QScatterSeries(); |
26 | series->append(0, 6); |
27 | series->append(2, 4); |
28 | ... |
29 | chart->addSeries(series); |
30 | \endcode |
31 | |
32 | For more information, see \l{Charts with Widgets Gallery} and |
33 | \l {Creating Scatter Charts}. |
34 | */ |
35 | /*! |
36 | \qmltype ScatterSeries |
37 | \instantiates QScatterSeries |
38 | \inqmlmodule QtCharts |
39 | |
40 | \inherits XYSeries |
41 | |
42 | \brief The ScatterSeries type presents data in scatter charts. |
43 | |
44 | The scatter data is displayed as a collection of points on the chart. For |
45 | each point, two values are specified that determine its position on the |
46 | horizontal axis and the vertical axis. |
47 | |
48 | \image examples_qmlchart5.png |
49 | |
50 | The following QML code shows how to create a chart with two simple scatter |
51 | series: |
52 | \snippet qmlchartsgallery/qml/ScatterSeries.qml 1 |
53 | |
54 | For more information, see \l{Charts with QML Gallery}. |
55 | */ |
56 | |
57 | /*! |
58 | \enum QScatterSeries::MarkerShape |
59 | |
60 | This enum value describes the shape used when rendering marker items. |
61 | |
62 | \value MarkerShapeCircle |
63 | The marker is a circle. This is the default value. |
64 | \value MarkerShapeRectangle |
65 | The marker is a rectangle. |
66 | \value MarkerShapeRotatedRectangle |
67 | The marker is a rotated rectangle. |
68 | \value MarkerShapeTriangle |
69 | The marker is a triangle. |
70 | \value MarkerShapeStar |
71 | The marker is a star. |
72 | \value MarkerShapePentagon |
73 | The marker is a pentagon. |
74 | */ |
75 | |
76 | /*! |
77 | \property QScatterSeries::brush |
78 | \brief The brush used to draw the scatter series markers. |
79 | |
80 | The brush can be an image that can be created using QPainterPath, |
81 | for example. |
82 | */ |
83 | |
84 | /*! |
85 | \qmlproperty brush ScatterSeries::brush |
86 | The brush used to draw the scatter series markers. |
87 | */ |
88 | |
89 | /*! |
90 | \property QScatterSeries::color |
91 | \brief The color used to fill the series markers. |
92 | |
93 | This is a convenience property for modifying the color of the brush. |
94 | \sa QScatterSeries::brush() |
95 | */ |
96 | |
97 | /*! |
98 | \property QScatterSeries::borderColor |
99 | \brief The color used to draw the marker borders. |
100 | |
101 | This is a convenience property for modifying the color of the pen. |
102 | \sa QScatterSeries::pen() |
103 | */ |
104 | |
105 | /*! |
106 | \qmlproperty int ScatterSeries::count |
107 | The number of data points in the series. |
108 | */ |
109 | |
110 | /*! |
111 | \qmlproperty color ScatterSeries::borderColor |
112 | The color used to draw the marker borders. |
113 | */ |
114 | |
115 | /*! |
116 | \qmlproperty real ScatterSeries::borderWidth |
117 | The width of the border line. By default, the width is 2.0. |
118 | */ |
119 | |
120 | /*! |
121 | \property QScatterSeries::markerShape |
122 | \brief The shape of the marker used to render the points in the series. |
123 | |
124 | The default shape is MarkerShapeCircle. |
125 | |
126 | \sa MarkerShape |
127 | */ |
128 | /*! |
129 | \qmlproperty enumeration ScatterSeries::markerShape |
130 | |
131 | The shape used when rendering marker items: |
132 | |
133 | \value ScatterSeries.MarkerShapeCircle |
134 | The marker is a circle. This is the default value. |
135 | \value ScatterSeries.MarkerShapeRectangle |
136 | The marker is a rectangle. |
137 | */ |
138 | |
139 | /*! |
140 | \property QScatterSeries::markerSize |
141 | \brief The size of the marker used to render the points in the series. |
142 | |
143 | \sa QXYSeries::setMarkerSize |
144 | */ |
145 | /*! |
146 | \qmlproperty real ScatterSeries::markerSize |
147 | The size of the marker used to render the points in the series. |
148 | */ |
149 | |
150 | /*! |
151 | \qmlproperty string ScatterSeries::brushFilename |
152 | The name of the file used as a brush for the series. |
153 | */ |
154 | |
155 | /*! |
156 | \fn void QScatterSeries::colorChanged(QColor color) |
157 | This signal is emitted when the fill (brush) color changes to \a color. |
158 | */ |
159 | |
160 | /*! |
161 | \fn void QScatterSeries::borderColorChanged(QColor color) |
162 | This signal is emitted when the line (pen) color changes to \a color. |
163 | */ |
164 | |
165 | /*! |
166 | \fn void QScatterSeries::markerShapeChanged(MarkerShape shape) |
167 | This signal is emitted when the marker shape changes to \a shape. |
168 | */ |
169 | |
170 | /*! |
171 | \fn void QScatterSeries::markerSizeChanged(qreal size) |
172 | This signal is emitted when the marker size changes to \a size. |
173 | */ |
174 | |
175 | QT_BEGIN_NAMESPACE |
176 | |
177 | /*! |
178 | Constructs a series object that is a child of \a parent. |
179 | */ |
180 | QScatterSeries::QScatterSeries(QObject *parent) |
181 | : QXYSeries(*new QScatterSeriesPrivate(this), parent) |
182 | { |
183 | setPointsVisible(true); |
184 | |
185 | // Emit QScatterSeries' markerSizeChanged signal as it's not the same as |
186 | // QXYSeries' markerSizeChanged |
187 | connect(sender: this, signal: &QXYSeries::markerSizeChanged, context: this, slot: &QScatterSeries::markerSizeChanged); |
188 | } |
189 | |
190 | /*! |
191 | Deletes the scatter series. |
192 | |
193 | \note Adding the series to QChart transfers the ownership to the chart. |
194 | */ |
195 | QScatterSeries::~QScatterSeries() |
196 | { |
197 | Q_D(QScatterSeries); |
198 | if (d->m_chart) |
199 | d->m_chart->removeSeries(series: this); |
200 | } |
201 | |
202 | /*! |
203 | \reimp |
204 | */ |
205 | QAbstractSeries::SeriesType QScatterSeries::type() const |
206 | { |
207 | return QAbstractSeries::SeriesTypeScatter; |
208 | } |
209 | |
210 | /*! |
211 | \reimp |
212 | */ |
213 | void QScatterSeries::setPen(const QPen &pen) |
214 | { |
215 | Q_D(QXYSeries); |
216 | if (d->m_pen != pen) { |
217 | bool emitColorChanged = d->m_pen.color() != pen.color(); |
218 | d->m_pen = pen; |
219 | emit d->seriesUpdated(); |
220 | if (emitColorChanged) |
221 | emit borderColorChanged(color: pen.color()); |
222 | } |
223 | } |
224 | |
225 | /*! |
226 | \reimp |
227 | */ |
228 | void QScatterSeries::setBrush(const QBrush &brush) |
229 | { |
230 | Q_D(QScatterSeries); |
231 | if (d->m_brush != brush) { |
232 | bool emitColorChanged = d->m_brush.color() != brush.color(); |
233 | d->m_brush = brush; |
234 | emit d->seriesUpdated(); |
235 | if (emitColorChanged) |
236 | emit colorChanged(color: brush.color()); |
237 | } |
238 | } |
239 | |
240 | QBrush QScatterSeries::brush() const |
241 | { |
242 | Q_D(const QScatterSeries); |
243 | if (d->m_brush == QChartPrivate::defaultBrush()) |
244 | return QBrush(); |
245 | else |
246 | return d->m_brush; |
247 | } |
248 | |
249 | void QScatterSeries::setColor(const QColor &color) |
250 | { |
251 | QBrush b = brush(); |
252 | if (b == QChartPrivate::defaultBrush()) |
253 | b = QBrush(); |
254 | if (b == QBrush()) |
255 | b.setStyle(Qt::SolidPattern); |
256 | b.setColor(color); |
257 | setBrush(b); |
258 | } |
259 | |
260 | QColor QScatterSeries::color() const |
261 | { |
262 | return brush().color(); |
263 | } |
264 | |
265 | void QScatterSeries::setBorderColor(const QColor &color) |
266 | { |
267 | QPen p = pen(); |
268 | if (p == QChartPrivate::defaultPen()) |
269 | p = QPen(); |
270 | p.setColor(color); |
271 | setPen(p); |
272 | } |
273 | |
274 | QColor QScatterSeries::borderColor() const |
275 | { |
276 | return pen().color(); |
277 | } |
278 | |
279 | QScatterSeries::MarkerShape QScatterSeries::markerShape() const |
280 | { |
281 | Q_D(const QScatterSeries); |
282 | return d->m_shape; |
283 | } |
284 | |
285 | void QScatterSeries::setMarkerShape(MarkerShape shape) |
286 | { |
287 | Q_D(QScatterSeries); |
288 | if (d->m_shape != shape) { |
289 | d->m_shape = shape; |
290 | emit d->seriesUpdated(); |
291 | emit markerShapeChanged(shape); |
292 | } |
293 | } |
294 | |
295 | qreal QScatterSeries::markerSize() const |
296 | { |
297 | // markerSize has moved to QXYSeries, but this method needs to remain for API compatibility. |
298 | return QXYSeries::markerSize(); |
299 | } |
300 | void QScatterSeries::setMarkerSize(qreal size) |
301 | { |
302 | // markerSize has moved to QXYSeries, but this method needs to remain for API compatibility. |
303 | QXYSeries::setMarkerSize(size); |
304 | } |
305 | |
306 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// |
307 | |
308 | QScatterSeriesPrivate::QScatterSeriesPrivate(QScatterSeries *q) |
309 | : QXYSeriesPrivate(q), |
310 | m_shape(QScatterSeries::MarkerShapeCircle) |
311 | { |
312 | } |
313 | |
314 | void QScatterSeriesPrivate::initializeGraphics(QGraphicsItem* parent) |
315 | { |
316 | Q_Q(QScatterSeries); |
317 | ScatterChartItem *scatter = new ScatterChartItem(q,parent); |
318 | m_item.reset(p: scatter); |
319 | QAbstractSeriesPrivate::initializeGraphics(parent); |
320 | } |
321 | |
322 | void QScatterSeriesPrivate::initializeTheme(int index, ChartTheme* theme, bool forced) |
323 | { |
324 | Q_Q(QScatterSeries); |
325 | const QList<QColor> colors = theme->seriesColors(); |
326 | const QList<QGradient> gradients = theme->seriesGradients(); |
327 | |
328 | if (forced || QChartPrivate::defaultPen() == m_pen) { |
329 | QPen pen; |
330 | pen.setColor(ChartThemeManager::colorAt(gradient: gradients.at(i: index % gradients.size()), pos: 0.0)); |
331 | pen.setWidthF(2); |
332 | q->setPen(pen); |
333 | } |
334 | |
335 | if (forced || QChartPrivate::defaultBrush() == m_brush) { |
336 | QBrush brush(colors.at(i: index % colors.size())); |
337 | q->setBrush(brush); |
338 | } |
339 | |
340 | if (forced || QChartPrivate::defaultPen().color() == m_pointLabelsColor) { |
341 | QColor color = theme->labelBrush().color(); |
342 | q->setPointLabelsColor(color); |
343 | } |
344 | } |
345 | |
346 | void QScatterSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration, |
347 | QEasingCurve &curve) |
348 | { |
349 | ScatterChartItem *item = static_cast<ScatterChartItem *>(m_item.get()); |
350 | Q_ASSERT(item); |
351 | |
352 | if (item->animation()) |
353 | item->animation()->stopAndDestroyLater(); |
354 | |
355 | if (options.testFlag(flag: QChart::SeriesAnimations)) |
356 | item->setAnimation(new ScatterAnimation(item, duration, curve)); |
357 | else |
358 | item->setAnimation(0); |
359 | |
360 | QAbstractSeriesPrivate::initializeAnimations(options, duration, curve); |
361 | } |
362 | |
363 | QT_END_NAMESPACE |
364 | |
365 | #include "moc_qscatterseries.cpp" |
366 | |