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 <QtGraphs/QLineSeries> |
6 | #include "private/qgraphpointanimation_p.h" |
7 | #include "private/qgraphtransition_p.h" |
8 | #include "private/qxyseries_p.h" |
9 | |
10 | /*! |
11 | \qmltype GraphPointAnimation |
12 | \inqmlmodule QtGraphs |
13 | \ingroup graphs_qml_2D |
14 | \brief An animation type which signifies the animation for points. |
15 | |
16 | GraphPointAnimation is an animation type derived from QVariantAnimation which defines how points are animated. |
17 | It can make use of QVariantAnimation functionality and properties for its animations, such as \c duration and \c easing. |
18 | These animations are housed inside of a QParallelAnimationGroup and hence will run in parallel. |
19 | |
20 | This example shows how to use a GraphPointAnimation to set points to animate with |
21 | a \c duration of 1000ms and \c easing of OutCubic: |
22 | |
23 | \snippet doc_src_qmlgraphs.cpp 12 |
24 | |
25 | For XYSeries, this is considered to be the main list of points defined inside |
26 | the series. The point is linearly interpolated from the start to the end value. |
27 | |
28 | \sa GraphTransition, SplineControlAnimation |
29 | |
30 | */ |
31 | |
32 | QGraphPointAnimation::QGraphPointAnimation(QObject *parent) |
33 | : QXYSeriesAnimation(parent) |
34 | { |
35 | setDuration(800); |
36 | setEasingCurve(QEasingCurve::OutCubic); |
37 | } |
38 | |
39 | QGraphPointAnimation::~QGraphPointAnimation() {} |
40 | |
41 | QGraphAnimation::GraphAnimationType QGraphPointAnimation::animationType() |
42 | { |
43 | return QGraphAnimation::GraphAnimationType::GraphPoint; |
44 | } |
45 | |
46 | void QGraphPointAnimation::setAnimatingValue(const QVariant &start, const QVariant &end) |
47 | { |
48 | setStartValue(start); |
49 | setEndValue(end); |
50 | } |
51 | |
52 | QVariant QGraphPointAnimation::interpolated(const QVariant &start, |
53 | const QVariant &end, |
54 | qreal progress) const |
55 | { |
56 | auto startPoint = qvariant_cast<QPointF>(v: start); |
57 | auto endPoint = qvariant_cast<QPointF>(v: end); |
58 | |
59 | auto interpolatedPoint = QPointF{ |
60 | qreal(startPoint.x() * (1.0 - progress) + endPoint.x() * progress), |
61 | qreal(startPoint.y() * (1.0 - progress) + endPoint.y() * progress), |
62 | }; |
63 | |
64 | return QVariant::fromValue(value: interpolatedPoint); |
65 | } |
66 | |
67 | void QGraphPointAnimation::animate() |
68 | { |
69 | // Hierarchy should look like GraphAnimation -> ParallelAnimationGroup -> GraphTransition -> QXYSeries |
70 | auto series = qobject_cast<QXYSeries *>(object: parent()->parent()->parent()); |
71 | |
72 | if (!series) |
73 | return; |
74 | |
75 | if (animating() == QGraphAnimation::AnimationState::Playing) { |
76 | end(); |
77 | m_activePointIndex = m_newPointIndex; |
78 | } |
79 | |
80 | setAnimating(QGraphAnimation::AnimationState::Playing); |
81 | |
82 | auto &pointList = series->d_func()->m_points; |
83 | |
84 | switch (m_currentTransitionType) { |
85 | default: |
86 | case QGraphTransition::TransitionType::PointAdded: { |
87 | pointList.append(t: series->points().size() >= 1 ? pointList.last() : m_newPoint); |
88 | |
89 | auto startv = QVariant::fromValue(value: pointList.last()); |
90 | auto endv = QVariant::fromValue(value: m_newPoint); |
91 | |
92 | setAnimatingValue(start: startv, end: endv); |
93 | } break; |
94 | case QGraphTransition::TransitionType::PointReplaced: { |
95 | auto startv = QVariant::fromValue(value: pointList[m_activePointIndex]); |
96 | auto endv = QVariant::fromValue(value: m_newPoint); |
97 | |
98 | setAnimatingValue(start: startv, end: endv); |
99 | } break; |
100 | case QGraphTransition::TransitionType::PointRemoved: { |
101 | if (series->points().size() < 1) |
102 | break; |
103 | |
104 | auto startv = QVariant::fromValue(value: pointList[pointList.size() - 1]); |
105 | auto endv = QVariant::fromValue( |
106 | value: pointList[pointList.size() > 1 ? pointList.size() - 2 : pointList.size() - 1]); |
107 | |
108 | setAnimatingValue(start: startv, end: endv); |
109 | } break; |
110 | } |
111 | |
112 | m_previousTransitionType = m_currentTransitionType; |
113 | } |
114 | |
115 | void QGraphPointAnimation::end() |
116 | { |
117 | auto series = qobject_cast<QXYSeries *>(object: parent()->parent()->parent()); |
118 | |
119 | if (!series || animating() == QGraphAnimation::AnimationState::Stopped) { |
120 | m_previousTransitionType = m_currentTransitionType; |
121 | return; |
122 | } |
123 | |
124 | setAnimating(QGraphAnimation::AnimationState::Stopped); |
125 | stop(); |
126 | |
127 | auto &points = series->d_func()->m_points; |
128 | |
129 | switch (m_previousTransitionType) { |
130 | default: |
131 | case QGraphTransition::TransitionType::PointAdded: { |
132 | points.replace(i: m_activePointIndex, t: qvariant_cast<QPointF>(v: endValue())); |
133 | emit series->pointAdded(index: points.size() - 1); |
134 | emit series->countChanged(); |
135 | } break; |
136 | case QGraphTransition::TransitionType::PointReplaced: { |
137 | points.replace(i: m_activePointIndex, t: qvariant_cast<QPointF>(v: endValue())); |
138 | emit series->pointReplaced(index: m_activePointIndex); |
139 | } break; |
140 | case QGraphTransition::TransitionType::PointRemoved: { |
141 | points.remove(i: points.size() - 1); |
142 | emit series->countChanged(); |
143 | emit series->pointRemoved(index: points.size() - 1); |
144 | } break; |
145 | } |
146 | |
147 | m_previousTransitionType = m_currentTransitionType; |
148 | emit series->update(); |
149 | } |
150 | |
151 | void QGraphPointAnimation::valueUpdated(const QVariant &value) |
152 | { |
153 | auto series = qobject_cast<QXYSeries *>(object: parent()->parent()->parent()); |
154 | |
155 | if (!series) |
156 | return; |
157 | |
158 | auto val = qvariant_cast<QPointF>(v: value); |
159 | auto &points = series->d_func()->m_points; |
160 | |
161 | switch (m_currentTransitionType) { |
162 | default: |
163 | case QGraphTransition::TransitionType::PointAdded: { |
164 | points.replace(i: m_activePointIndex, t: val); |
165 | } break; |
166 | case QGraphTransition::TransitionType::PointReplaced: { |
167 | points.replace(i: m_activePointIndex, t: val); |
168 | } break; |
169 | case QGraphTransition::TransitionType::PointRemoved: { |
170 | if (points.size() > 1) |
171 | points.replace(i: points.size() - 1, t: val); |
172 | } break; |
173 | } |
174 | |
175 | emit series->update(); |
176 | } |
177 | |