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/jsview/js_interactable_view.h"
21 #include "bridge/declarative_frontend/jsview/js_linear_gradient.h"
22 #include "bridge/declarative_frontend/jsview/js_utils.h"
23 #include "bridge/declarative_frontend/jsview/js_view_abstract.h"
24 #include "bridge/declarative_frontend/jsview/models/data_panel_model_impl.h"
25 #include "bridge/declarative_frontend/ark_theme/theme_apply/js_data_panel_theme.h"
26 #include "core/components/data_panel/data_panel_theme.h"
27 #include "core/components_ng/base/view_abstract_model.h"
28 #include "core/components_ng/pattern/data_panel/data_panel_model_ng.h"
29
30 namespace OHOS::Ace {
31
32 std::unique_ptr<DataPanelModel> DataPanelModel::instance_ = nullptr;
33 std::mutex DataPanelModel::mutex_;
34
GetInstance()35 DataPanelModel* DataPanelModel::GetInstance()
36 {
37 if (!instance_) {
38 std::lock_guard<std::mutex> lock(mutex_);
39 if (!instance_) {
40 #ifdef NG_BUILD
41 instance_.reset(new NG::DataPanelModelNG());
42 #else
43 if (Container::IsCurrentUseNewPipeline()) {
44 instance_.reset(new NG::DataPanelModelNG());
45 } else {
46 instance_.reset(new Framework::DataPanelModelImpl());
47 }
48 #endif
49 }
50 }
51 return instance_.get();
52 }
53
54 } // namespace OHOS::Ace
55 namespace OHOS::Ace::Framework {
56 namespace {
57 constexpr uint32_t TYPE_CYCLE = 0;
58 }
59
60 constexpr size_t MAX_COUNT = 9;
61 uint32_t JSDataPanel::dataPanelType_ = 0;
62
JSBind(BindingTarget globalObj)63 void JSDataPanel::JSBind(BindingTarget globalObj)
64 {
65 JSClass<JSDataPanel>::Declare("DataPanel");
66 JSClass<JSDataPanel>::StaticMethod("create", &JSDataPanel::Create);
67 JSClass<JSDataPanel>::StaticMethod("closeEffect", &JSDataPanel::CloseEffect);
68
69 JSClass<JSDataPanel>::StaticMethod("valueColors", &JSDataPanel::ValueColors);
70 JSClass<JSDataPanel>::StaticMethod("trackBackgroundColor", &JSDataPanel::TrackBackground);
71 JSClass<JSDataPanel>::StaticMethod("strokeWidth", &JSDataPanel::StrokeWidth);
72 JSClass<JSDataPanel>::StaticMethod("trackShadow", &JSDataPanel::ShadowOption);
73 JSClass<JSDataPanel>::StaticMethod("borderRadius", &JSDataPanel::BorderRadius);
74
75 JSClass<JSDataPanel>::StaticMethod("onClick", &JSInteractableView::JsOnClick);
76 JSClass<JSDataPanel>::StaticMethod("onTouch", &JSInteractableView::JsOnTouch);
77 JSClass<JSDataPanel>::StaticMethod("onKeyEvent", &JSInteractableView::JsOnKey);
78 JSClass<JSDataPanel>::StaticMethod("onDeleteEvent", &JSInteractableView::JsOnDelete);
79 JSClass<JSDataPanel>::StaticMethod("onAttach", &JSInteractableView::JsOnAttach);
80 JSClass<JSDataPanel>::StaticMethod("onAppear", &JSInteractableView::JsOnAppear);
81 JSClass<JSDataPanel>::StaticMethod("onDetach", &JSInteractableView::JsOnDetach);
82 JSClass<JSDataPanel>::StaticMethod("onDisAppear", &JSInteractableView::JsOnDisAppear);
83 JSClass<JSDataPanel>::StaticMethod("remoteMessage", &JSInteractableView::JsCommonRemoteMessage);
84
85 JSClass<JSDataPanel>::InheritAndBind<JSViewAbstract>(globalObj);
86 }
87
Create(const JSCallbackInfo & info)88 void JSDataPanel::Create(const JSCallbackInfo& info)
89 {
90 if (!info[0]->IsObject()) {
91 return;
92 }
93 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
94 // max
95 double max = jsObj->GetPropertyValue<double>("max", 100.0);
96 // values
97 JSRef<JSVal> jsValue = jsObj->GetProperty("values");
98 if (!jsValue->IsArray()) {
99 return;
100 }
101 JSRef<JSArray> jsArray = JSRef<JSArray>::Cast(jsValue);
102 size_t length = jsArray->Length();
103 std::vector<double> dateValues;
104 double dataSum = 0.0;
105 size_t count = std::min(length, MAX_COUNT);
106 for (size_t i = 0; i < count; ++i) {
107 JSRef<JSVal> item = jsArray->GetValueAt(i);
108 if (!item->IsNumber()) {
109 continue;
110 }
111 double value = item->ToNumber<double>();
112 if (LessOrEqual(value, 0.0)) {
113 value = 0.0;
114 }
115 // if the sum of values exceeds the maximum value, only fill in to the maximum value
116 if (GreatOrEqual(dataSum + value, max) && GreatNotEqual(max, 0)) {
117 dateValues.emplace_back(max - dataSum);
118 break;
119 }
120 dataSum += value;
121 dateValues.emplace_back(value);
122 }
123 if (LessOrEqual(max, 0.0)) {
124 max = dataSum;
125 }
126
127 size_t dataPanelType = 0;
128 int32_t type = jsObj->GetPropertyValue<int32_t>("type", static_cast<int32_t>(ChartType::RAINBOW));
129 if (type == static_cast<int32_t>(ChartType::LINE)) {
130 dataPanelType = 1;
131 }
132 dataPanelType_ = dataPanelType;
133 DataPanelModel::GetInstance()->Create(dateValues, max, dataPanelType);
134 JSDataPanelTheme::ApplyTheme();
135 }
136
CloseEffect(const JSCallbackInfo & info)137 void JSDataPanel::CloseEffect(const JSCallbackInfo& info)
138 {
139 bool isCloseEffect = true;
140 if (info[0]->IsBoolean()) {
141 isCloseEffect = info[0]->ToBoolean();
142 }
143 DataPanelModel::GetInstance()->SetEffect(isCloseEffect);
144 }
145
ValueColors(const JSCallbackInfo & info)146 void JSDataPanel::ValueColors(const JSCallbackInfo& info)
147 {
148 if (info.Length() < 1) {
149 return;
150 }
151
152 std::vector<OHOS::Ace::NG::Gradient> valueColors;
153 if (!info[0]->IsArray() || info[0]->IsEmpty()) {
154 ConvertThemeColor(valueColors);
155 DataPanelModel::GetInstance()->SetValueColors(valueColors);
156 return;
157 }
158
159 auto paramArray = JSRef<JSArray>::Cast(info[0]);
160 size_t length = paramArray->Length();
161 size_t count = std::min(length, MAX_COUNT);
162 for (size_t i = 0; i < count; ++i) {
163 auto item = paramArray->GetValueAt(i);
164 OHOS::Ace::NG::Gradient gradient;
165 if (!ConvertGradientColor(item, gradient)) {
166 valueColors.clear();
167 ConvertThemeColor(valueColors);
168 break;
169 }
170 valueColors.emplace_back(gradient);
171 }
172 DataPanelModel::GetInstance()->SetValueColors(valueColors);
173 }
174
TrackBackground(const JSCallbackInfo & info)175 void JSDataPanel::TrackBackground(const JSCallbackInfo& info)
176 {
177 if (info.Length() < 1) {
178 return;
179 }
180 Color color;
181 if (!ParseJsColor(info[0], color)) {
182 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
183 color = theme->GetBackgroundColor();
184 }
185
186 DataPanelModel::GetInstance()->SetTrackBackground(color);
187 }
188
StrokeWidth(const JSCallbackInfo & info)189 void JSDataPanel::StrokeWidth(const JSCallbackInfo& info)
190 {
191 if (info.Length() < 1) {
192 return;
193 }
194
195 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
196 CalcDimension strokeWidthDimension;
197 if (!ParseJsDimensionVp(info[0], strokeWidthDimension)) {
198 strokeWidthDimension = theme->GetThickness();
199 }
200
201 // If the parameter value is string(''), parse result 0.
202 // The value of 0 is allowed, but the value of string('') is not allowed, so use theme value.
203 if (info[0]->IsString() && (info[0]->ToString().empty() || !StringUtils::StringToDimensionWithUnitNG(
204 info[0]->ToString(), strokeWidthDimension))) {
205 strokeWidthDimension = theme->GetThickness();
206 }
207
208 if (strokeWidthDimension.IsNegative() || strokeWidthDimension.Unit() == DimensionUnit::PERCENT) {
209 strokeWidthDimension = theme->GetThickness();
210 }
211 DataPanelModel::GetInstance()->SetStrokeWidth(strokeWidthDimension);
212 }
213
ShadowOption(const JSCallbackInfo & info)214 void JSDataPanel::ShadowOption(const JSCallbackInfo& info)
215 {
216 OHOS::Ace::NG::DataPanelShadow shadow;
217 if (info[0]->IsNull()) {
218 shadow.isShadowVisible = false;
219 DataPanelModel::GetInstance()->SetShadowOption(shadow);
220 return;
221 }
222 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
223 double radius = theme->GetTrackShadowRadius().ConvertToVp();
224 double offsetX = theme->GetTrackShadowOffsetX().ConvertToVp();
225 double offsetY = theme->GetTrackShadowOffsetY().ConvertToVp();
226 std::vector<OHOS::Ace::NG::Gradient> shadowColors;
227 ConvertThemeColor(shadowColors);
228 if (info[0]->IsObject()) {
229 auto paramObject = JSRef<JSObject>::Cast(info[0]);
230 JSRef<JSVal> jsRadius = paramObject->GetProperty("radius");
231 JSRef<JSVal> jsOffsetX = paramObject->GetProperty("offsetX");
232 JSRef<JSVal> jsOffsetY = paramObject->GetProperty("offsetY");
233 ParseJsDouble(jsRadius, radius);
234 if (NonPositive(radius)) {
235 radius = theme->GetTrackShadowRadius().ConvertToVp();
236 }
237 ParseJsDouble(jsOffsetX, offsetX);
238 ParseJsDouble(jsOffsetY, offsetY);
239
240 auto colors = paramObject->GetProperty("colors");
241 if (!colors->IsArray()) {
242 shadow.radius = radius;
243 shadow.offsetX = offsetX;
244 shadow.offsetY = offsetY;
245 shadow.colors = shadowColors;
246 DataPanelModel::GetInstance()->SetShadowOption(shadow);
247 return;
248 }
249 shadowColors.clear();
250 auto colorsArray = JSRef<JSArray>::Cast(colors);
251 for (size_t i = 0; i < colorsArray->Length(); ++i) {
252 auto item = colorsArray->GetValueAt(i);
253 OHOS::Ace::NG::Gradient gradient;
254 if (!ConvertGradientColor(item, gradient)) {
255 shadowColors.clear();
256 ConvertThemeColor(shadowColors);
257 break;
258 }
259 shadowColors.emplace_back(gradient);
260 }
261 }
262
263 shadow.radius = radius;
264 shadow.offsetX = offsetX;
265 shadow.offsetY = offsetY;
266 shadow.colors = shadowColors;
267 DataPanelModel::GetInstance()->SetShadowOption(shadow);
268 }
269
ConvertGradientColor(const JsiRef<JsiValue> & itemParam,OHOS::Ace::NG::Gradient & gradient)270 bool JSDataPanel::ConvertGradientColor(const JsiRef<JsiValue>& itemParam, OHOS::Ace::NG::Gradient& gradient)
271 {
272 if (!itemParam->IsObject()) {
273 return ConvertResourceColor(itemParam, gradient);
274 }
275
276 JSLinearGradient* jsLinearGradient = JSRef<JSObject>::Cast(itemParam)->Unwrap<JSLinearGradient>();
277 if (!jsLinearGradient) {
278 return ConvertResourceColor(itemParam, gradient);
279 }
280
281 size_t colorLength = jsLinearGradient->GetGradient().size();
282 if (colorLength == 0) {
283 return false;
284 }
285 for (size_t colorIndex = 0; colorIndex < colorLength; ++colorIndex) {
286 OHOS::Ace::NG::GradientColor gradientColor;
287 gradientColor.SetLinearColor(LinearColor(jsLinearGradient->GetGradient().at(colorIndex).first));
288 gradientColor.SetDimension(jsLinearGradient->GetGradient().at(colorIndex).second);
289 gradient.AddColor(gradientColor);
290 }
291 return true;
292 }
293
ConvertResourceColor(const JsiRef<JsiValue> & itemParam,OHOS::Ace::NG::Gradient & gradient)294 bool JSDataPanel::ConvertResourceColor(const JsiRef<JsiValue>& itemParam, OHOS::Ace::NG::Gradient& gradient)
295 {
296 Color color;
297 if (!ParseJsColor(itemParam, color)) {
298 return false;
299 }
300 OHOS::Ace::NG::GradientColor gradientColorStart;
301 gradientColorStart.SetLinearColor(LinearColor(color));
302 gradientColorStart.SetDimension(Dimension(0.0));
303 gradient.AddColor(gradientColorStart);
304 OHOS::Ace::NG::GradientColor gradientColorEnd;
305 gradientColorEnd.SetLinearColor(LinearColor(color));
306 gradientColorEnd.SetDimension(Dimension(1.0));
307 gradient.AddColor(gradientColorEnd);
308 return true;
309 }
310
ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient> & colors)311 void JSDataPanel::ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient>& colors)
312 {
313 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
314 auto themeColors = theme->GetColorsArray();
315 for (const auto& item : themeColors) {
316 OHOS::Ace::NG::Gradient gradient;
317 OHOS::Ace::NG::GradientColor gradientColorStart;
318 gradientColorStart.SetLinearColor(LinearColor(item.first));
319 gradientColorStart.SetDimension(Dimension(0.0));
320 gradient.AddColor(gradientColorStart);
321 OHOS::Ace::NG::GradientColor gradientColorEnd;
322 gradientColorEnd.SetLinearColor(LinearColor(item.second));
323 gradientColorEnd.SetDimension(Dimension(1.0));
324 gradient.AddColor(gradientColorEnd);
325 colors.emplace_back(gradient);
326 }
327 }
328
BorderRadius(const JSCallbackInfo & info)329 void JSDataPanel::BorderRadius(const JSCallbackInfo& info)
330 {
331 if (Container::LessThanAPITargetVersion(PlatformVersion::VERSION_TWELVE)) {
332 JSViewAbstract::JsBorderRadius(info);
333 } else {
334 std::vector<JSCallbackInfoType> checkList { JSCallbackInfoType::STRING, JSCallbackInfoType::NUMBER,
335 JSCallbackInfoType::OBJECT };
336 if (!CheckJSCallbackInfo("JsBorderRadius", info[0], checkList)) {
337 if (dataPanelType_ != TYPE_CYCLE) {
338 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
339 CHECK_NULL_VOID(theme);
340 ViewAbstractModel::GetInstance()->SetBorderRadius(theme->GetDefaultBorderRadius());
341 } else {
342 ViewAbstractModel::GetInstance()->SetBorderRadius(Dimension {});
343 }
344 return;
345 }
346 JSViewAbstract::ParseBorderRadius(info[0]);
347 }
348 }
349 } // namespace OHOS::Ace::Framework
350