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