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 return;
75
76 auto pointList = series->points();
77 auto &cPoints = series->d_func()->m_controlPoints;
78
79 if (animating() == QGraphAnimation::AnimationState::Playing)
80 end();
81
82 setAnimating(QGraphAnimation::AnimationState::Playing);
83
84 auto oldPoints = cPoints;
85
86 series->d_func()->calculateSplinePoints();
87
88 while (oldPoints.size() < cPoints.size()) {
89 // Each point corresponds to a 2n - 1 control point pair other than the first
90 // (Except when there are only 2 points)
91 // 0 ---- 0
92 // 1 ---- 1
93 // ---- 2
94 // 2 ---- 3
95 // ---- 4 ...
96 QPointF point = pointList[oldPoints.size() / 2];
97 oldPoints.append(t: point);
98 }
99
100 auto varStart = QVariant::fromValue(value: oldPoints);
101 auto varEnd = QVariant::fromValue(value: cPoints);
102
103 setAnimatingValue(start: varStart, end: varEnd);
104}
105
106void QSplineControlAnimation::end()
107{
108 auto series = qobject_cast<QSplineSeries *>(object: parent()->parent()->parent());
109
110 if (!series || animating() == QGraphAnimation::AnimationState::Stopped)
111 return;
112
113 setAnimating(QGraphAnimation::AnimationState::Stopped);
114 stop();
115
116 series->d_func()->calculateSplinePoints();
117
118 emit series->update();
119}
120
121void QSplineControlAnimation::valueUpdated(const QVariant &value)
122{
123 auto series = qobject_cast<QSplineSeries *>(object: parent()->parent()->parent());
124
125 if (!series)
126 return;
127
128 auto &cPoints = series->d_func()->m_controlPoints;
129 auto points = qvariant_cast<QList<QPointF>>(v: value);
130
131 for (int i = 0; i < qMin(a: points.size(), b: cPoints.size()); ++i)
132 cPoints.replace(i, t: points[i]);
133
134 emit series->update();
135}
136

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