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

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