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