1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtCore/QList>
5#include "QtGraphs/QSplineSeries"
6#include "QtGraphs/QXYSeries"
7#include "private/qgraphtransition_p.h"
8#include "private/qsplinecontrolanimation_p.h"
9#include "private/qsplineseries_p.h"
10#include "private/qxyseries_p.h"
11#include "private/qxyseriesanimation_p.h"
12
13/*!
14 \qmltype GraphTransition
15 \inqmlmodule QtGraphs
16 \ingroup graphs_qml_2D
17 \brief A container in which all animations are defined.
18
19 GraphTransition is a container for animations inside on Graphs2D. Define this class
20 inside a graph type to enable animated changes for XYSeries within 2D graphs. To
21 define individual animations, add them inside of the GraphTransition. The
22 individual animations within the same GraphTransition are animated in parallel. If
23 a GraphTransition is found by the graph during a call to a supported function
24 which appends or replaces a point, then the values are interpolated according to
25 the animations that are added.
26
27 This example shows how to define a GraphTransition within a graph.
28
29 \snippet doc_src_qmlgraphs.cpp 11
30
31 \note GraphTransition requires it to be defined directly inside the graph which needs to be animated.
32 Currently only XYSeries are supported.
33
34 \sa GraphPointAnimation, SplineControlAnimation
35*/
36
37/*!
38 \qmlproperty enumeration GraphTransition::TransitionType
39
40 Type of the transition.
41
42 \value None
43 No transition.
44 \value PointAdded
45 A point has been added.
46 \value PointReplaced
47 A point has been replaced.
48 \value PointRemoved
49 A point has been removed.
50*/
51
52QGraphTransition::QGraphTransition(QObject *parent)
53 : QObject(parent)
54 , m_animationGroup(this)
55 , m_initialized(false)
56{}
57
58QGraphTransition::~QGraphTransition() {}
59
60void QGraphTransition::componentComplete()
61{
62 // Currently only assuming animations in QXYSeries
63 Q_ASSERT(parent() != nullptr && qobject_cast<QXYSeries *>(parent()));
64 auto series = qobject_cast<QXYSeries *>(object: parent());
65
66 if (series)
67 series->d_func()->m_graphTransition = this;
68}
69
70void QGraphTransition::onPointChanged(TransitionType type, int index, QPointF point)
71{
72 auto series = qobject_cast<QXYSeries *>(object: parent());
73
74 if (!series || !series->hasLoaded())
75 return;
76
77 if (m_animationGroup.state() == QAbstractAnimation::Running)
78 m_animationGroup.stop();
79
80 for (auto child : m_animationGroup.children()) {
81 auto childAnimation = qobject_cast<QXYSeriesAnimation *>(object: child);
82 childAnimation->updateCurrent(tt: type, index, point);
83 }
84
85 for (auto child : m_animationGroup.children()) {
86 auto childAnimation = qobject_cast<QXYSeriesAnimation *>(object: child);
87
88 childAnimation->animate();
89 }
90
91#ifdef USE_SPLINEGRAPH
92 auto spline = qobject_cast<QSplineSeries *>(object: series);
93
94 if (spline && !contains(type: QGraphAnimation::GraphAnimationType::ControlPoint))
95 spline->d_func()->calculateSplinePoints();
96#endif
97
98 m_animationGroup.start();
99}
100
101void QGraphTransition::initialize()
102{
103 auto series = qobject_cast<QXYSeries *>(object: parent());
104
105 if (!series || m_initialized)
106 return;
107
108 const auto &animationChildren = m_animationGroup.children();
109 for (qsizetype i = 0; i < animationChildren.size(); ++i) {
110 auto childAnimation = qobject_cast<QXYSeriesAnimation *>(object: animationChildren[i]);
111
112 //GraphPointAnimation needs to be the first for the transition to work
113 if (childAnimation->animationType() == QGraphAnimation::GraphAnimationType::GraphPoint
114 && i != 0)
115 return;
116 }
117
118 m_initialized = true;
119}
120
121void QGraphTransition::stop()
122{
123 m_animationGroup.stop();
124
125 for (auto child : m_animationGroup.children()) {
126 auto childAnimation = qobject_cast<QXYSeriesAnimation *>(object: child);
127 childAnimation->end();
128 }
129}
130
131bool QGraphTransition::initialized()
132{
133 return m_initialized;
134}
135
136bool QGraphTransition::contains(QGraphAnimation::GraphAnimationType type)
137{
138 for (const auto anim : std::as_const(t&: m_animations)) {
139 if (anim->animationType() == type)
140 return true;
141 }
142
143 return false;
144}
145
146/*!
147 \qmlproperty list<object> GraphTransition::animations
148 A container for all the animations in the GraphTransition.
149 Currently only supports animations to be added and cleared.
150 By default, the list is empty.
151 */
152QQmlListProperty<QObject> QGraphTransition::animations()
153{
154 return QQmlListProperty<QObject>{this,
155 nullptr,
156 &QGraphTransition::append,
157 nullptr,
158 nullptr,
159 &QGraphTransition::clear};
160}
161
162void QGraphTransition::classBegin() {}
163
164void QGraphTransition::append(QQmlListProperty<QObject> *animationProps, QObject *animation)
165{
166 auto graphTransition = qobject_cast<QGraphTransition *>(object: animationProps->object);
167
168 if (graphTransition) {
169 auto graphAnimation = qobject_cast<QGraphAnimation *>(object: animation);
170 graphTransition->m_animations.append(t: graphAnimation);
171 graphTransition->m_animationGroup.addAnimation(animation: graphAnimation);
172 }
173}
174
175void QGraphTransition::clear(QQmlListProperty<QObject> *)
176{
177 Q_UNIMPLEMENTED();
178}
179

source code of qtgraphs/src/graphs2d/animation/qgraphtransition.cpp