1 /*
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/components/data_panel/render_data_panel.h"
17
18 #include "core/animation/spring_animation.h"
19
20 namespace OHOS::Ace {
21 namespace {
22
23 constexpr double MILLISECOND_PER_PERCENT = 20.0;
24 constexpr double MAX_TRANSITION_TIME = 5000.0;
25 constexpr double MIN_TRANSITION_TIME = 200.0;
26 constexpr double SECOND_TO_MILLISECOND = 1000.0;
27
28 } // namespace
29
RenderDataPanel()30 RenderDataPanel::RenderDataPanel() : RenderNode(true) {}
31
Update(const RefPtr<Component> & component)32 void RenderDataPanel::Update(const RefPtr<Component>& component)
33 {
34 const RefPtr<DataPanelComponent> dataPanelComponent = AceType::DynamicCast<DataPanelComponent>(component);
35 if (!dataPanelComponent) {
36 return;
37 }
38 height_ = dataPanelComponent->GetDefaultHeight();
39 width_ = dataPanelComponent->GetDefaultWidth();
40 measureType_ = dataPanelComponent->GetMeasureType();
41 type_ = dataPanelComponent->GetPanelType();
42 thickness_ = dataPanelComponent->GetThickness();
43 useEffect_ = dataPanelComponent->GetEffects();
44 backgroundTrack_ = dataPanelComponent->GetTrackColor();
45 autoScale_ = dataPanelComponent->GetAutoScale();
46 userAnimationDuration_ = dataPanelComponent->GetAnimationDuration();
47
48 if (animationInitialized_) {
49 return;
50 }
51
52 auto pipelineContext = GetContext().Upgrade();
53 if (!pipelineContext) {
54 return;
55 }
56 if (!animator_) {
57 animator_ = CREATE_ANIMATOR(pipelineContext);
58 }
59 if (!progressTransitionController_) {
60 progressTransitionController_ = CREATE_ANIMATOR(pipelineContext);
61 }
62 }
63
Measure()64 const Size RenderDataPanel::Measure()
65 {
66 if (measureType_ == MeasureType::CONTENT) {
67 return Size(NormalizeToPx(width_), NormalizeToPx(height_));
68 } else {
69 Size maxSize = GetLayoutParam().GetMaxSize();
70 return Size(maxSize.Width(), maxSize.Height());
71 }
72 }
73
PerformLayout()74 void RenderDataPanel::PerformLayout()
75 {
76 Size panelSize = Measure();
77 SetLayoutSize(panelSize);
78 if (type_ == ChartType::LOADING || (type_ == ChartType::RAINBOW && needReplayAnimation_)) {
79 PlayAnimation();
80 AnimationChanged();
81 }
82 needReplayAnimation_ = false;
83 }
84
OnVisibleChanged()85 void RenderDataPanel::OnVisibleChanged()
86 {
87 AnimationChanged();
88 }
89
OnHiddenChanged(bool hidden)90 void RenderDataPanel::OnHiddenChanged(bool hidden)
91 {
92 AnimationChanged();
93 }
94
AnimationChanged()95 void RenderDataPanel::AnimationChanged()
96 {
97 if (type_ != ChartType::LOADING) {
98 return;
99 }
100 if (GetVisible() && !GetHidden()) {
101 if (animator_) {
102 // when the dataPanel is visible, reset to user defined state.
103 isUserSetPlay_ ? animator_->Play() : animator_->Pause();
104 } else {
105 LOGI("fail to start progress animation");
106 }
107 } else {
108 if (animator_) {
109 animator_->Pause();
110 } else {
111 LOGI("fail to stop progress animation");
112 }
113 }
114 }
115
Update(const RefPtr<Component> & component)116 void RenderProgressDataPanel::Update(const RefPtr<Component>& component)
117 {
118 RenderDataPanel::Update(component);
119 const RefPtr<ProgressDataPanelComponent> dataPanelComponent =
120 AceType::DynamicCast<ProgressDataPanelComponent>(component);
121 if (!dataPanelComponent) {
122 return;
123 }
124 startColor_ = dataPanelComponent->GetStartColor();
125 endColor_ = dataPanelComponent->GetEndColor();
126 // if the type is changed, need to initialize the animator
127 if (isLoading_ != (dataPanelComponent->GetPanelType() == ChartType::LOADING)) {
128 animationInitialized_ = false;
129 }
130 isLoading_ = dataPanelComponent->GetPanelType() == ChartType::LOADING ? true : false;
131 auto animationStartProgress = dataPanelComponent->GetProgressValue();
132 auto needUpdateAnimation = false;
133 if (!NearEqual(animationStartProgress, previousPercentValue_)) {
134 animationDuring_ = std::chrono::steady_clock::now() - previousUpdateTime_;
135 percentChange_ = animationStartProgress - previousPercentValue_;
136 previousPercentValue_ = animationStartProgress;
137 previousUpdateTime_ = std::chrono::steady_clock::now();
138 needUpdateAnimation = true;
139 }
140 if (GreatNotEqual(progress_, 100.0)) {
141 LOGI("chart value %{public}lf is larger than 100.0", progress_);
142 progress_ = 100.0;
143 }
144 if (LessNotEqual(progress_, 0.0)) {
145 LOGI("chart value %{public}lf is smaller than 0.0", progress_);
146 progress_ = 0.0;
147 }
148 if (isLoading_ && !animationInitialized_) {
149 animation_ = AceType::MakeRefPtr<CurveAnimation<double>>(0.0, 2.0, Curves::LINEAR);
150 animation_->AddListener([weak = WeakClaim(this)](const double& value) {
151 auto renderDataPanel = weak.Upgrade();
152 if (!renderDataPanel) {
153 return;
154 }
155 renderDataPanel->rotateAngle_ = 360 * (1 - std::cos(M_PI * value / 2.0) + value / 2.0) / 3;
156 if (value > 1.0) {
157 renderDataPanel->sweepDegree_ = 90.0 * (2 - value);
158 } else {
159 renderDataPanel->sweepDegree_ = 90.0 * value;
160 }
161 renderDataPanel->MarkNeedRender();
162 });
163 PrepareAnimation();
164 PlayAnimation();
165 AnimationChanged();
166 animationInitialized_ = true;
167 } else if (!isLoading_ && needUpdateAnimation) {
168 animation_ = AceType::MakeRefPtr<CurveAnimation<double>>(0.0, 1.5, Curves::LINEAR);
169 animation_->AddListener([weak = WeakClaim(this)](const double& value) {
170 auto renderDataPanel = weak.Upgrade();
171 if (!renderDataPanel) {
172 return;
173 }
174 renderDataPanel->percent_ = value;
175 if (renderDataPanel->percent_ > 1.0) {
176 renderDataPanel->percent_ = 1.0;
177 }
178 renderDataPanel->MarkNeedRender();
179 });
180
181 transitionAnimation_ =
182 AceType::MakeRefPtr<CurveAnimation<double>>(progress_, previousPercentValue_, Curves::EASE_OUT);
183 transitionAnimation_->AddListener([weak = WeakClaim(this)](const double& value) {
184 auto renderDataPanel = weak.Upgrade();
185 if (!renderDataPanel) {
186 return;
187 }
188 renderDataPanel->progress_ = value;
189 renderDataPanel->MarkNeedRender();
190 });
191 PrepareAnimation();
192 StopAnimation();
193 PlayAnimation();
194 AnimationChanged();
195 animationInitialized_ = true;
196 }
197 }
198
PrepareAnimation()199 void RenderProgressDataPanel::PrepareAnimation()
200 {
201 if (animator_) {
202 animator_->AddInterpolator(animation_);
203 animator_->SetDuration(2000);
204 animator_->SetIteration(ANIMATION_REPEAT_INFINITE);
205 }
206
207 if (progressTransitionController_) {
208 double animationTime = 0.0;
209 if (std::abs(percentChange_ * MILLISECOND_PER_PERCENT) > animationDuring_.count() * SECOND_TO_MILLISECOND) {
210 animationTime = std::abs(percentChange_ * MILLISECOND_PER_PERCENT);
211 } else {
212 animationTime = animationDuring_.count() * SECOND_TO_MILLISECOND;
213 }
214
215 if (animationTime < MIN_TRANSITION_TIME || NearEqual(previousPercentValue_, 100.0)) {
216 animationTime = MIN_TRANSITION_TIME;
217 } else if (animationTime > MAX_TRANSITION_TIME) {
218 animationTime = MAX_TRANSITION_TIME;
219 }
220 progressTransitionController_->AddInterpolator(transitionAnimation_);
221 progressTransitionController_->SetDuration(animationTime);
222 progressTransitionController_->SetIteration(1);
223 }
224 }
225
PrepareAnimation()226 void RenderPercentageDataPanel::PrepareAnimation()
227 {
228 if (animator_) {
229 if (GreatOrEqual(userAnimationDuration_, 0.0)) {
230 animator_->SetDuration(userAnimationDuration_);
231 } else {
232 animator_->SetDuration(3000);
233 }
234 if (!useEffect_) {
235 animator_->SetDuration(0.0);
236 }
237 animator_->SetIteration(1);
238 }
239 }
240
Update(const RefPtr<Component> & component)241 void RenderPercentageDataPanel::Update(const RefPtr<Component>& component)
242 {
243 RenderDataPanel::Update(component);
244 const RefPtr<PercentageDataPanelComponent> dataPanelComponent =
245 AceType::DynamicCast<PercentageDataPanelComponent>(component);
246 if (!dataPanelComponent) {
247 return;
248 }
249 startDegree_ = dataPanelComponent->GetStartDegree();
250 sweepDegree_ = dataPanelComponent->GetSweepDegree();
251 segments_ = dataPanelComponent->GetSegments();
252 totalValue_ = dataPanelComponent->GetTotalValue();
253 maxValue_ = dataPanelComponent->GetMaxValue();
254 panelType_ = dataPanelComponent->GetPanelType();
255 if (!animationInitialized_) {
256 auto springProperty = AceType::MakeRefPtr<SpringProperty>(1.0f, 100.0f, 15.0f);
257 auto springAnimation = AceType::MakeRefPtr<SpringAnimation>(springProperty);
258 springAnimation->AddListener([weak = WeakClaim(this)](const double& value) {
259 auto renderDataPanel = weak.Upgrade();
260 if (!renderDataPanel) {
261 return;
262 }
263 renderDataPanel->animationPercent_ = value;
264 renderDataPanel->MarkNeedRender();
265 });
266 animator_->AddInterpolator(springAnimation);
267 animationInitialized_ = true;
268 }
269 PrepareAnimation();
270 needReplayAnimation_ = true;
271 MarkNeedLayout();
272 }
273
274 } // namespace OHOS::Ace
275