1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtGraphs/qareaseries.h>
5#include <QtGraphs/qbarseries.h>
6#include <QtGraphs/qlineseries.h>
7#include <QtGraphs/qpieseries.h>
8#include <QtGraphs/qscatterseries.h>
9#include <QtGraphs/qsplineseries.h>
10#include <private/qgraphsview_p.h>
11#include <private/arearenderer_p.h>
12#include <private/axisrenderer_p.h>
13#include <private/barsrenderer_p.h>
14#include <private/pierenderer_p.h>
15#include <private/pointrenderer_p.h>
16#include <private/qabstractaxis_p.h>
17#include <QtQuick/private/qquickrectangle_p.h>
18#include <QTimer>
19
20QT_BEGIN_NAMESPACE
21
22/*!
23 \qmltype GraphsView
24 \nativetype QGraphsView
25 \inqmlmodule QtGraphs
26 \ingroup graphs_qml_2D
27 \brief Base type for all Qt Graphs views.
28
29This class collects the series and theming together and draws the graphs.
30You will need to import Qt Graphs module to use this type:
31
32\snippet doc_src_qmlgraphs.cpp 0
33
34After that you can use GraphsView in your qml files:
35
36\snippet doc_src_qmlgraphs.cpp 10
37
38\image graphsview-minimal.png
39
40\sa BarSeries, LineSeries, BarCategoryAxis, ValueAxis, GraphsTheme
41*/
42
43QGraphsView::QGraphsView(QQuickItem *parent) :
44 QQuickItem(parent)
45{
46 setFlag(flag: QQuickItem::ItemHasContents);
47 setAcceptedMouseButtons(Qt::LeftButton);
48 setAcceptHoverEvents(true);
49 m_defaultTheme = new QGraphsTheme(this);
50}
51
52QGraphsView::~QGraphsView()
53{
54 const auto slist = m_seriesList;
55 for (const auto &s : slist)
56 removeSeries(series: s);
57 if (m_axisX)
58 m_axisX->d_func()->setGraph(nullptr);
59 if (m_axisY)
60 m_axisY->d_func()->setGraph(nullptr);
61}
62
63/*!
64 \qmlmethod GraphsView::addSeries(AbstractSeries series)
65 Appends a \a series into GraphsView.
66 If the \a series is null, it will not be added. If the \a series already
67 belongs to the graph, it will be moved into the end.
68*/
69/*!
70 Appends a \a series into GraphsView.
71 If the \a series is null, it will not be added. If the \a series already
72 belongs to the graph, it will be moved into the end.
73*/
74void QGraphsView::addSeries(QObject *series)
75{
76 insertSeries(index: m_seriesList.size(), series);
77}
78
79/*!
80 \qmlmethod GraphsView::insertSeries(int index, AbstractSeries series)
81 Inserts a \a series at the position specified by \a index.
82 If the \a series is null, it will not be inserted. If the \a series already
83 belongs to the graph, it will be moved into \a index.
84*/
85/*!
86 Inserts a \a series at the position specified by \a index.
87 If the \a series is null, it will not be inserted. If the \a series already
88 belongs to the graph, it will be moved into \a index.
89*/
90void QGraphsView::insertSeries(qsizetype index, QObject *object)
91{
92 if (auto series = qobject_cast<QAbstractSeries *>(object)) {
93 series->setGraph(this);
94 if (m_seriesList.contains(t: series)) {
95 qsizetype oldIndex = m_seriesList.indexOf(t: series);
96 if (index != oldIndex) {
97 m_seriesList.removeOne(t: series);
98 if (oldIndex < index)
99 index--;
100 m_seriesList.insert(i: index, t: series);
101 }
102 } else {
103 m_seriesList.insert(i: index, t: series);
104
105 QObject::connect(sender: series, signal: &QAbstractSeries::update,
106 context: this, slot: &QGraphsView::polishAndUpdate);
107 QObject::connect(sender: series, signal: &QAbstractSeries::hoverEnter,
108 context: this, slot: &QGraphsView::handleHoverEnter);
109 QObject::connect(sender: series, signal: &QAbstractSeries::hoverExit,
110 context: this, slot: &QGraphsView::handleHoverExit);
111 QObject::connect(sender: series, signal: &QAbstractSeries::hover,
112 context: this, slot: &QGraphsView::handleHover);
113
114 if (auto pie = qobject_cast<QPieSeries *>(object: series))
115 connect(sender: pie, signal: &QPieSeries::removed, context: m_pieRenderer, slot: &PieRenderer::markedDeleted);
116 }
117 polishAndUpdate();
118 }
119}
120
121/*!
122 \qmlmethod GraphsView::removeSeries(AbstractSeries series)
123 Removes the \a series from the graph.
124*/
125/*!
126 Removes the \a series from the graph.
127*/
128void QGraphsView::removeSeries(QObject *object)
129{
130 if (auto series = reinterpret_cast<QAbstractSeries *>(object)) {
131 series->setGraph(nullptr);
132 m_seriesList.removeAll(t: series);
133 auto &cleanupSeriesList = m_cleanupSeriesList[getSeriesRendererIndex(series)];
134
135 if (auto pie = qobject_cast<QPieSeries *>(object: series))
136 disconnect(sender: pie, signal: &QPieSeries::removed, receiver: m_pieRenderer, slot: &PieRenderer::markedDeleted);
137
138 cleanupSeriesList.append(t: series);
139 polishAndUpdate();
140 }
141}
142
143/*!
144 \qmlmethod GraphsView::removeSeries(int index)
145 Removes the series specified by \a index from the graph.
146*/
147/*!
148 Removes the series specified by \a index from the graph.
149*/
150void QGraphsView::removeSeries(qsizetype index)
151{
152 if (index >= 0 && index < m_seriesList.size())
153 removeSeries(object: m_seriesList[index]);
154}
155
156/*!
157 \qmlmethod bool GraphsView::hasSeries(AbstractSeries series)
158 Returns \c true if the \a series is in the graph.
159*/
160/*!
161 Returns \c true if the \a series is in the graph.
162*/
163bool QGraphsView::hasSeries(QObject *series)
164{
165 return m_seriesList.contains(t: series);
166}
167
168void QGraphsView::addAxis(QAbstractAxis *axis)
169{
170 if (axis) {
171 axis->d_func()->setGraph(this);
172 // Ensure AxisRenderer exists
173 createAxisRenderer();
174 polishAndUpdate();
175 QObject::connect(sender: axis, signal: &QAbstractAxis::update, context: this, slot: &QGraphsView::polishAndUpdate);
176 }
177}
178
179void QGraphsView::removeAxis(QAbstractAxis *axis)
180{
181 if (m_axisX == axis)
182 m_axisX = nullptr;
183 if (m_axisY == axis)
184 m_axisY = nullptr;
185}
186
187qsizetype QGraphsView::graphSeriesCount() const
188{
189 return m_graphSeriesCount;
190}
191
192void QGraphsView::setGraphSeriesCount(qsizetype count)
193{
194 if (count > m_graphSeriesCount)
195 m_graphSeriesCount = count;
196}
197
198void QGraphsView::createBarsRenderer()
199{
200 if (!m_barsRenderer) {
201 m_barsRenderer = new BarsRenderer(this);
202 updateComponentSizes();
203 }
204}
205
206void QGraphsView::createAxisRenderer()
207{
208 if (!m_axisRenderer) {
209 m_axisRenderer = new AxisRenderer(this);
210 m_axisRenderer->setZ(-1);
211 updateComponentSizes();
212 }
213}
214
215void QGraphsView::createPointRenderer()
216{
217 if (!m_pointRenderer) {
218 m_pointRenderer = new PointRenderer(this);
219 updateComponentSizes();
220 }
221}
222
223void QGraphsView::createPieRenderer()
224{
225 if (!m_pieRenderer) {
226 m_pieRenderer = new PieRenderer(this);
227 updateComponentSizes();
228 }
229}
230
231void QGraphsView::createAreaRenderer()
232{
233 if (!m_areaRenderer) {
234 m_areaRenderer = new AreaRenderer(this);
235 updateComponentSizes();
236 }
237}
238
239/*!
240 \property QGraphsView::axisXSmoothing
241 \brief Controls the graph X axis smoothing (antialiasing) amount.
242 By default, the smoothing is \c 1.0.
243*/
244/*!
245 \qmlproperty real GraphsView::axisXSmoothing
246 Controls the graph X axis smoothing (antialiasing) amount.
247 By default, the smoothing is \c 1.0.
248*/
249qreal QGraphsView::axisXSmoothing() const
250{
251 return m_axisXSmoothing;
252}
253
254void QGraphsView::setAxisXSmoothing(qreal smoothing)
255{
256 if (qFuzzyCompare(p1: m_axisXSmoothing, p2: smoothing))
257 return;
258 m_axisXSmoothing = smoothing;
259 emit axisXSmoothingChanged();
260 polishAndUpdate();
261}
262
263/*!
264 \property QGraphsView::axisYSmoothing
265 \brief Controls the graph Y axis smoothing (antialiasing) amount.
266 By default, the smoothing is \c 1.0.
267*/
268/*!
269 \qmlproperty real GraphsView::axisYSmoothing
270 Controls the graph Y axis smoothing (antialiasing) amount.
271 By default, the smoothing is \c 1.0.
272*/
273qreal QGraphsView::axisYSmoothing() const
274{
275 return m_axisYSmoothing;
276}
277
278void QGraphsView::setAxisYSmoothing(qreal smoothing)
279{
280 if (qFuzzyCompare(p1: m_axisYSmoothing, p2: smoothing))
281 return;
282 m_axisYSmoothing = smoothing;
283 emit axisYSmoothingChanged();
284 polishAndUpdate();
285}
286
287/*!
288 \property QGraphsView::gridSmoothing
289 \brief Controls the graph grid smoothing (antialiasing) amount.
290 By default, the smoothing is \c 1.0.
291*/
292/*!
293 \qmlproperty real GraphsView::gridSmoothing
294 Controls the graph grid smoothing (antialiasing) amount.
295 By default, the smoothing is \c 1.0.
296*/
297qreal QGraphsView::gridSmoothing() const
298{
299 return m_gridSmoothing;
300}
301
302void QGraphsView::setGridSmoothing(qreal smoothing)
303{
304 if (qFuzzyCompare(p1: m_gridSmoothing, p2: smoothing))
305 return;
306 m_gridSmoothing = smoothing;
307 emit gridSmoothingChanged();
308 polishAndUpdate();
309}
310
311/*!
312 \property QGraphsView::shadowVisible
313 \brief Controls if the graph grid shadow is visible.
314 By default, shadow visibility is set to \c false.
315*/
316/*!
317 \qmlproperty bool GraphsView::shadowVisible
318 Controls if the graph grid shadow is visible.
319 By default, shadow visibility is set to \c false.
320*/
321bool QGraphsView::isShadowVisible() const
322{
323 return m_isShadowVisible;
324}
325
326void QGraphsView::setShadowVisible(bool newShadowVisibility)
327{
328 if (m_isShadowVisible == newShadowVisibility)
329 return;
330 m_isShadowVisible = newShadowVisibility;
331 emit shadowVisibleChanged();
332 polishAndUpdate();
333}
334
335/*!
336 \property QGraphsView::shadowColor
337 \brief Controls the graph grid shadow color.
338 By default, shadow color is set to \c black.
339*/
340/*!
341 \qmlproperty color GraphsView::shadowColor
342 Controls the graph grid shadow color.
343 By default, shadow color is set to \c black.
344*/
345QColor QGraphsView::shadowColor() const
346{
347 return m_shadowColor;
348}
349
350void QGraphsView::setShadowColor(QColor newShadowColor)
351{
352 if (m_shadowColor == newShadowColor)
353 return;
354 m_shadowColor = newShadowColor;
355 emit shadowColorChanged();
356 polishAndUpdate();
357}
358
359/*!
360 \property QGraphsView::shadowBarWidth
361 \brief Controls the graph grid shadow width.
362 By default, shadow width is set to \c 2.0.
363*/
364/*!
365 \qmlproperty real GraphsView::shadowBarWidth
366 Controls the graph grid shadow width.
367 By default, shadow width is set to \c 2.0.
368*/
369qreal QGraphsView::shadowBarWidth() const
370{
371 return m_shadowBarWidth;
372}
373
374void QGraphsView::setShadowBarWidth(qreal newShadowBarWidth)
375{
376 if (qFuzzyCompare(p1: m_shadowBarWidth, p2: newShadowBarWidth))
377 return;
378 m_shadowBarWidth = newShadowBarWidth;
379 emit shadowBarWidthChanged();
380 polishAndUpdate();
381}
382
383/*!
384 \property QGraphsView::shadowXOffset
385 \brief Controls the graph grid shadow X offset.
386 By default, shadow X offset is set to \c 0.0.
387*/
388/*!
389 \qmlproperty real GraphsView::shadowXOffset
390 Controls the graph grid shadow X offset.
391 By default, shadow X offset is set to \c 0.0.
392*/
393qreal QGraphsView::shadowXOffset() const
394{
395 return m_shadowXOffset;
396}
397
398void QGraphsView::setShadowXOffset(qreal newShadowXOffset)
399{
400 if (qFuzzyCompare(p1: m_shadowXOffset, p2: newShadowXOffset))
401 return;
402 m_shadowXOffset = newShadowXOffset;
403 emit shadowXOffsetChanged();
404 polishAndUpdate();
405}
406
407/*!
408 \property QGraphsView::shadowYOffset
409 \brief Controls the graph grid shadow Y offset.
410 By default, shadow Y offset is set to \c 0.0.
411*/
412/*!
413 \qmlproperty real GraphsView::shadowYOffset
414 Controls the graph grid shadow Y offset.
415 By default, shadow Y offset is set to \c 0.0.
416*/
417qreal QGraphsView::shadowYOffset() const
418{
419 return m_shadowYOffset;
420}
421
422void QGraphsView::setShadowYOffset(qreal newShadowYOffset)
423{
424 if (qFuzzyCompare(p1: m_shadowYOffset, p2: newShadowYOffset))
425 return;
426 m_shadowYOffset = newShadowYOffset;
427 emit shadowYOffsetChanged();
428 polishAndUpdate();
429}
430
431/*!
432 \property QGraphsView::shadowSmoothing
433 \brief Controls the graph grid shadow smoothing (antialiasing) amount.
434 By default, shadow smoothing is set to \c 4.0.
435*/
436/*!
437 \qmlproperty real GraphsView::shadowSmoothing
438 Controls the graph grid shadow smoothing (antialiasing) amount.
439 By default, shadow smoothing is set to \c 4.0.
440*/
441qreal QGraphsView::shadowSmoothing() const
442{
443 return m_shadowSmoothing;
444}
445
446void QGraphsView::setShadowSmoothing(qreal smoothing)
447{
448 if (qFuzzyCompare(p1: m_shadowSmoothing, p2: smoothing))
449 return;
450 m_shadowSmoothing = smoothing;
451 emit shadowSmoothingChanged();
452 polishAndUpdate();
453}
454
455void QGraphsView::handleHoverEnter(const QString &seriesName, QPointF position, QPointF value)
456{
457 if (m_hoverCount == 0)
458 emit hoverEnter(seriesName, position, value);
459 m_hoverCount++;
460}
461
462void QGraphsView::handleHoverExit(const QString &seriesName, QPointF position)
463{
464 m_hoverCount--;
465 if (m_hoverCount == 0)
466 emit hoverExit(seriesName, position);
467}
468
469void QGraphsView::handleHover(const QString &seriesName, QPointF position, QPointF value)
470{
471 emit hover(seriesName, position, value);
472}
473
474void QGraphsView::updateComponentSizes()
475{
476 updateAxisAreas();
477 updatePlotArea();
478
479 if (m_axisRenderer)
480 m_axisRenderer->setSize(size());
481
482 if (m_barsRenderer) {
483 m_barsRenderer->setX(m_plotArea.x());
484 m_barsRenderer->setY(m_plotArea.y());
485 m_barsRenderer->setSize(m_plotArea.size());
486 }
487 if (m_pointRenderer) {
488 m_pointRenderer->setX(m_plotArea.x());
489 m_pointRenderer->setY(m_plotArea.y());
490 m_pointRenderer->setSize(m_plotArea.size());
491 }
492 if (m_pieRenderer) {
493 m_pieRenderer->setX(m_plotArea.x());
494 m_pieRenderer->setY(m_plotArea.y());
495
496 // Remove axis widths and heights as there aren't any in Pie
497 auto s = m_plotArea.size();
498 s.setHeight(s.height() + m_axisHeight);
499 s.setWidth(s.width() - m_axisWidth);
500
501 m_pieRenderer->setSize(s);
502 }
503 if (m_areaRenderer) {
504 m_areaRenderer->setX(m_plotArea.x());
505 m_areaRenderer->setY(m_plotArea.y());
506 m_areaRenderer->setSize(m_plotArea.size());
507 }
508}
509
510void QGraphsView::componentComplete()
511{
512 if (!m_theme) {
513 m_theme = m_defaultTheme;
514 QObject::connect(sender: m_theme, signal: &QGraphsTheme::update, context: this, slot: &QQuickItem::update);
515 m_theme->resetColorTheme();
516 }
517 QQuickItem::componentComplete();
518
519 ensurePolished();
520}
521
522void QGraphsView::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry)
523{
524 QQuickItem::geometryChange(newGeometry, oldGeometry);
525
526 updateComponentSizes();
527
528 ensurePolished();
529}
530
531void QGraphsView::mouseMoveEvent(QMouseEvent *event)
532{
533 bool handled = false;
534
535 // Adjust event position to renderers position
536 QPointF localPos = event->position() - m_plotArea.topLeft();
537 QMouseEvent mappedEvent(event->type(), localPos, event->scenePosition(),
538 event->globalPosition(), event->button(),
539 event->buttons(), event->modifiers());
540 mappedEvent.setAccepted(false);
541
542 if (m_pointRenderer)
543 handled |= m_pointRenderer->handleMouseMove(event: &mappedEvent);
544
545 if (!handled)
546 event->ignore();
547 else
548 polishAndUpdate();
549}
550
551void QGraphsView::mousePressEvent(QMouseEvent *event)
552{
553 bool handled = false;
554
555 // Adjust event position to renderers position
556 QPointF localPos = event->position() - m_plotArea.topLeft();
557 QMouseEvent mappedEvent(event->type(), localPos, event->scenePosition(),
558 event->globalPosition(), event->button(),
559 event->buttons(), event->modifiers());
560 mappedEvent.setAccepted(false);
561
562 if (m_barsRenderer)
563 handled |= m_barsRenderer->handleMousePress(event: &mappedEvent);
564
565 if (m_pointRenderer)
566 handled |= m_pointRenderer->handleMousePress(event: &mappedEvent);
567
568 if (m_areaRenderer)
569 handled |= m_areaRenderer->handleMousePress(event: &mappedEvent);
570
571 if (!handled)
572 event->ignore();
573 else
574 polishAndUpdate();
575}
576
577void QGraphsView::mouseReleaseEvent(QMouseEvent *event)
578{
579 bool handled = false;
580
581 // Adjust event position to renderers position
582 QPointF localPos = event->position() - m_plotArea.topLeft();
583 QMouseEvent mappedEvent(event->type(), localPos, event->scenePosition(),
584 event->globalPosition(), event->button(),
585 event->buttons(), event->modifiers());
586 mappedEvent.setAccepted(false);
587
588 if (m_pointRenderer)
589 handled |= m_pointRenderer->handleMouseRelease(event: &mappedEvent);
590
591 if (!handled)
592 event->ignore();
593 else
594 polishAndUpdate();
595}
596
597void QGraphsView::hoverMoveEvent(QHoverEvent *event)
598{
599 bool handled = false;
600
601 // Adjust event position to renderers position
602 QPointF localPos = event->position() - m_plotArea.topLeft();
603 QHoverEvent mappedEvent(event->type(), localPos,event->globalPosition(),
604 event->oldPosF(), event->modifiers());
605 mappedEvent.setAccepted(false);
606
607 if (m_barsRenderer)
608 handled |= m_barsRenderer->handleHoverMove(event: &mappedEvent);
609
610 if (m_pointRenderer)
611 handled |= m_pointRenderer->handleHoverMove(event: &mappedEvent);
612
613 if (m_areaRenderer)
614 handled |= m_areaRenderer->handleHoverMove(event: &mappedEvent);
615
616 if (!handled)
617 event->ignore();
618}
619
620QSGNode *QGraphsView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *updatePaintNodeData)
621{
622 Q_UNUSED(updatePaintNodeData);
623
624 for (auto series : std::as_const(t&: m_seriesList)) {
625 if (m_barsRenderer) {
626 if (auto barSeries = qobject_cast<QBarSeries *>(object: series))
627 m_barsRenderer->updateSeries(series: barSeries);
628 }
629
630 if (m_pointRenderer) {
631 if (auto lineSeries = qobject_cast<QLineSeries *>(object: series))
632 m_pointRenderer->updateSeries(series: lineSeries);
633
634 if (auto scatterSeries = qobject_cast<QScatterSeries *>(object: series))
635 m_pointRenderer->updateSeries(series: scatterSeries);
636
637 if (auto splineSeries = qobject_cast<QSplineSeries *>(object: series))
638 m_pointRenderer->updateSeries(series: splineSeries);
639 }
640
641 if (m_pieRenderer) {
642 if (auto pieSeries = qobject_cast<QPieSeries *>(object: series))
643 m_pieRenderer->updateSeries(series: pieSeries);
644 }
645
646 if (m_areaRenderer) {
647 if (auto areaSeries = qobject_cast<QAreaSeries *>(object: series))
648 m_areaRenderer->updateSeries(series: areaSeries);
649 }
650 }
651
652 if (m_barsRenderer) {
653 auto &cleanupSeriesList = m_cleanupSeriesList[0];
654 m_barsRenderer->afterUpdate(cleanupSeries&: cleanupSeriesList);
655 cleanupSeriesList.clear();
656 }
657 if (m_pointRenderer) {
658 auto &cleanupSeriesList = m_cleanupSeriesList[1];
659 m_pointRenderer->afterUpdate(cleanupSeries&: cleanupSeriesList);
660 cleanupSeriesList.clear();
661 }
662 if (m_areaRenderer) {
663 auto &cleanupSeriesList = m_cleanupSeriesList[2];
664 m_areaRenderer->afterUpdate(cleanupSeries&: cleanupSeriesList);
665 }
666 if (m_pieRenderer) {
667 auto &cleanupSeriesList = m_cleanupSeriesList[3];
668 m_pieRenderer->afterUpdate(cleanupSeries&: cleanupSeriesList);
669 cleanupSeriesList.clear();
670 }
671
672 // Now possibly dirty theme has been taken into use
673 m_theme->resetThemeDirty();
674
675 return oldNode;
676}
677
678void QGraphsView::updatePolish()
679{
680 if (m_axisRenderer) {
681 m_axisRenderer->handlePolish();
682 // Initialize shaders after system's event queue
683 QTimer::singleShot(interval: 0, receiver: m_axisRenderer, slot: &AxisRenderer::initialize);
684 }
685 if (m_theme && m_theme->isBackgroundVisible()) {
686 if (!m_backgroundRectangle) {
687 // Create m_backgroundRectangle only when it is needed
688 m_backgroundRectangle = new QQuickRectangle(this);
689 m_backgroundRectangle->setZ(-2);
690 }
691 m_backgroundRectangle->setColor(m_theme->backgroundColor());
692 m_backgroundRectangle->setWidth(width());
693 m_backgroundRectangle->setHeight(height());
694 m_backgroundRectangle->setVisible(true);
695 } else if (m_backgroundRectangle) {
696 // Hide and delete the m_backgroundRectangle
697 m_backgroundRectangle->setVisible(false);
698 m_backgroundRectangle->deleteLater();
699 m_backgroundRectangle = nullptr;
700 }
701
702 // Polish for all series
703 for (auto series : std::as_const(t&: m_seriesList)) {
704 if (m_barsRenderer) {
705 if (auto barSeries = qobject_cast<QBarSeries*>(object: series))
706 m_barsRenderer->handlePolish(series: barSeries);
707 }
708
709 if (m_pointRenderer) {
710 if (auto lineSeries = qobject_cast<QLineSeries *>(object: series))
711 m_pointRenderer->handlePolish(series: lineSeries);
712
713 if (auto scatterSeries = qobject_cast<QScatterSeries *>(object: series))
714 m_pointRenderer->handlePolish(series: scatterSeries);
715
716 if (auto splineSeries = qobject_cast<QSplineSeries *>(object: series)) {
717 m_pointRenderer->handlePolish(series: splineSeries);
718 }
719 }
720
721 if (m_pieRenderer) {
722 if (auto pieSeries = qobject_cast<QPieSeries *>(object: series))
723 m_pieRenderer->handlePolish(series: pieSeries);
724 }
725
726 if (m_areaRenderer) {
727 if (auto areaSeries = qobject_cast<QAreaSeries *>(object: series))
728 m_areaRenderer->handlePolish(series: areaSeries);
729 }
730 }
731
732 if (m_barsRenderer) {
733 auto &cleanupSeriesList = m_cleanupSeriesList[0];
734 m_barsRenderer->afterPolish(cleanupSeries&: cleanupSeriesList);
735 }
736 if (m_pointRenderer) {
737 auto &cleanupSeriesList = m_cleanupSeriesList[1];
738 m_pointRenderer->afterPolish(cleanupSeries&: cleanupSeriesList);
739 }
740 if (m_areaRenderer) {
741 auto &cleanupSeriesList = m_cleanupSeriesList[2];
742 m_areaRenderer->afterPolish(cleanupSeries&: cleanupSeriesList);
743 }
744 if (m_pieRenderer) {
745 auto &cleanupSeriesList = m_cleanupSeriesList[3];
746 m_pieRenderer->afterPolish(cleanupSeries&: cleanupSeriesList);
747 }
748}
749
750void QGraphsView::polishAndUpdate()
751{
752 polish();
753 update();
754}
755
756// ***** Static QQmlListProperty methods *****
757
758/*!
759 \qmlproperty list GraphsView::seriesList
760
761 List of series that are rendered by the GraphsView. Filled automatically
762 with the series type children of the GraphsView.
763
764 This is the default property, so child elements are automatically added
765 into the series list.
766 \sa BarSeries, LineSeries, ScatterSeries
767*/
768QQmlListProperty<QObject> QGraphsView::seriesList()
769{
770 return QQmlListProperty<QObject>(this, this,
771 &QGraphsView::appendSeriesFunc,
772 &QGraphsView::countSeriesFunc,
773 &QGraphsView::atSeriesFunc,
774 &QGraphsView::clearSeriesFunc);
775}
776
777void QGraphsView::appendSeriesFunc(QQmlListProperty<QObject> *list, QObject *series)
778{
779 reinterpret_cast<QGraphsView *>(list->data)->addSeries(series);
780}
781
782qsizetype QGraphsView::countSeriesFunc(QQmlListProperty<QObject> *list)
783{
784 return reinterpret_cast<QGraphsView *>(list->data)->getSeriesList().size();
785}
786
787QObject *QGraphsView::atSeriesFunc(QQmlListProperty<QObject> *list, qsizetype index)
788{
789 return reinterpret_cast<QGraphsView *>(list->data)->getSeriesList().at(i: index);
790}
791
792void QGraphsView::clearSeriesFunc(QQmlListProperty<QObject> *list)
793{
794 QGraphsView *declItems = reinterpret_cast<QGraphsView *>(list->data);
795 QList<QObject *> realList = declItems->getSeriesList();
796 qsizetype count = realList.size();
797 for (int i = 0; i < count; i++)
798 declItems->removeSeries(object: realList.at(i));
799}
800
801/*!
802 \qmlproperty GraphsTheme GraphsView::theme
803 The theme used by the graph. Determines coloring,
804 axis lines, fonts etc. If theme has not been set,
805 the default theme is used.
806*/
807QGraphsTheme *QGraphsView::theme() const
808{
809 return m_theme;
810}
811
812void QGraphsView::setTheme(QGraphsTheme *newTheme)
813{
814 if (m_theme == newTheme)
815 return;
816
817 if (m_theme)
818 QObject::disconnect(sender: m_theme, signal: nullptr, receiver: this, member: nullptr);
819
820 m_theme = newTheme;
821
822 if (!m_theme) {
823 m_theme = m_defaultTheme;
824 m_theme->resetColorTheme();
825 }
826
827 QObject::connect(sender: m_theme, signal: &QGraphsTheme::update, context: this, slot: &QGraphsView::polishAndUpdate);
828 emit themeChanged();
829 polishAndUpdate();
830}
831
832/*!
833 \qmlproperty real GraphsView::marginTop
834 The amount of empty space on the top of the graph.
835 By default, the margin is 20.
836*/
837qreal QGraphsView::marginTop() const
838{
839 return m_marginTop;
840}
841
842void QGraphsView::setMarginTop(qreal newMarginTop)
843{
844 if (qFuzzyCompare(p1: m_marginTop, p2: newMarginTop))
845 return;
846 m_marginTop = newMarginTop;
847 updateComponentSizes();
848 polishAndUpdate();
849 emit marginTopChanged();
850}
851
852/*!
853 \qmlproperty real GraphsView::marginBottom
854 The amount of empty space on the bottom of the graph.
855 By default, the margin is 20.
856*/
857qreal QGraphsView::marginBottom() const
858{
859 return m_marginBottom;
860}
861
862void QGraphsView::setMarginBottom(qreal newMarginBottom)
863{
864 if (qFuzzyCompare(p1: m_marginBottom, p2: newMarginBottom))
865 return;
866 m_marginBottom = newMarginBottom;
867 updateComponentSizes();
868 polishAndUpdate();
869 emit marginBottomChanged();
870}
871
872/*!
873 \qmlproperty real GraphsView::marginLeft
874 The amount of empty space on the left of the graph.
875 By default, the margin is 20.
876*/
877qreal QGraphsView::marginLeft() const
878{
879 return m_marginLeft;
880}
881
882void QGraphsView::setMarginLeft(qreal newMarginLeft)
883{
884 if (qFuzzyCompare(p1: m_marginLeft, p2: newMarginLeft))
885 return;
886 m_marginLeft = newMarginLeft;
887 updateComponentSizes();
888 polishAndUpdate();
889 emit marginLeftChanged();
890}
891
892/*!
893 \qmlproperty real GraphsView::marginRight
894 The amount of empty space on the right of the graph.
895 By default, the margin is 20.
896*/
897qreal QGraphsView::marginRight() const
898{
899 return m_marginRight;
900}
901
902void QGraphsView::setMarginRight(qreal newMarginRight)
903{
904 if (qFuzzyCompare(p1: m_marginRight, p2: newMarginRight))
905 return;
906 m_marginRight = newMarginRight;
907 updateComponentSizes();
908 polishAndUpdate();
909 emit marginRightChanged();
910}
911
912QRectF QGraphsView::plotArea() const
913{
914 return m_plotArea;
915}
916
917void QGraphsView::updateAxisAreas()
918{
919 QRectF r = { m_marginLeft,
920 m_marginTop,
921 width() - m_marginLeft - m_marginRight,
922 height() - m_marginTop - m_marginBottom };
923 m_axisHeight = m_axisLabelsHeight + m_axisXLabelsMargin + m_axisTickersHeight;
924 m_axisWidth = m_axisLabelsWidth + m_axisYLabelsMargin + m_axisTickersWidth;
925 float leftPadding = m_axisWidth;
926 float topPadding = 0;
927 m_xAxisArea = { r.x() + leftPadding, r.y() + r.height() - m_axisHeight,
928 r.width() - m_axisWidth, m_axisHeight };
929 m_xAxisLabelsArea = { m_xAxisArea.x(),
930 m_xAxisArea.y() + m_axisTickersHeight + m_axisXLabelsMargin,
931 m_xAxisArea.width(),
932 m_axisTickersHeight };
933 m_xAxisTickersArea = { m_xAxisArea.x(),
934 m_xAxisArea.y(),
935 m_xAxisArea.width(),
936 m_axisTickersHeight };
937 m_yAxisArea = { r.x(), r.y() + topPadding, m_axisWidth, r.height() - m_axisHeight };
938 m_yAxisLabelsArea = { m_yAxisArea.x(),
939 m_yAxisArea.y(),
940 m_axisLabelsWidth,
941 m_yAxisArea.height() };
942 m_yAxisTickersArea = { m_yAxisArea.x() + m_axisLabelsWidth + m_axisYLabelsMargin,
943 m_yAxisArea.y(),
944 m_axisTickersWidth,
945 m_yAxisArea.height() };
946}
947
948void QGraphsView::updatePlotArea()
949{
950 // When axis are in left & bottom
951 qreal x = m_marginLeft;
952 qreal y = m_marginTop;
953 qreal w = width() - x - m_marginRight;
954 qreal h = height() - y - m_marginBottom;
955 x += m_axisWidth;
956 h -= m_axisHeight;
957 w -= m_axisWidth;
958 w = qMax(a: w, b: 0.0);
959 h = qMax(a: h, b: 0.0);
960 QRectF plotArea = QRectF(x, y, w, h);
961 if (plotArea != m_plotArea)
962 m_plotArea = plotArea;
963}
964
965/*!
966 \property QGraphsView::axisX
967 \brief X-axis of this view.
968
969 The x-axis used for the series inside this view.
970*/
971/*!
972 \qmlproperty AbstractAxis GraphsView::axisX
973 The x-axis used for the series inside this view.
974 \sa axisY
975*/
976
977QAbstractAxis *QGraphsView::axisX() const
978{
979 return m_axisX;
980}
981
982void QGraphsView::setAxisX(QAbstractAxis *axis)
983{
984 if (m_axisX == axis)
985 return;
986 removeAxis(axis: m_axisX);
987 m_axisX = axis;
988 if (axis)
989 addAxis(axis);
990 emit update();
991}
992
993/*!
994 \property QGraphsView::axisY
995 \brief Y-axis of this view.
996
997 The y-axis used for the series inside this view.
998*/
999/*!
1000 \qmlproperty AbstractAxis GraphsView::axisY
1001 The y-axis used for the series inside this view.
1002 \sa axisX
1003*/
1004
1005QAbstractAxis *QGraphsView::axisY() const
1006{
1007 return m_axisY;
1008}
1009
1010void QGraphsView::setAxisY(QAbstractAxis *axis)
1011{
1012 if (m_axisY == axis)
1013 return;
1014 removeAxis(axis: m_axisY);
1015 m_axisY = axis;
1016 if (axis)
1017 addAxis(axis);
1018 emit update();
1019}
1020
1021/*!
1022 \property QGraphsView::orientation
1023 \brief Orientation of the GraphsView.
1024
1025 Determines the orientation of the QGraphsView. When the orientation is
1026 \l {Qt::Horizontal}{Qt::Horizontal}, \l axisX and \l axisY will switch the
1027 positions so that \l axisX is rendered vertically and \l axisY horizontally.
1028 This property is currently used by the \l QBarSeries.
1029 The default value is \l {Qt::Vertical}{Qt::Vertical}.
1030*/
1031/*!
1032 \qmlproperty Qt.Orientation GraphsView::orientation
1033 Determines the orientation of the GraphsView. When the orientation is
1034 \l {Qt::Horizontal}{Qt.Horizontal}, \l axisX and \l axisY will switch the
1035 positions so that \l axisX is rendered vertically and \l axisY horizontally.
1036 This property is currently used by the \l BarSeries.
1037 The default value is \l {Qt::Vertical}{Qt.Vertical}.
1038*/
1039Qt::Orientation QGraphsView::orientation() const
1040{
1041 return m_orientation;
1042}
1043
1044void QGraphsView::setOrientation(Qt::Orientation newOrientation)
1045{
1046 if (m_orientation == newOrientation)
1047 return;
1048 m_orientation = newOrientation;
1049 emit orientationChanged();
1050 emit update();
1051}
1052
1053int QGraphsView::getSeriesRendererIndex(QAbstractSeries *series)
1054{
1055 int index = 0;
1056 if (series) {
1057 switch (series->type()) {
1058 case QAbstractSeries::SeriesType::Bar:
1059 index = 0;
1060 break;
1061 case QAbstractSeries::SeriesType::Scatter:
1062 case QAbstractSeries::SeriesType::Line:
1063 case QAbstractSeries::SeriesType::Spline:
1064 index = 1;
1065 break;
1066 case QAbstractSeries::SeriesType::Area:
1067 index = 2;
1068 break;
1069 case QAbstractSeries::SeriesType::Pie:
1070 index = 3;
1071 break;
1072 }
1073 }
1074 return index;
1075}
1076
1077QT_END_NAMESPACE
1078

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtgraphs/src/graphs2d/qgraphsview.cpp