1 | // Copyright (C) 2021 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include <QtCharts/QAbstractSeries> |
5 | #include <private/qabstractseries_p.h> |
6 | #include <private/chartdataset_p.h> |
7 | #include <QtCharts/QChart> |
8 | #include <private/qchart_p.h> |
9 | #include <private/chartitem_p.h> |
10 | #include <private/xydomain_p.h> |
11 | #include <private/xlogydomain_p.h> |
12 | #include <private/logxydomain_p.h> |
13 | #include <private/logxlogydomain_p.h> |
14 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | /*! |
18 | \class QAbstractSeries |
19 | \inmodule QtCharts |
20 | \brief The QAbstractSeries class is a base class for all Qt Chart series. |
21 | |
22 | Usually, the series type specific inherited classes are used instead of the base class. |
23 | |
24 | \sa QXYSeries, QLineSeries, QSplineSeries, QScatterSeries, QAreaSeries, QAbstractBarSeries |
25 | \sa QBarSeries, QStackedBarSeries, QPercentBarSeries, QHorizontalBarSeries |
26 | \sa QHorizontalStackedBarSeries, QHorizontalPercentBarSeries, QPieSeries |
27 | */ |
28 | /*! |
29 | \qmltype AbstractSeries |
30 | \instantiates QAbstractSeries |
31 | \inqmlmodule QtCharts |
32 | |
33 | \brief Base type for all Qt Chart series types. |
34 | |
35 | This type cannot be instantiated directly. Instead, one of the following derived types |
36 | should be used to create a series: LineSeries, AreaSeries, BarSeries, StackedBarSeries, |
37 | PercentBarSeries, HorizontalBarSeries, HorizontalStackedBarSeries, HorizontalPercentBarSeries, |
38 | PieSeries, ScatterSeries, SplineSeries, BoxPlotSeries, or CandlestickSeries. |
39 | */ |
40 | |
41 | /*! |
42 | \enum QAbstractSeries::SeriesType |
43 | |
44 | This enum describes the type of the series. |
45 | |
46 | \value SeriesTypeLine A line chart. |
47 | \value SeriesTypeArea An area chart. |
48 | \value SeriesTypeBar A vertical bar chart. |
49 | \value SeriesTypeStackedBar A vertical stacked bar chart. |
50 | \value SeriesTypePercentBar A vertical percent bar chart. |
51 | \value SeriesTypePie A pie chart. |
52 | \value SeriesTypeScatter A scatter chart. |
53 | \value SeriesTypeSpline A spline chart. |
54 | \value SeriesTypeHorizontalBar A horizontal bar chart. |
55 | \value SeriesTypeHorizontalStackedBar A horizontal stacked bar chart. |
56 | \value SeriesTypeHorizontalPercentBar A horizontal percent bar chart. |
57 | \value SeriesTypeBoxPlot A box plot chart. |
58 | \value SeriesTypeCandlestick A candlestick chart. |
59 | */ |
60 | |
61 | /*! |
62 | \property QAbstractSeries::type |
63 | \brief The type of the series. |
64 | */ |
65 | /*! |
66 | \qmlproperty enumeration AbstractSeries::type |
67 | |
68 | The type of the series. |
69 | |
70 | \value AbstractSeries.SeriesTypeLine A line chart. |
71 | \value AbstractSeries.SeriesTypeArea An area chart. |
72 | \value AbstractSeries.SeriesTypeBar A vertical bar chart. |
73 | \value AbstractSeries.SeriesTypeStackedBar A vertical stacked bar chart. |
74 | \value AbstractSeries.SeriesTypePercentBar A vertical percent bar chart. |
75 | \value AbstractSeries.SeriesTypePie A pie chart. |
76 | \value AbstractSeries.SeriesTypeScatter A scatter chart. |
77 | \value AbstractSeries.SeriesTypeSpline A spline chart. |
78 | \value AbstractSeries.SeriesTypeHorizontalBar A horizontal bar chart. |
79 | \value AbstractSeries.SeriesTypeHorizontalStackedBar A horizontal stacked bar chart. |
80 | \value AbstractSeries.SeriesTypeHorizontalPercentBar A horizontal percent bar chart. |
81 | \value AbstractSeries.SeriesTypeBoxPlot A box plot chart. |
82 | \value AbstractSeries.SeriesTypeCandlestick A candlestick chart. |
83 | */ |
84 | |
85 | /*! |
86 | \property QAbstractSeries::name |
87 | \brief The name of the series. |
88 | |
89 | The name is displayed in the legend for the series and it supports HTML formatting. |
90 | */ |
91 | /*! |
92 | \qmlproperty string AbstractSeries::name |
93 | The name of the series. It is displayed in the legend for the series and it |
94 | supports HTML formatting. |
95 | */ |
96 | |
97 | /*! |
98 | \fn void QAbstractSeries::nameChanged() |
99 | This signal is emitted when the series name changes. |
100 | */ |
101 | |
102 | /*! |
103 | \property QAbstractSeries::visible |
104 | \brief whether the series is visible or not. |
105 | |
106 | By default, \c true. |
107 | */ |
108 | /*! |
109 | \qmlproperty bool AbstractSeries::visible |
110 | Visibility of the series. By default, \c true. |
111 | */ |
112 | |
113 | /*! |
114 | \fn void QAbstractSeries::visibleChanged() |
115 | This signal is emitted when the series visibility changes. |
116 | */ |
117 | |
118 | /*! |
119 | \property QAbstractSeries::opacity |
120 | \brief The opacity of the series. |
121 | |
122 | By default, the opacity is 1.0. The valid values range from 0.0 (transparent) to 1.0 (opaque). |
123 | */ |
124 | /*! |
125 | \qmlproperty real AbstractSeries::opacity |
126 | The opacity of the series. By default, the opacity is 1.0. |
127 | The valid values range from 0.0 (transparent) to 1.0 (opaque). |
128 | */ |
129 | |
130 | /*! |
131 | \fn void QAbstractSeries::opacityChanged() |
132 | This signal is emitted when the opacity of the series changes. |
133 | */ |
134 | |
135 | /*! |
136 | \property QAbstractSeries::useOpenGL |
137 | \brief Specifies whether or not drawing the series is accelerated by using OpenGL. |
138 | |
139 | Acceleration using OpenGL is supported only for QLineSeries and QScatterSeries. |
140 | A line series used as an edge series for QAreaSeries cannot use OpenGL acceleration. |
141 | When a chart contains any series that are drawn with OpenGL, a transparent QOpenGLWidget |
142 | is created on top of the chart plot area. The accelerated series are not drawn on the underlying |
143 | QGraphicsView, but are instead drawn on the created QOpenGLWidget. |
144 | |
145 | Performance gained from using OpenGL to accelerate series drawing depends on the underlying |
146 | hardware, but in most cases it is significant. For example, on a standard desktop computer, |
147 | enabling OpenGL acceleration for a series typically allows rendering at least a hundred times |
148 | more points without reduction on the frame rate. |
149 | Chart size also has less effect on the frame rate. |
150 | |
151 | The OpenGL acceleration of series drawing is meant for use cases that need fast drawing of |
152 | large numbers of points. It is optimized for efficiency, and therefore the series using |
153 | it lack support for many features available to non-accelerated series: |
154 | |
155 | \list |
156 | \li Series animations are not supported for accelerated series. |
157 | \li Point labels are not supported for accelerated series. |
158 | \li Pen styles, marker shapes and light markers are ignored for accelerated series. |
159 | Only solid lines and plain scatter dots are supported. |
160 | The scatter dots may be circular or rectangular, depending on the underlying graphics |
161 | hardware and drivers. |
162 | \li Polar charts do not support accelerated series. |
163 | \li Enabling chart drop shadow or using transparent chart background color is not recommended |
164 | when using accelerated series, as that can slow the frame rate down significantly. |
165 | \endlist |
166 | |
167 | These additional restrictions stem from the fact that the accelerated series is drawn on a |
168 | separate widget on top of the chart: |
169 | |
170 | \list |
171 | \li If you draw any graphics items on top of a chart containing an accelerated series, |
172 | the accelerated series is drawn over those items. |
173 | \li To enable QOpenGLWidget to be partially transparent, it needs to be stacked on top of |
174 | all other widgets. This means you cannot have other widgets partially covering the |
175 | chart when using accelerated series. |
176 | \li Accelerated series are not supported for use cases where the graphics scene has more than |
177 | one graphics view attached to it. |
178 | \li Accelerated series are not supported for use cases where the chart has non-default geometry. |
179 | For example, adding transforms to the graphics view causes the accelerated series to |
180 | be drawn in an incorrect position related to the chart. |
181 | \endlist |
182 | |
183 | The default value is \c{false}. |
184 | */ |
185 | /*! |
186 | \qmlproperty bool AbstractSeries::useOpenGL |
187 | Specifies whether or not the series is drawn with OpenGL. |
188 | |
189 | Acceleration using OpenGL is supported only for LineSeries and ScatterSeries. |
190 | A line series used as an edge series for a AreaSeries cannot use OpenGL acceleration. |
191 | When a chart contains any series that are drawn with OpenGL, an additional transparent child |
192 | node is created for the ChartView node. The accelerated series are not drawn on the |
193 | ChartView node, but are instead drawn on the child node. |
194 | |
195 | Performance gained from using OpenGL to accelerate series drawing depends on the underlying |
196 | hardware, but in most cases it is significant. For example, on a standard desktop computer, |
197 | enabling OpenGL acceleration for a series typically allows rendering at least hundred times |
198 | more points without reduction on the frame rate. |
199 | Chart size also has less effect on the frame rate. |
200 | The biggest performance sink when rendering ChartView is rendering and uploading the underlying |
201 | chart texture. If the underlying chart itself is not changing rapidly, significant extra |
202 | performance is gained from not needing to regenerate the chart texture for each frame. |
203 | |
204 | The OpenGL acceleration of series drawing is meant for use cases that need fast drawing of |
205 | large numbers of points. It is optimized for efficiency, and therefore the series using |
206 | it lack support for many features available to non-accelerated series: |
207 | |
208 | \list |
209 | \li Series animations are not supported for accelerated series. |
210 | \li Point labels are not supported for accelerated series. |
211 | \li Pen styles, marker shapes and light markers are ignored for accelerated series. |
212 | Only solid lines and plain scatter dots are supported. |
213 | The scatter dots may be circular or rectangular, depending on the underlying graphics |
214 | hardware and drivers. |
215 | \li Polar charts do not support accelerated series. |
216 | \li Mouse events for series are reported asynchronously. |
217 | \li Enabling chart drop shadow or using transparent chart background color is not recommended |
218 | when using accelerated series, as that can slow the frame rate down significantly. |
219 | \endlist |
220 | |
221 | The default value is \c{false}. |
222 | */ |
223 | |
224 | /*! |
225 | \fn void QAbstractSeries::useOpenGLChanged() |
226 | This signal is emitted when accelerating the drawing of the series by using OpenGL |
227 | is enabled or disabled. |
228 | */ |
229 | |
230 | /*! |
231 | \internal |
232 | \brief Constructs QAbstractSeries object with \a parent. |
233 | */ |
234 | QAbstractSeries::QAbstractSeries(QAbstractSeriesPrivate &d, QObject *parent) : |
235 | QObject(parent), |
236 | d_ptr(&d) |
237 | { |
238 | } |
239 | |
240 | /*! |
241 | \brief Virtual destructor for the chart series. |
242 | */ |
243 | QAbstractSeries::~QAbstractSeries() |
244 | { |
245 | if (d_ptr->m_chart) |
246 | qFatal(msg: "Series still bound to a chart when destroyed!" ); |
247 | } |
248 | |
249 | void QAbstractSeries::setName(const QString &name) |
250 | { |
251 | if (name != d_ptr->m_name) { |
252 | d_ptr->m_name = name; |
253 | emit nameChanged(); |
254 | } |
255 | } |
256 | |
257 | QString QAbstractSeries::name() const |
258 | { |
259 | return d_ptr->m_name; |
260 | } |
261 | |
262 | void QAbstractSeries::setVisible(bool visible) |
263 | { |
264 | if (visible != d_ptr->m_visible) { |
265 | d_ptr->m_visible = visible; |
266 | emit visibleChanged(); |
267 | } |
268 | } |
269 | |
270 | bool QAbstractSeries::isVisible() const |
271 | { |
272 | return d_ptr->m_visible; |
273 | } |
274 | |
275 | qreal QAbstractSeries::opacity() const |
276 | { |
277 | return d_ptr->m_opacity; |
278 | } |
279 | |
280 | void QAbstractSeries::setOpacity(qreal opacity) |
281 | { |
282 | if (opacity != d_ptr->m_opacity) { |
283 | d_ptr->m_opacity = opacity; |
284 | emit opacityChanged(); |
285 | } |
286 | } |
287 | |
288 | void QAbstractSeries::setUseOpenGL(bool enable) |
289 | { |
290 | #ifdef QT_NO_OPENGL |
291 | Q_UNUSED(enable); |
292 | #else |
293 | bool polarChart = d_ptr->m_chart && d_ptr->m_chart->chartType() == QChart::ChartTypePolar; |
294 | bool supportedSeries = (type() == SeriesTypeLine || type() == SeriesTypeScatter); |
295 | if ((!enable || !d_ptr->m_blockOpenGL) |
296 | && supportedSeries |
297 | && enable != d_ptr->m_useOpenGL |
298 | && (!enable || !polarChart)) { |
299 | d_ptr->m_useOpenGL = enable; |
300 | emit useOpenGLChanged(); |
301 | } |
302 | #endif |
303 | } |
304 | |
305 | bool QAbstractSeries::useOpenGL() const |
306 | { |
307 | return d_ptr->m_useOpenGL; |
308 | } |
309 | |
310 | /*! |
311 | Returns the chart that the series belongs to. |
312 | |
313 | Set automatically when the series is added to the chart, |
314 | and unset when the series is removed from the chart. |
315 | */ |
316 | QChart *QAbstractSeries::chart() const |
317 | { |
318 | return d_ptr->m_chart; |
319 | } |
320 | |
321 | /*! |
322 | Sets the visibility of the series to \c true. |
323 | |
324 | \sa setVisible(), isVisible() |
325 | */ |
326 | void QAbstractSeries::show() |
327 | { |
328 | setVisible(true); |
329 | } |
330 | |
331 | /*! |
332 | Sets the visibility of the series to \c false. |
333 | |
334 | \sa setVisible(), isVisible() |
335 | */ |
336 | void QAbstractSeries::hide() |
337 | { |
338 | setVisible(false); |
339 | } |
340 | |
341 | /*! |
342 | Attaches the axis specified by \a axis to the series. |
343 | |
344 | Returns \c true if the axis was attached successfully, \c false otherwise. |
345 | |
346 | \note If multiple axes of the same orientation are attached to the same series, |
347 | they will have the same minimum and maximum values. |
348 | |
349 | \sa QChart::addAxis(), QChart::createDefaultAxes() |
350 | */ |
351 | bool QAbstractSeries::attachAxis(QAbstractAxis* axis) |
352 | { |
353 | if (d_ptr->m_chart) |
354 | return d_ptr->m_chart->d_ptr->m_dataset->attachAxis(series: this, axis); |
355 | |
356 | qWarning(msg: "Series not in the chart. Please addSeries to chart first." ); |
357 | return false; |
358 | } |
359 | |
360 | /*! |
361 | Detaches the axis specified by \a axis from the series. |
362 | |
363 | Returns \c true if the axis was detached successfully, \c false otherwise. |
364 | |
365 | \sa QChart::removeAxis() |
366 | */ |
367 | bool QAbstractSeries::detachAxis(QAbstractAxis* axis) |
368 | { |
369 | if (d_ptr->m_chart) |
370 | return d_ptr->m_chart->d_ptr->m_dataset->detachAxis(series: this, axis); |
371 | |
372 | qWarning(msg: "Series not in the chart. Please addSeries to chart first." ); |
373 | return false; |
374 | } |
375 | |
376 | /*! |
377 | Returns the list of axes attached to the series. Usually, an x-axis and a y-axis |
378 | are attached to a series, except for QPieSeries, which does not have any axes attached. |
379 | \sa attachAxis(), detachAxis() |
380 | */ |
381 | QList<QAbstractAxis*> QAbstractSeries::attachedAxes() |
382 | { |
383 | return d_ptr->m_axes; |
384 | } |
385 | |
386 | /////////////////////////////////////////////////////////////////////////////////////////////////// |
387 | |
388 | QAbstractSeriesPrivate::QAbstractSeriesPrivate(QAbstractSeries *q) |
389 | : q_ptr(q), |
390 | m_chart(nullptr), |
391 | m_item(nullptr), |
392 | m_domain(new XYDomain()), |
393 | m_visible(true), |
394 | m_opacity(1.0), |
395 | m_useOpenGL(false), |
396 | m_blockOpenGL(false) |
397 | { |
398 | } |
399 | |
400 | QAbstractSeriesPrivate::~QAbstractSeriesPrivate() |
401 | { |
402 | } |
403 | |
404 | void QAbstractSeriesPrivate::setDomain(AbstractDomain* domain) |
405 | { |
406 | Q_ASSERT(domain); |
407 | if(m_domain.data()!=domain) { |
408 | if (m_item) |
409 | QObject::disconnect(sender: m_domain.data(), SIGNAL(updated()), receiver: m_item.get(), SLOT(handleDomainUpdated())); |
410 | m_domain.reset(other: domain); |
411 | if (m_item) { |
412 | QObject::connect(sender: m_domain.data(), SIGNAL(updated()), receiver: m_item.get(), SLOT(handleDomainUpdated())); |
413 | m_item->handleDomainUpdated(); |
414 | } |
415 | } |
416 | } |
417 | |
418 | void QAbstractSeriesPrivate::setPresenter(ChartPresenter *presenter) |
419 | { |
420 | m_presenter = presenter; |
421 | } |
422 | |
423 | ChartPresenter *QAbstractSeriesPrivate::presenter() const |
424 | { |
425 | return m_presenter; |
426 | } |
427 | |
428 | void QAbstractSeriesPrivate::initializeGraphics(QGraphicsItem* parent) |
429 | { |
430 | Q_ASSERT(m_item); |
431 | Q_UNUSED(parent); |
432 | QObject::connect(sender: m_domain.data(), SIGNAL(updated()), receiver: m_item.get(), SLOT(handleDomainUpdated())); |
433 | } |
434 | |
435 | void QAbstractSeriesPrivate::initializeAnimations(QChart::AnimationOptions options, int duration, |
436 | QEasingCurve &curve) |
437 | { |
438 | Q_UNUSED(options); |
439 | Q_UNUSED(duration); |
440 | Q_UNUSED(curve); |
441 | } |
442 | |
443 | // This function can be used to explicitly block OpenGL use from some otherwise supported series, |
444 | // such as the line series used as edge series of an area series. |
445 | void QAbstractSeriesPrivate::setBlockOpenGL(bool enable) |
446 | { |
447 | m_blockOpenGL = enable; |
448 | if (enable) |
449 | q_ptr->setUseOpenGL(false); |
450 | } |
451 | |
452 | QT_END_NAMESPACE |
453 | |
454 | #include "moc_qabstractseries.cpp" |
455 | #include "moc_qabstractseries_p.cpp" |
456 | |