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