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 return;
79
80 if (animating() == QGraphAnimation::AnimationState::Playing) {
81 end();
82 m_activePointIndex = m_newPointIndex;
83 }
84
85 setAnimating(QGraphAnimation::AnimationState::Playing);
86
87 auto &pointList = series->d_func()->m_points;
88
89 switch (m_currentTransitionType) {
90 default:
91 case QGraphTransition::TransitionType::PointAdded: {
92 pointList.append(t: series->points().size() >= 1 ? pointList.last() : m_newPoint);
93
94 auto startv = QVariant::fromValue(value: pointList.last());
95 auto endv = QVariant::fromValue(value: m_newPoint);
96
97 setAnimatingValue(start: startv, end: endv);
98 } break;
99 case QGraphTransition::TransitionType::PointReplaced: {
100 auto startv = QVariant::fromValue(value: pointList[m_activePointIndex]);
101 auto endv = QVariant::fromValue(value: m_newPoint);
102
103 setAnimatingValue(start: startv, end: endv);
104 } break;
105 case QGraphTransition::TransitionType::PointRemoved: {
106 if (series->points().size() < 1)
107 break;
108
109 auto startv = QVariant::fromValue(value: pointList[pointList.size() - 1]);
110 auto endv = QVariant::fromValue(
111 value: pointList[pointList.size() > 1 ? pointList.size() - 2 : pointList.size() - 1]);
112
113 setAnimatingValue(start: startv, end: endv);
114 } break;
115 }
116
117 m_previousTransitionType = m_currentTransitionType;
118}
119
120void QGraphPointAnimation::end()
121{
122 auto series = qobject_cast<QXYSeries *>(object: parent()->parent()->parent());
123
124 if (!series || animating() == QGraphAnimation::AnimationState::Stopped) {
125 m_previousTransitionType = m_currentTransitionType;
126 return;
127 }
128
129 setAnimating(QGraphAnimation::AnimationState::Stopped);
130 stop();
131
132 auto &points = series->d_func()->m_points;
133
134 switch (m_previousTransitionType) {
135 default:
136 case QGraphTransition::TransitionType::PointAdded: {
137 points.replace(i: m_activePointIndex, t: qvariant_cast<QPointF>(v: endValue()));
138 emit series->pointAdded(index: points.size() - 1);
139 emit series->countChanged();
140 } break;
141 case QGraphTransition::TransitionType::PointReplaced: {
142 points.replace(i: m_activePointIndex, t: qvariant_cast<QPointF>(v: endValue()));
143 emit series->pointReplaced(index: m_activePointIndex);
144 } break;
145 case QGraphTransition::TransitionType::PointRemoved: {
146 points.remove(i: points.size() - 1);
147 emit series->countChanged();
148 emit series->pointRemoved(index: points.size() - 1);
149 } break;
150 }
151
152 m_previousTransitionType = m_currentTransitionType;
153 emit series->update();
154}
155
156void QGraphPointAnimation::valueUpdated(const QVariant &value)
157{
158 auto series = qobject_cast<QXYSeries *>(object: parent()->parent()->parent());
159
160 if (!series)
161 return;
162
163 auto val = qvariant_cast<QPointF>(v: value);
164 auto &points = series->d_func()->m_points;
165
166 switch (m_currentTransitionType) {
167 default:
168 case QGraphTransition::TransitionType::PointAdded: {
169 points.replace(i: m_activePointIndex, t: val);
170 } break;
171 case QGraphTransition::TransitionType::PointReplaced: {
172 points.replace(i: m_activePointIndex, t: val);
173 } break;
174 case QGraphTransition::TransitionType::PointRemoved: {
175 if (points.size() > 1)
176 points.replace(i: points.size() - 1, t: val);
177 } break;
178 }
179
180 emit series->update();
181}
182

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