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 auto spline = qobject_cast<QSplineSeries *>(object: series);
92
93 if (spline && !contains(type: QGraphAnimation::GraphAnimationType::ControlPoint))
94 spline->d_func()->calculateSplinePoints();
95
96 m_animationGroup.start();
97}
98
99void QGraphTransition::initialize()
100{
101 auto series = qobject_cast<QXYSeries *>(object: parent());
102
103 if (!series || m_initialized)
104 return;
105
106 const auto &animationChildren = m_animationGroup.children();
107 for (qsizetype i = 0; i < animationChildren.size(); ++i) {
108 auto childAnimation = qobject_cast<QXYSeriesAnimation *>(object: animationChildren[i]);
109
110 //GraphPointAnimation needs to be the first for the transition to work
111 if (childAnimation->animationType() == QGraphAnimation::GraphAnimationType::GraphPoint
112 && i != 0)
113 return;
114 }
115
116 m_initialized = true;
117}
118
119void QGraphTransition::stop()
120{
121 m_animationGroup.stop();
122
123 for (auto child : m_animationGroup.children()) {
124 auto childAnimation = qobject_cast<QXYSeriesAnimation *>(object: child);
125 childAnimation->end();
126 }
127}
128
129bool QGraphTransition::initialized()
130{
131 return m_initialized;
132}
133
134bool QGraphTransition::contains(QGraphAnimation::GraphAnimationType type)
135{
136 for (const auto anim : m_animations) {
137 if (anim->animationType() == type)
138 return true;
139 }
140
141 return false;
142}
143
144/*!
145 \qmlproperty list<object> GraphTransition::animations
146 A container for all the animations in the GraphTransition.
147 Currently only supports animations to be added and cleared.
148 By default, the list is empty.
149 */
150QQmlListProperty<QObject> QGraphTransition::animations()
151{
152 return QQmlListProperty<QObject>{this,
153 nullptr,
154 &QGraphTransition::append,
155 nullptr,
156 nullptr,
157 &QGraphTransition::clear};
158}
159
160void QGraphTransition::classBegin() {}
161
162void QGraphTransition::append(QQmlListProperty<QObject> *animationProps, QObject *animation)
163{
164 auto graphTransition = qobject_cast<QGraphTransition *>(object: animationProps->object);
165
166 if (graphTransition) {
167 auto graphAnimation = qobject_cast<QGraphAnimation *>(object: animation);
168 graphTransition->m_animations.append(t: graphAnimation);
169 graphTransition->m_animationGroup.addAnimation(animation: graphAnimation);
170 }
171}
172
173void QGraphTransition::clear(QQmlListProperty<QObject> *)
174{
175 Q_UNIMPLEMENTED();
176}
177

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