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 JSRef<JSObject> jsObj = JSRef<JSObject>::Cast(info[0]);
84 // max
85 double max = jsObj->GetPropertyValue<double>("max", 100.0);
86 // values
87 JSRef<JSVal> jsValue = jsObj->GetProperty("values");
88 if (!jsValue->IsArray()) {
89 return;
90 }
91 JSRef<JSArray> jsArray = JSRef<JSArray>::Cast(jsValue);
92 size_t length = jsArray->Length();
93 std::vector<double> dateValues;
94 double dataSum = 0.0;
95 size_t count = std::min(length, MAX_COUNT);
96 for (size_t i = 0; i < count; ++i) {
97 JSRef<JSVal> item = jsArray->GetValueAt(i);
98 if (!item->IsNumber()) {
99 continue;
100 }
101 double value = item->ToNumber<double>();
102 if (LessOrEqual(value, 0.0)) {
103 value = 0.0;
104 }
105 // if the sum of values exceeds the maximum value, only fill in to the maximum value
106 if (GreatOrEqual(dataSum + value, max) && GreatNotEqual(max, 0)) {
107 dateValues.emplace_back(max - dataSum);
108 break;
109 }
110 dataSum += value;
111 dateValues.emplace_back(value);
112 }
113 if (LessOrEqual(max, 0.0)) {
114 max = dataSum;
115 }
116
117 size_t dataPanelType = 0;
118 int32_t type = jsObj->GetPropertyValue<int32_t>("type", static_cast<int32_t>(ChartType::RAINBOW));
119 if (type == static_cast<int32_t>(ChartType::LINE)) {
120 dataPanelType = 1;
121 }
122 DataPanelModel::GetInstance()->Create(dateValues, max, dataPanelType);
123 }
124
CloseEffect(const JSCallbackInfo & info)125 void JSDataPanel::CloseEffect(const JSCallbackInfo& info)
126 {
127 bool isCloseEffect = true;
128 if (info[0]->IsBoolean()) {
129 isCloseEffect = info[0]->ToBoolean();
130 }
131 DataPanelModel::GetInstance()->SetEffect(isCloseEffect);
132 }
133
ValueColors(const JSCallbackInfo & info)134 void JSDataPanel::ValueColors(const JSCallbackInfo& info)
135 {
136 if (info.Length() < 1) {
137 return;
138 }
139
140 std::vector<OHOS::Ace::NG::Gradient> valueColors;
141 if (!info[0]->IsArray() || info[0]->IsEmpty()) {
142 ConvertThemeColor(valueColors);
143 DataPanelModel::GetInstance()->SetValueColors(valueColors);
144 return;
145 }
146
147 auto paramArray = JSRef<JSArray>::Cast(info[0]);
148 size_t length = paramArray->Length();
149 size_t count = std::min(length, MAX_COUNT);
150 for (size_t i = 0; i < count; ++i) {
151 auto item = paramArray->GetValueAt(i);
152 OHOS::Ace::NG::Gradient gradient;
153 if (!ConvertGradientColor(item, gradient)) {
154 valueColors.clear();
155 ConvertThemeColor(valueColors);
156 break;
157 }
158 valueColors.emplace_back(gradient);
159 }
160 DataPanelModel::GetInstance()->SetValueColors(valueColors);
161 }
162
TrackBackground(const JSCallbackInfo & info)163 void JSDataPanel::TrackBackground(const JSCallbackInfo& info)
164 {
165 if (info.Length() < 1) {
166 return;
167 }
168 Color color;
169 if (!ParseJsColor(info[0], color)) {
170 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
171 color = theme->GetBackgroundColor();
172 }
173
174 DataPanelModel::GetInstance()->SetTrackBackground(color);
175 }
176
StrokeWidth(const JSCallbackInfo & info)177 void JSDataPanel::StrokeWidth(const JSCallbackInfo& info)
178 {
179 if (info.Length() < 1) {
180 return;
181 }
182
183 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
184 CalcDimension strokeWidthDimension;
185 if (!ParseJsDimensionVp(info[0], strokeWidthDimension)) {
186 strokeWidthDimension = theme->GetThickness();
187 }
188
189 // If the parameter value is string(''), parse result 0.
190 // The value of 0 is allowed, but the value of string('') is not allowed, so use theme value.
191 if (info[0]->IsString() && (info[0]->ToString().empty() || !StringUtils::StringToDimensionWithUnitNG(
192 info[0]->ToString(), strokeWidthDimension))) {
193 strokeWidthDimension = theme->GetThickness();
194 }
195
196 if (strokeWidthDimension.IsNegative() || strokeWidthDimension.Unit() == DimensionUnit::PERCENT) {
197 strokeWidthDimension = theme->GetThickness();
198 }
199 DataPanelModel::GetInstance()->SetStrokeWidth(strokeWidthDimension);
200 }
201
ShadowOption(const JSCallbackInfo & info)202 void JSDataPanel::ShadowOption(const JSCallbackInfo& info)
203 {
204 OHOS::Ace::NG::DataPanelShadow shadow;
205 if (info[0]->IsNull()) {
206 shadow.isShadowVisible = false;
207 DataPanelModel::GetInstance()->SetShadowOption(shadow);
208 return;
209 }
210 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
211 double radius = theme->GetTrackShadowRadius().ConvertToVp();
212 double offsetX = theme->GetTrackShadowOffsetX().ConvertToVp();
213 double offsetY = theme->GetTrackShadowOffsetY().ConvertToVp();
214 std::vector<OHOS::Ace::NG::Gradient> shadowColors;
215 ConvertThemeColor(shadowColors);
216 if (info[0]->IsObject()) {
217 auto paramObject = JSRef<JSObject>::Cast(info[0]);
218 JSRef<JSVal> jsRadius = paramObject->GetProperty("radius");
219 JSRef<JSVal> jsOffsetX = paramObject->GetProperty("offsetX");
220 JSRef<JSVal> jsOffsetY = paramObject->GetProperty("offsetY");
221 ParseJsDouble(jsRadius, radius);
222 if (NonPositive(radius)) {
223 radius = theme->GetTrackShadowRadius().ConvertToVp();
224 }
225 ParseJsDouble(jsOffsetX, offsetX);
226 ParseJsDouble(jsOffsetY, offsetY);
227
228 auto colors = paramObject->GetProperty("colors");
229 if (!colors->IsArray()) {
230 shadow.radius = radius;
231 shadow.offsetX = offsetX;
232 shadow.offsetY = offsetY;
233 shadow.colors = shadowColors;
234 DataPanelModel::GetInstance()->SetShadowOption(shadow);
235 return;
236 }
237 shadowColors.clear();
238 auto colorsArray = JSRef<JSArray>::Cast(colors);
239 for (size_t i = 0; i < colorsArray->Length(); ++i) {
240 auto item = colorsArray->GetValueAt(i);
241 OHOS::Ace::NG::Gradient gradient;
242 if (!ConvertGradientColor(item, gradient)) {
243 shadowColors.clear();
244 ConvertThemeColor(shadowColors);
245 break;
246 }
247 shadowColors.emplace_back(gradient);
248 }
249 }
250
251 shadow.radius = radius;
252 shadow.offsetX = offsetX;
253 shadow.offsetY = offsetY;
254 shadow.colors = shadowColors;
255 DataPanelModel::GetInstance()->SetShadowOption(shadow);
256 }
257
ConvertGradientColor(const JsiRef<JsiValue> & itemParam,OHOS::Ace::NG::Gradient & gradient)258 bool JSDataPanel::ConvertGradientColor(const JsiRef<JsiValue>& itemParam, OHOS::Ace::NG::Gradient& gradient)
259 {
260 if (!itemParam->IsObject()) {
261 return ConvertResourceColor(itemParam, gradient);
262 }
263
264 JSLinearGradient* jsLinearGradient = JSRef<JSObject>::Cast(itemParam)->Unwrap<JSLinearGradient>();
265 if (!jsLinearGradient) {
266 return ConvertResourceColor(itemParam, gradient);
267 }
268
269 size_t colorLength = jsLinearGradient->GetGradient().size();
270 if (colorLength == 0) {
271 return false;
272 }
273 for (size_t colorIndex = 0; colorIndex < colorLength; ++colorIndex) {
274 OHOS::Ace::NG::GradientColor gradientColor;
275 gradientColor.SetLinearColor(LinearColor(jsLinearGradient->GetGradient().at(colorIndex).first));
276 gradientColor.SetDimension(jsLinearGradient->GetGradient().at(colorIndex).second);
277 gradient.AddColor(gradientColor);
278 }
279 return true;
280 }
281
ConvertResourceColor(const JsiRef<JsiValue> & itemParam,OHOS::Ace::NG::Gradient & gradient)282 bool JSDataPanel::ConvertResourceColor(const JsiRef<JsiValue>& itemParam, OHOS::Ace::NG::Gradient& gradient)
283 {
284 Color color;
285 if (!ParseJsColor(itemParam, color)) {
286 return false;
287 }
288 OHOS::Ace::NG::GradientColor gradientColorStart;
289 gradientColorStart.SetLinearColor(LinearColor(color));
290 gradientColorStart.SetDimension(Dimension(0.0));
291 gradient.AddColor(gradientColorStart);
292 OHOS::Ace::NG::GradientColor gradientColorEnd;
293 gradientColorEnd.SetLinearColor(LinearColor(color));
294 gradientColorEnd.SetDimension(Dimension(1.0));
295 gradient.AddColor(gradientColorEnd);
296 return true;
297 }
298
ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient> & colors)299 void JSDataPanel::ConvertThemeColor(std::vector<OHOS::Ace::NG::Gradient>& colors)
300 {
301 RefPtr<DataPanelTheme> theme = GetTheme<DataPanelTheme>();
302 auto themeColors = theme->GetColorsArray();
303 for (const auto& item : themeColors) {
304 OHOS::Ace::NG::Gradient gradient;
305 OHOS::Ace::NG::GradientColor gradientColorStart;
306 gradientColorStart.SetLinearColor(LinearColor(item.first));
307 gradientColorStart.SetDimension(Dimension(0.0));
308 gradient.AddColor(gradientColorStart);
309 OHOS::Ace::NG::GradientColor gradientColorEnd;
310 gradientColorEnd.SetLinearColor(LinearColor(item.second));
311 gradientColorEnd.SetDimension(Dimension(1.0));
312 gradient.AddColor(gradientColorEnd);
313 colors.emplace_back(gradient);
314 }
315 }
316 } // namespace OHOS::Ace::Framework
317