1 /*
2 * Copyright (c) 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_ng/pattern/loading_progress/loading_progress_modifier.h"
17 #include <algorithm>
18
19 #include "base/geometry/dimension.h"
20 #include "base/memory/ace_type.h"
21 #include "base/utils/utils.h"
22 #include "bridge/common/dom/dom_type.h"
23 #include "core/components/common/properties/animation_option.h"
24 #include "core/components_ng/base/modifier.h"
25 #include "core/components_ng/pattern/loading_progress/loading_progress_utill.h"
26 #include "core/components_ng/pattern/refresh/refresh_animation_state.h"
27 #include "core/components_ng/render/animation_utils.h"
28 #include "core/components_ng/render/drawing.h"
29 #include "core/components_ng/render/drawing_prop_convertor.h"
30 #include "core/components_ng/render/paint.h"
31
32 namespace OHOS::Ace::NG {
33 namespace {
34 constexpr float TOTAL_ANGLE = 360.0f;
35 constexpr float ROTATEX = -116.0f;
36 constexpr float ROTATEY = 30.0f;
37 constexpr float ROTATEZ = 22.0f;
38 constexpr float COUNT = 50.0f;
39 constexpr float HALF = 0.5f;
40 constexpr float DOUBLE = 2.0f;
41 constexpr int32_t RING_ALPHA = 200;
42 constexpr int32_t TOTAL_POINTS_COUNT = 20;
43 constexpr int32_t TAIL_ANIAMTION_DURATION = 400;
44 constexpr int32_t TRANS_DURATION = 100;
45 constexpr float TOTAL_TAIL_LENGTH = 60.0f;
46 constexpr float TAIL_ALPHA_RATIO = 0.82f;
47 constexpr float INITIAL_SIZE_SCALE = 0.825f;
48 constexpr float INITIAL_OPACITY_SCALE = 0.7f;
49 constexpr float COMET_TAIL_ANGLE = 3.0f;
50 constexpr int32_t LOADING_DURATION = 1200;
51 constexpr float FOLLOW_START = 72.0f;
52 constexpr float FOLLOW_SPAN = 10.0f;
53 constexpr float FULL_COUNT = 100.0f;
54 constexpr float STAGE1 = 0.25f;
55 constexpr float STAGE2 = 0.65f;
56 constexpr float STAGE3 = 0.75f;
57 constexpr float STAGE4 = 0.85f;
58 constexpr float STAGE5 = 1.0f;
59 constexpr float OPACITY1 = 0.2f;
60 constexpr float OPACITY2 = 0.7f;
61 constexpr float OPACITY3 = 1.0f;
62 constexpr float SIZE_SCALE1 = 0.65f;
63 constexpr float SIZE_SCALE2 = 0.825f;
64 constexpr float SIZE_SCALE3 = 0.93f;
65 constexpr float MOVE_STEP = 0.06f;
66 constexpr float TRANS_OPACITY_SPAN = 0.3f;
67 constexpr float FULL_OPACITY = 255.0f;
68 constexpr float TWO = 2.0f;
69 } // namespace
LoadingProgressModifier(LoadingProgressOwner loadingProgressOwner)70 LoadingProgressModifier::LoadingProgressModifier(LoadingProgressOwner loadingProgressOwner)
71 : date_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
72 color_(AceType::MakeRefPtr<AnimatablePropertyColor>(LinearColor::BLUE)),
73 centerDeviation_(AceType::MakeRefPtr<AnimatablePropertyFloat>(0.0f)),
74 cometOpacity_(AceType::MakeRefPtr<AnimatablePropertyFloat>(INITIAL_OPACITY_SCALE)),
75 cometSizeScale_(AceType::MakeRefPtr<AnimatablePropertyFloat>(INITIAL_SIZE_SCALE)),
76 cometTailLen_(AceType::MakeRefPtr<AnimatablePropertyFloat>(TOTAL_TAIL_LENGTH)),
77 sizeScale_(AceType::MakeRefPtr<AnimatablePropertyFloat>(1.0f)),
78 loadingProgressOwner_(loadingProgressOwner)
79 {
80 AttachProperty(date_);
81 AttachProperty(color_);
82 AttachProperty(centerDeviation_);
83 AttachProperty(cometOpacity_);
84 AttachProperty(cometSizeScale_);
85 AttachProperty(cometTailLen_);
86 AttachProperty(sizeScale_);
87 };
88
onDraw(DrawingContext & context)89 void LoadingProgressModifier::onDraw(DrawingContext& context)
90 {
91 float date = date_->Get();
92 auto diameter = std::min(context.width, context.height);
93 RingParam ringParam;
94 ringParam.strokeWidth = LoadingProgressUtill::GetRingStrokeWidth(diameter) * sizeScale_->Get();
95 ringParam.radius = LoadingProgressUtill::GetRingRadius(diameter) * sizeScale_->Get();
96 ringParam.movement =
97 (ringParam.radius * DOUBLE + ringParam.strokeWidth) * centerDeviation_->Get() * sizeScale_->Get();
98
99 CometParam cometParam;
100 cometParam.radius = LoadingProgressUtill::GetCometRadius(diameter) * sizeScale_->Get();
101 cometParam.alphaScale = cometOpacity_->Get();
102 cometParam.sizeScale = cometSizeScale_->Get();
103 cometParam.pointCount = GetCometNumber();
104
105 auto orbitRadius = LoadingProgressUtill::GetOrbitRadius(diameter) * sizeScale_->Get();
106 if (date > COUNT) {
107 DrawRing(context, ringParam);
108 DrawOrbit(context, cometParam, orbitRadius, date);
109 } else {
110 DrawOrbit(context, cometParam, orbitRadius, date);
111 DrawRing(context, ringParam);
112 }
113 }
114
DrawRing(DrawingContext & context,const RingParam & ringParam)115 void LoadingProgressModifier::DrawRing(DrawingContext& context, const RingParam& ringParam)
116 {
117 auto& canvas = context.canvas;
118 canvas.Save();
119 RSPen pen;
120 auto ringColor = color_->Get();
121 pen.SetColor(ToRSColor(Color::FromARGB(RING_ALPHA, ringColor.GetRed(), ringColor.GetGreen(), ringColor.GetBlue())));
122 pen.SetWidth(ringParam.strokeWidth);
123 pen.SetAntiAlias(true);
124 canvas.AttachPen(pen);
125 canvas.DrawCircle({ context.width * HALF, context.height * HALF + ringParam.movement }, ringParam.radius);
126 canvas.DetachPen();
127 canvas.Restore();
128 }
129
DrawOrbit(DrawingContext & context,const CometParam & cometParam,float orbitRadius,float date)130 void LoadingProgressModifier::DrawOrbit(
131 DrawingContext& context, const CometParam& cometParam, float orbitRadius, float date)
132 {
133 auto pointCounts = cometParam.pointCount;
134 auto& canvas = context.canvas;
135 float width_ = context.width;
136 float height_ = context.height;
137 double angle = TOTAL_ANGLE * date / FULL_COUNT;
138 auto* camera_ = new RSCamera3D();
139 camera_->Save();
140 camera_->RotateYDegrees(ROTATEY);
141 camera_->RotateXDegrees(ROTATEX);
142 camera_->RotateZDegrees(ROTATEZ);
143 RSMatrix matrix;
144 camera_->ApplyToMatrix(matrix);
145 camera_->Restore();
146 auto center = RSPoint(width_ / 2, height_ / 2);
147 RSBrush brush;
148 brush.SetAntiAlias(true);
149 canvas.Save();
150 canvas.Translate(center.GetX(), center.GetY());
151 std::vector<RSPoint> points;
152 for (uint32_t i = 0; i < pointCounts; i++) {
153 RSPoint point;
154 float cometAngal = GetCurentCometAngle(angle, pointCounts - i, pointCounts);
155 float rad = cometAngal * PI_NUM / (TOTAL_ANGLE * HALF);
156 point.SetX(std::cos(rad) * orbitRadius);
157 point.SetY(-std::sin(rad) * orbitRadius);
158 points.push_back(point);
159 }
160 std::vector<RSPoint> distPoints(points.size());
161 matrix.MapPoints(distPoints, points, points.size());
162 auto cometColor = color_->Get();
163 float colorAlpha = cometColor.GetAlpha() / FULL_OPACITY;
164 auto baseAlpha = colorAlpha * cometParam.alphaScale;
165 for (uint32_t i = 0; i < distPoints.size(); i++) {
166 RSPoint pointCenter = distPoints[i];
167 float setAlpha = GetCurentCometOpacity(baseAlpha, distPoints.size() - i, distPoints.size());
168 if (NearZero(setAlpha)) {
169 continue;
170 }
171 brush.SetColor(
172 ToRSColor(Color::FromRGBO(cometColor.GetRed(), cometColor.GetGreen(), cometColor.GetBlue(), setAlpha)));
173 canvas.AttachBrush(brush);
174 canvas.DrawCircle(pointCenter, cometParam.radius * cometParam.sizeScale);
175 }
176 canvas.DetachBrush();
177 canvas.Restore();
178 }
179
StartRecycleRingAnimation()180 void LoadingProgressModifier::StartRecycleRingAnimation()
181 {
182 auto previousStageCurve = AceType::MakeRefPtr<CubicCurve>(0.0f, 0.0f, 0.67f, 1.0f);
183 AnimationOption option;
184 option.SetDuration(LOADING_DURATION);
185 option.SetCurve(previousStageCurve);
186 option.SetIteration(-1);
187 AnimationUtils::OpenImplicitAnimation(option, previousStageCurve, nullptr);
188 auto middleStageCurve = AceType::MakeRefPtr<CubicCurve>(0.33f, 0.0f, 0.67f, 1.0f);
189 AnimationUtils::AddKeyFrame(STAGE1, middleStageCurve, [&]() { centerDeviation_->Set(-1 * MOVE_STEP); });
190 auto latterStageCurve = AceType::MakeRefPtr<CubicCurve>(0.33f, 0.0f, 1.0f, 1.0f);
191 AnimationUtils::AddKeyFrame(STAGE3, latterStageCurve, [&]() { centerDeviation_->Set(MOVE_STEP); });
192 AnimationUtils::AddKeyFrame(STAGE5, latterStageCurve, [&]() { centerDeviation_->Set(0.0f); });
193 AnimationUtils::CloseImplicitAnimation();
194 }
195
StartRecycleCometAnimation()196 void LoadingProgressModifier::StartRecycleCometAnimation()
197 {
198 auto curve = AceType::MakeRefPtr<LinearCurve>();
199 AnimationOption option;
200 option.SetDuration(LOADING_DURATION);
201 option.SetCurve(curve);
202 option.SetIteration(-1);
203 cometOpacity_->Set(OPACITY2);
204 AnimationUtils::OpenImplicitAnimation(option, curve, nullptr);
205 AnimationUtils::AddKeyFrame(STAGE1, curve, [&]() {
206 cometOpacity_->Set(OPACITY1);
207 cometSizeScale_->Set(SIZE_SCALE1);
208 });
209 AnimationUtils::AddKeyFrame(STAGE2, curve, [&]() {
210 cometOpacity_->Set(OPACITY3);
211 cometSizeScale_->Set(SIZE_SCALE3);
212 });
213 AnimationUtils::AddKeyFrame(STAGE3, curve, [&]() {
214 cometOpacity_->Set(OPACITY3);
215 cometSizeScale_->Set(1.0f);
216 });
217 AnimationUtils::AddKeyFrame(STAGE4, curve, [&]() {
218 cometOpacity_->Set(OPACITY3);
219 cometSizeScale_->Set(SIZE_SCALE3);
220 });
221 AnimationUtils::AddKeyFrame(STAGE5, curve, [&]() {
222 cometOpacity_->Set(OPACITY2);
223 cometSizeScale_->Set(SIZE_SCALE2);
224 });
225 AnimationUtils::CloseImplicitAnimation();
226 }
227
StartCometTailAnimation()228 void LoadingProgressModifier::StartCometTailAnimation()
229 {
230 auto curve = AceType::MakeRefPtr<LinearCurve>();
231 AnimationOption option;
232 option.SetDuration(TAIL_ANIAMTION_DURATION);
233 option.SetIteration(1);
234 option.SetCurve(curve);
235 AnimationUtils::Animate(option, [&]() { cometTailLen_->Set(TOTAL_TAIL_LENGTH); });
236 }
237
GetCurentCometOpacity(float baseOpacity,uint32_t index,uint32_t totalNumber)238 float LoadingProgressModifier::GetCurentCometOpacity(float baseOpacity, uint32_t index, uint32_t totalNumber)
239 {
240 return baseOpacity * std::pow(TAIL_ALPHA_RATIO, std::clamp(index, 1u, totalNumber) - 1);
241 }
242
GetCurentCometAngle(float baseAngle,uint32_t index,uint32_t totalNumber)243 float LoadingProgressModifier::GetCurentCometAngle(float baseAngle, uint32_t index, uint32_t totalNumber)
244 {
245 return std::fmod((baseAngle - (std::clamp(index, 1u, totalNumber) - 1) * COMET_TAIL_ANGLE), TOTAL_ANGLE);
246 }
247
GetCometNumber()248 uint32_t LoadingProgressModifier::GetCometNumber()
249 {
250 CHECK_NULL_RETURN(cometTailLen_, TOTAL_POINTS_COUNT);
251 return static_cast<uint32_t>(cometTailLen_->Get() / COMET_TAIL_ANGLE);
252 }
253
StartRecycle()254 void LoadingProgressModifier::StartRecycle()
255 {
256 if (isLoading_) {
257 return;
258 }
259 sizeScale_->Set(1.0f);
260 if (date_) {
261 isLoading_ = true;
262 date_->Set(0.0f);
263 AnimationOption option = AnimationOption();
264 RefPtr<Curve> curve = AceType::MakeRefPtr<LinearCurve>();
265 option.SetDuration(LOADING_DURATION);
266 option.SetDelay(0);
267 option.SetCurve(curve);
268 option.SetIteration(-1);
269 AnimationUtils::Animate(option, [&]() { date_->Set(FULL_COUNT); });
270 }
271 cometOpacity_->Set(INITIAL_OPACITY_SCALE);
272 cometSizeScale_->Set(INITIAL_SIZE_SCALE);
273 StartRecycleRingAnimation();
274 StartRecycleCometAnimation();
275 }
276
StartTransToRecycleAnimation()277 void LoadingProgressModifier::StartTransToRecycleAnimation()
278 {
279 auto curve = AceType::MakeRefPtr<CubicCurve>(0.6f, 0.2f, 1.0f, 1.0f);
280 AnimationOption option;
281 option.SetDuration(TRANS_DURATION);
282 option.SetIteration(1);
283 option.SetCurve(curve);
284 AnimationUtils::Animate(
285 option,
286 [&]() {
287 date_->Set(FULL_COUNT);
288 cometOpacity_->Set(1.0 - TRANS_OPACITY_SPAN);
289 cometSizeScale_->Set(INITIAL_SIZE_SCALE);
290 },
291 [&]() { StartRecycle(); });
292 StartCometTailAnimation();
293 }
294
ChangeRefreshFollowData(float refreshFollowRatio)295 void LoadingProgressModifier::ChangeRefreshFollowData(float refreshFollowRatio)
296 {
297 auto ratio = CorrectNormalize(refreshFollowRatio);
298 sizeScale_->Set(std::sqrt(TWO) * HALF + (1.0 - std::sqrt(TWO) * HALF) * ratio);
299 if (isLoading_) {
300 return;
301 }
302 CHECK_NULL_VOID(date_);
303 date_->Set(FOLLOW_START + FOLLOW_SPAN * ratio);
304 cometTailLen_->Set(COMET_TAIL_ANGLE);
305 cometOpacity_->Set(1.0f);
306 cometSizeScale_->Set(1.0f);
307 }
308
CorrectNormalize(float originData)309 float LoadingProgressModifier::CorrectNormalize(float originData)
310 {
311 auto ratio = originData;
312 if (ratio < 0.0f) {
313 ratio = 0.0f;
314 }
315 if (ratio > 1.0f) {
316 ratio = 1.0f;
317 };
318 return ratio;
319 }
320 } // namespace OHOS::Ace::NG
321