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 | |
31 | QSplineControlAnimation::QSplineControlAnimation(QObject *parent) |
32 | : QXYSeriesAnimation(parent) |
33 | { |
34 | setDuration(800); |
35 | setEasingCurve(QEasingCurve::OutCubic); |
36 | } |
37 | |
38 | QSplineControlAnimation::~QSplineControlAnimation() {} |
39 | |
40 | QGraphAnimation::GraphAnimationType QSplineControlAnimation::animationType() |
41 | { |
42 | return QGraphAnimation::GraphAnimationType::ControlPoint; |
43 | } |
44 | |
45 | void QSplineControlAnimation::setAnimatingValue(const QVariant &start, const QVariant &end) |
46 | { |
47 | setStartValue(start); |
48 | setEndValue(end); |
49 | } |
50 | |
51 | QVariant 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 | |
68 | void 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 | |
106 | void 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 | |
121 | void 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 | |