1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtCore/QPointF>
5#include "QSplineSeries"
6#include "private/qsplinecontrolanimation_p.h"
7#include "private/qsplineseries_p.h"
8
9/*!
10 \qmltype SplineControlAnimation
11 \inqmlmodule QtGraphs
12 \ingroup graphs_qml_2D
13 \inherits XYSeriesAnimation
14 \brief An animation type which signifies the animation for spline control points.
15
16 SplineControlAnimation is an animation type derived from QVariantAnimation which defines how spline control points
17 are animated. It can make use of QVariantAnimation functionality and properties for its animations, such as \c duration
18 and \c easing. These animations are housed inside a QParallelAnimationGroup and hence will run in parallel.
19 This animation will not affect the main points of the SplineSeries, but only the two control handles
20 on either side of the point. Each of the control points are linearly interpolated in succession.
21
22 This example shows how to use both a SplineControlPointAnimation and a
23 GraphPointAnimation to define animations for both the main series of points and the
24 control points of a SplineSeries:
25
26 \snippet doc_src_qmlgraphs.cpp 13
27
28 \sa GraphTransition, GraphPointAnimation
29*/
30
31QSplineControlAnimation::QSplineControlAnimation(QObject *parent)
32 : QXYSeriesAnimation(parent)
33{
34 setDuration(800);
35 setEasingCurve(QEasingCurve::OutCubic);
36}
37
38QSplineControlAnimation::~QSplineControlAnimation() {}
39
40QGraphAnimation::GraphAnimationType QSplineControlAnimation::animationType()
41{
42 return QGraphAnimation::GraphAnimationType::ControlPoint;
43}
44
45void QSplineControlAnimation::setAnimatingValue(const QVariant &start, const QVariant &end)
46{
47 setStartValue(start);
48 setEndValue(end);
49}
50
51QVariant QSplineControlAnimation::interpolated(const QVariant &start,
52 const QVariant &end,
53 qreal progress) const
54{
55 auto startList = qvariant_cast<QList<QPointF>>(v: start);
56 auto endList = qvariant_cast<QList<QPointF>>(v: end);
57 auto interpolateList = QList<QPointF>();
58
59 for (int i = 0; i < qMin(a: startList.size(), b: endList.size()); ++i) {
60 interpolateList.push_back(
61 t: {qreal(startList[i].x() * (1.0 - progress) + endList[i].x() * progress),
62 qreal(startList[i].y() * (1.0 - progress) + endList[i].y() * progress)});
63 }
64
65 return QVariant::fromValue(value: interpolateList);
66}
67
68void QSplineControlAnimation::animate()
69{
70 // Hierarchy should look like GraphAnimation -> ParallelAnimationGroup -> GraphTransition -> SplineSeries
71 auto series = qobject_cast<QSplineSeries *>(object: parent()->parent()->parent());
72
73 if (!series || series->points().size() < 1) {
74 qCDebug(lcAnimation, "Series is nullptr or series point list is empty");
75 return;
76 }
77
78 auto pointList = series->points();
79 auto &cPoints = series->d_func()->m_controlPoints;
80
81 if (animating() == QGraphAnimation::AnimationState::Playing)
82 end();
83
84 setAnimating(QGraphAnimation::AnimationState::Playing);
85
86 auto oldPoints = cPoints;
87
88 series->d_func()->calculateSplinePoints();
89
90 while (oldPoints.size() < cPoints.size()) {
91 // Each point corresponds to a 2n - 1 control point pair other than the first
92 // (Except when there are only 2 points)
93 // 0 ---- 0
94 // 1 ---- 1
95 // ---- 2
96 // 2 ---- 3
97 // ---- 4 ...
98 QPointF point = pointList[oldPoints.size() / 2];
99 oldPoints.append(t: point);
100 }
101
102 auto varStart = QVariant::fromValue(value: oldPoints);
103 auto varEnd = QVariant::fromValue(value: cPoints);
104
105 setAnimatingValue(start: varStart, end: varEnd);
106}
107
108void QSplineControlAnimation::end()
109{
110 auto series = qobject_cast<QSplineSeries *>(object: parent()->parent()->parent());
111
112 if (!series || animating() == QGraphAnimation::AnimationState::Stopped)
113 return;
114
115 setAnimating(QGraphAnimation::AnimationState::Stopped);
116 stop();
117
118 series->d_func()->calculateSplinePoints();
119
120 emit series->update();
121}
122
123void QSplineControlAnimation::valueUpdated(const QVariant &value)
124{
125 auto series = qobject_cast<QSplineSeries *>(object: parent()->parent()->parent());
126
127 if (!series)
128 return;
129
130 auto &cPoints = series->d_func()->m_controlPoints;
131 auto points = qvariant_cast<QList<QPointF>>(v: value);
132
133 for (int i = 0; i < qMin(a: points.size(), b: cPoints.size()); ++i)
134 cPoints.replace(i, t: points[i]);
135
136 emit series->update();
137}
138

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