• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 "bridge/declarative_frontend/jsview/js_data_panel.h"
17 
18 #include <vector>
19 
20 #include "bridge/declarative_frontend/ark_theme/theme_apply/js_data_panel_theme.h"
21 #include "bridge/declarative_frontend/jsview/js_interactable_view.h"
22 #include "bridge/declarative_frontend/jsview/js_linear_gradient.h"
23 #include "bridge/declarative_frontend/jsview/js_utils.h"
24 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
25 #include "bridge/declarative_frontend/jsview/models/data_panel_model_impl.h"
26 #include "core/common/resource/resource_parse_utils.h"
27 #include "core/components/data_panel/data_panel_theme.h"
28 #include "core/components_ng/base/view_abstract_model.h"
29 #include "core/components_ng/pattern/data_panel/data_panel_model.h"
30 #include "core/components_ng/pattern/data_panel/data_panel_model_ng.h"
31 
32 namespace OHOS::Ace {
33 
34 std::unique_ptr<DataPanelModel> DataPanelModel::instance_ = nullptr;
35 std::mutex DataPanelModel::mutex_;
36 
GetInstance()37 DataPanelModel* DataPanelModel::GetInstance()
38 {
39     if (!instance_) {
40         std::lock_guard<std::mutex> lock(mutex_);
41         if (!instance_) {
42 #ifdef NG_BUILD
43             instance_.reset(new NG::DataPanelModelNG());
44 #else
45             if (Container::IsCurrentUseNewPipeline()) {
46                 instance_.reset(new NG::DataPanelModelNG());
47             } else {
48                 instance_.reset(new Framework::DataPanelModelImpl());
49             }
50 #endif
51         }
52     }
53     return instance_.get();
54 }
55 
56 } // namespace OHOS::Ace
57 namespace OHOS::Ace::Framework {
58 namespace {
59 constexpr uint32_t TYPE_CYCLE = 0;
60 }
61 
62 constexpr size_t MAX_COUNT = 9;
63 uint32_t JSDataPanel::dataPanelType_ = 0;
64 
JSBind(BindingTarget globalObj)65 void JSDataPanel::JSBind(BindingTarget globalObj)
66 {
67     JSClass<JSDataPanel>::Declare("DataPanel");
68     JSClass<JSDataPanel>::StaticMethod("create", &JSDataPanel::Create);
69     JSClass<JSDataPanel>::StaticMethod("closeEffect", &JSDataPanel::CloseEffect);
70 
71     JSClass<JSDataPanel>::StaticMethod("valueColors", &JSDataPanel::ValueColors);
72     JSClass<JSDataPanel>::StaticMethod("trackBackgroundColor", &JSDataPanel::TrackBackground);
73     JSClass<JSDataPanel>::StaticMethod("strokeWidth", &JSDataPanel::StrokeWidth);
74     JSClass<JSDataPanel>::StaticMethod("trackShadow", &JSDataPanel::ShadowOption);
75     JSClass<JSDataPanel>::StaticMethod("borderRadius", &JSDataPanel::BorderRadius);
76 
77     JSClass<JSDataPanel>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
78     JSClass<JSDataPanel>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
79     JSClass<JSDataPanel>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
80     JSClass<JSDataPanel>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
81     JSClass<JSDataPanel>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
82     JSClass<JSDataPanel>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
83     JSClass<JSDataPanel>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
84     JSClass<JSDataPanel>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
85     JSClass<JSDataPanel>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
86 
87     JSClass<JSDataPanel>::InheritAndBind<JSViewAbstract>(globalObj);
88 }
89 
Create(const JSCallbackInfo & info)90 void JSDataPanel::Create(const JSCallbackInfo& info)
91 {
92     if (!info[0]->IsObject()) {
93         return;
94     }
95     JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
96     // max
97     double max = jsObj->GetPropertyValue<double>("max", 100.0);
98     // values
99     JSRef<JSVal> jsValue = jsObj->GetProperty("values");
100     if (!jsValue->IsArray()) {
101         return;
102     }
103     JSRef<JSArray> jsArray = JSRef<JSArray>::Cast(jsValue);
104     size_t length = jsArray->Length();
105     std::vector<double> dateValues;
106     double dataSum = 0.0;
107     size_t count = std::min(length, MAX_COUNT);
108     for (size_t i = 0; i < count; ++i) {
109         JSRef<JSVal> item = jsArray->GetValueAt(i);
110         if (!item->IsNumber()) {
111             continue;
112         }
113         double value = item->ToNumber<double>();
114         if (LessOrEqual(value, 0.0)) {
115             value = 0.0;
116         }
117         // if the sum of values exceeds the maximum value, only fill in to the maximum value
118         if (GreatOrEqual(dataSum + value, max) && GreatNotEqual(max, 0)) {
119             dateValues.emplace_back(max - dataSum);
120             break;
121         }
122         dataSum += value;
123         dateValues.emplace_back(value);
124     }
125     if (LessOrEqual(max, 0.0)) {
126         max = dataSum;
127     }
128 
129     size_t dataPanelType = 0;
130     int32_t type = jsObj->GetPropertyValue<int32_t>("type", static_cast<int32_t>(ChartType::RAINBOW));
131     if (type == static_cast<int32_t>(ChartType::LINE)) {
132         dataPanelType = 1;
133     }
134     dataPanelType_ = dataPanelType;
135     DataPanelModel::GetInstance()->Create(dateValues, max, dataPanelType);
136     JSDataPanelTheme::ApplyTheme();
137 }
138 
CloseEffect(const JSCallbackInfo & info)139 void JSDataPanel::CloseEffect(const JSCallbackInfo& info)
140 {
141     bool isCloseEffect = true;
142     if (info[0]->IsBoolean()) {
143         isCloseEffect = info[0]->ToBoolean();
144     }
145     DataPanelModel::GetInstance()->SetEffect(isCloseEffect);
146 }
147 
ValueColors(const JSCallbackInfo & info)148 void JSDataPanel::ValueColors(const JSCallbackInfo& info)
149 {
150     if (info.Length() < 1) {
151         return;
152     }
153 
154     std::vector<OHOS::Ace::NG::Gradient> valueColors;
155     if (!info[0]->IsArray() || info[0]->IsEmpty()) {
156         ConvertThemeColor(valueColors);
157         DataPanelModel::GetInstance()->SetValueColors(valueColors);
158         if (SystemProperties::ConfigChangePerform()) {
159             DataPanelModel::GetInstance()->SetValueColorsSetByUser(false);
160         }
161         return;
162     }
163     bool valueColorsSetByUser = true;
164     auto paramArray = JSRef<JSArray>::Cast(info[0]);
165     size_t length = paramArray->Length();
166     size_t count = std::min(length, MAX_COUNT);
167     for (size_t i = 0; i < count; ++i) {
168         auto item = paramArray->GetValueAt(i);
169         OHOS::Ace::NG::Gradient gradient;
170         if (!ConvertGradientColor(item, gradient)) {
171             valueColors.clear();
172             ConvertThemeColor(valueColors);
173             valueColorsSetByUser = false;
174             break;
175         }
176         valueColors.emplace_back(gradient);
177     }
178     DataPanelModel::GetInstance()->SetValueColors(valueColors);
179     if (SystemProperties::ConfigChangePerform()) {
180         DataPanelModel::GetInstance()->SetValueColorsSetByUser(valueColorsSetByUser);
181     }
182 }
183 
TrackBackground(const JSCallbackInfo & info)184 void JSDataPanel::TrackBackground(const JSCallbackInfo& info)
185 {
186     if (info.Length() < 1) {
187         return;
188     }
189     Color color;
190     if (SystemProperties::ConfigChangePerform()) {
191         RefPtr<ResourceObject> resObj;
192         bool state = ParseJsColor(info[0], color, resObj);
193         DataPanelModel::GetInstance()->CreateWithResourceObj(
194             OHOS::Ace::DataPanelResourceType::TRACK_BACKGROUND_COLOR, resObj);
195         if (state) {
196             DataPanelModel::GetInstance()->SetTrackBackground(color);
197         } else {
198             RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
199             color = theme->GetBackgroundColor();
200             DataPanelModel::GetInstance()->SetTrackBackground(color);
201         }
202     } else {
203         RefPtr<ResourceObject> resObj;
204         if (!ParseJsColor(info[0], color)) {
205             RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
206             color = theme->GetBackgroundColor();
207         }
208         DataPanelModel::GetInstance()->SetTrackBackground(color);
209     }
210 }
211 
StrokeWidth(const JSCallbackInfo & info)212 void JSDataPanel::StrokeWidth(const JSCallbackInfo& info)
213 {
214     if (info.Length() < 1) {
215         return;
216     }
217 
218     RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
219     CalcDimension strokeWidthDimension;
220     RefPtr<ResourceObject> resObj;
221     if (SystemProperties::ConfigChangePerform()) {
222         bool state = ParseJsDimensionVp(info[0], strokeWidthDimension, resObj);
223         DataPanelModel::GetInstance()->CreateWithResourceObj(OHOS::Ace::DataPanelResourceType::STROKE_WIDTH, resObj);
224         if (state) {
225             DataPanelModel::GetInstance()->SetStrokeWidth(strokeWidthDimension);
226         } else {
227             strokeWidthDimension = theme->GetThickness();
228             DataPanelModel::GetInstance()->SetStrokeWidth(strokeWidthDimension);
229         }
230     } else {
231         if (!ParseJsDimensionVp(info[0], strokeWidthDimension)) {
232             strokeWidthDimension = theme->GetThickness();
233         }
234     }
235 
236     // If the parameter value is string(''), parse result 0.
237     // The value of 0 is allowed, but the value of string('') is not allowed, so use theme value.
238     if (info[0]->IsString() && (info[0]->ToString().empty() || !StringUtils::StringToDimensionWithUnitNG(
239         info[0]->ToString(), strokeWidthDimension))) {
240         strokeWidthDimension = theme->GetThickness();
241     }
242 
243     if (strokeWidthDimension.IsNegative() || strokeWidthDimension.Unit() == DimensionUnit::PERCENT) {
244         strokeWidthDimension = theme->GetThickness();
245     }
246     DataPanelModel::GetInstance()->SetStrokeWidth(strokeWidthDimension);
247 }
248 
ShadowOption(const JSCallbackInfo & info)249 void JSDataPanel::ShadowOption(const JSCallbackInfo& info)
250 {
251     OHOS::Ace::NG::DataPanelShadow shadow;
252     if (info[0]->IsNull()) {
253         shadow.isShadowVisible = false;
254         DataPanelModel::GetInstance()->SetShadowOption(shadow);
255         return;
256     }
257     RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
258     double radius = theme->GetTrackShadowRadius().ConvertToVp();
259     double offsetX = theme->GetTrackShadowOffsetX().ConvertToVp();
260     double offsetY = theme->GetTrackShadowOffsetY().ConvertToVp();
261     std::vector<OHOS::Ace::NG::Gradient> shadowColors;
262     ConvertThemeColor(shadowColors);
263     if (info[0]->IsObject()) {
264         auto paramObject = JSRef<JSObject>::Cast(info[0]);
265         JSRef<JSVal> jsRadius = paramObject->GetProperty("radius");
266         JSRef<JSVal> jsOffsetX = paramObject->GetProperty("offsetX");
267         JSRef<JSVal> jsOffsetY = paramObject->GetProperty("offsetY");
268         RefPtr<ResourceObject> resR;
269         RefPtr<ResourceObject> resX;
270         RefPtr<ResourceObject> resY;
271         HandleShadowRadius(jsRadius, radius, resR, shadow);
272         HandleShadowOffsetX(jsOffsetX, offsetX, resX, shadow);
273         HandleShadowOffsetY(jsOffsetY, offsetY, resY, shadow);
274         auto colors = paramObject->GetProperty("colors");
275         if (!colors->IsArray()) {
276             shadow.radius = radius;
277             shadow.offsetX = offsetX;
278             shadow.offsetY = offsetY;
279             shadow.colors = shadowColors;
280             DataPanelModel::GetInstance()->SetShadowOption(shadow);
281             return;
282         }
283         ParseShadowColors(colors, shadowColors);
284     }
285 
286     shadow.radius = radius;
287     shadow.offsetX = offsetX;
288     shadow.offsetY = offsetY;
289     shadow.colors = shadowColors;
290     DataPanelModel::GetInstance()->SetShadowOption(shadow);
291 }
292 
ConvertGradientColor(const JsiRef<JsiValue> & itemParam,OHOS::Ace::NG::Gradient & gradient)293 bool JSDataPanel::ConvertGradientColor(const JsiRef<JsiValue>& itemParam, OHOS::Ace::NG::Gradient& gradient)
294 {
295     if (!itemParam->IsObject()) {
296         return ConvertResourceColor(itemParam, gradient);
297     }
298 
299     JSLinearGradient* jsLinearGradient = JSRef<JSObject>::Cast(itemParam)->Unwrap<JSLinearGradient>();
300     if (!jsLinearGradient) {
301         return ConvertResourceColor(itemParam, gradient);
302     }
303 
304     size_t colorLength = jsLinearGradient->GetGradient().size();
305     if (colorLength == 0) {
306         return false;
307     }
308     for (size_t colorIndex = 0; colorIndex < colorLength; ++colorIndex) {
309         OHOS::Ace::NG::GradientColor gradientColor;
310         gradientColor.SetLinearColor(LinearColor(jsLinearGradient->GetGradient().at(colorIndex).first));
311         gradientColor.SetDimension(jsLinearGradient->GetGradient().at(colorIndex).second);
312         gradient.AddColor(gradientColor);
313     }
314     return true;
315 }
316 
ConvertResourceColor(const JsiRef<JsiValue> & itemParam,OHOS::Ace::NG::Gradient & gradient)317 bool JSDataPanel::ConvertResourceColor(const JsiRef<JsiValue>& itemParam, OHOS::Ace::NG::Gradient& gradient)
318 {
319     Color color;
320     RefPtr<ResourceObject> resObj;
321     if (!ParseJsColor(itemParam, color, resObj)) {
322         return false;
323     }
324 
325     if (resObj && SystemProperties::ConfigChangePerform()) {
326         std::string key = "gradient.Color";
327         gradient.AddResource(key, resObj, [](const RefPtr<ResourceObject>& resObj, NG::Gradient& gradient) {
328             Color color;
329             ResourceParseUtils::ParseResColor(resObj, color);
330             gradient.ClearColors();
331             NG::GradientColor startColor;
332             startColor.SetLinearColor(LinearColor(color));
333             startColor.SetDimension(Dimension(0.0));
334             NG::GradientColor endColor;
335             endColor.SetLinearColor(LinearColor(color));
336             endColor.SetDimension(Dimension(1.0));
337             gradient.AddColor(startColor);
338             gradient.AddColor(endColor);
339         });
340     }
341     OHOS::Ace::NG::GradientColor gradientColorStart;
342     gradientColorStart.SetLinearColor(LinearColor(color));
343     gradientColorStart.SetDimension(Dimension(0.0));
344     gradient.AddColor(gradientColorStart);
345     OHOS::Ace::NG::GradientColor gradientColorEnd;
346     gradientColorEnd.SetLinearColor(LinearColor(color));
347     gradientColorEnd.SetDimension(Dimension(1.0));
348     gradient.AddColor(gradientColorEnd);
349     return true;
350 }
351 
ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient> & colors)352 void JSDataPanel::ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient>& colors)
353 {
354     RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
355     auto themeColors = theme->GetColorsArray();
356     for (const auto& item : themeColors) {
357         OHOS::Ace::NG::Gradient gradient;
358         OHOS::Ace::NG::GradientColor gradientColorStart;
359         gradientColorStart.SetLinearColor(LinearColor(item.first));
360         gradientColorStart.SetDimension(Dimension(0.0));
361         gradient.AddColor(gradientColorStart);
362         OHOS::Ace::NG::GradientColor gradientColorEnd;
363         gradientColorEnd.SetLinearColor(LinearColor(item.second));
364         gradientColorEnd.SetDimension(Dimension(1.0));
365         gradient.AddColor(gradientColorEnd);
366         colors.emplace_back(gradient);
367     }
368 }
369 
BorderRadius(const JSCallbackInfo & info)370 void JSDataPanel::BorderRadius(const JSCallbackInfo& info)
371 {
372     if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
373         JSViewAbstract::JsBorderRadius(info);
374     } else {
375         std::vector<JSCallbackInfoType> checkList { JSCallbackInfoType::STRING, JSCallbackInfoType::NUMBER,
376             JSCallbackInfoType::OBJECT };
377         if (!CheckJSCallbackInfo("JsBorderRadius", info[0], checkList)) {
378             if (dataPanelType_ != TYPE_CYCLE) {
379                 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
380                 CHECK_NULL_VOID(theme);
381                 ViewAbstractModel::GetInstance()->SetBorderRadius(theme->GetDefaultBorderRadius());
382             } else {
383                 ViewAbstractModel::GetInstance()->SetBorderRadius(Dimension {});
384             }
385             return;
386         }
387         JSViewAbstract::ParseBorderRadius(info[0]);
388     }
389 }
390 
ParseShadowColors(const JSRef<JSArray> & colorsArray,std::vector<OHOS::Ace::NG::Gradient> & shadowColors)391 void JSDataPanel::ParseShadowColors(
392     const JSRef<JSArray>& colorsArray, std::vector<OHOS::Ace::NG::Gradient>& shadowColors)
393 {
394     shadowColors.clear();
395     for (size_t i = 0; i < colorsArray->Length(); ++i) {
396         auto item = colorsArray->GetValueAt(i);
397         OHOS::Ace::NG::Gradient gradient;
398         if (!ConvertGradientColor(item, gradient)) {
399             shadowColors.clear();
400             ConvertThemeColor(shadowColors);
401             break;
402         }
403         shadowColors.emplace_back(gradient);
404     }
405 }
406 
HandleShadowRadius(const JSRef<JSVal> & jsRadius,double & radius,RefPtr<ResourceObject> & resR,OHOS::Ace::NG::DataPanelShadow & shadow)407 void JSDataPanel::HandleShadowRadius(
408     const JSRef<JSVal>& jsRadius, double& radius, RefPtr<ResourceObject>& resR, OHOS::Ace::NG::DataPanelShadow& shadow)
409 {
410     RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
411     ParseJsDouble(jsRadius, radius, resR);
412     if (resR && SystemProperties::ConfigChangePerform()) {
413         auto&& updateFunc = [](const RefPtr<ResourceObject>& resRadius, OHOS::Ace::NG::DataPanelShadow& shadow) {
414             RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
415             double radius = theme->GetTrackShadowRadius().ConvertToVp();
416             ResourceParseUtils::ParseResDouble(resRadius, radius);
417             if (NonPositive(radius)) {
418                 radius = theme->GetTrackShadowRadius().ConvertToVp();
419             }
420             shadow.SetRadius(radius);
421         };
422         shadow.AddResource("shadow.radius", resR, std::move(updateFunc));
423     } else {
424         if (NonPositive(radius)) {
425             radius = theme->GetTrackShadowRadius().ConvertToVp();
426         }
427     }
428 }
429 
HandleShadowOffsetX(const JSRef<JSVal> & jsOffsetX,double & offsetX,RefPtr<ResourceObject> & resX,OHOS::Ace::NG::DataPanelShadow & shadow)430 void JSDataPanel::HandleShadowOffsetX(const JSRef<JSVal>& jsOffsetX, double& offsetX, RefPtr<ResourceObject>& resX,
431     OHOS::Ace::NG::DataPanelShadow& shadow)
432 {
433     RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
434     ParseJsDouble(jsOffsetX, offsetX, resX);
435     if (resX && SystemProperties::ConfigChangePerform()) {
436         auto&& updateFuncX = [](const RefPtr<ResourceObject>& resObj, OHOS::Ace::NG::DataPanelShadow& shadow) {
437             RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
438             double val = theme->GetTrackShadowOffsetX().ConvertToVp();
439             ResourceParseUtils::ParseResDouble(resObj, val);
440             shadow.SetOffsetX(val);
441         };
442         shadow.AddResource("shadow.offsetX", resX, std::move(updateFuncX));
443     }
444 }
445 
HandleShadowOffsetY(const JSRef<JSVal> & jsOffsetY,double & offsetY,RefPtr<ResourceObject> & resY,OHOS::Ace::NG::DataPanelShadow & shadow)446 void JSDataPanel::HandleShadowOffsetY(const JSRef<JSVal>& jsOffsetY, double& offsetY, RefPtr<ResourceObject>& resY,
447     OHOS::Ace::NG::DataPanelShadow& shadow)
448 {
449     RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
450     ParseJsDouble(jsOffsetY, offsetY, resY);
451     if (resY && SystemProperties::ConfigChangePerform()) {
452         auto&& updateFuncY = [](const RefPtr<ResourceObject>& resObj, OHOS::Ace::NG::DataPanelShadow& shadow) {
453             RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
454             double val = theme->GetTrackShadowOffsetY().ConvertToVp();
455             ResourceParseUtils::ParseResDouble(resObj, val);
456             shadow.SetOffsetY(val);
457         };
458         shadow.AddResource("shadow.offsetY", resY, std::move(updateFuncY));
459     }
460 }
461 } // namespace OHOS::Ace::Framework
462