1 /*
2 * Copyright (c) 2020-2021 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 "components/chart_component.h"
17 #include "ace_log.h"
18 #include "ace_mem_base.h"
19 #include "flex_layout.h"
20 #include "font/ui_font_header.h"
21 #include "keys.h"
22 #include "ui_chart.h"
23 #include "ui_circle_progress.h"
24
25 namespace OHOS {
26 namespace ACELite {
27 const char * const ChartComponent::DATA = "data";
28 const char * const ChartComponent::APPEND_SERIAL_INDEX = "serial";
29 const char * const ChartComponent::LINE = "line";
30 const char * const ChartComponent::BAR = "bar";
31 const char * const ChartComponent::FUNC_JS_API = "append";
32 const char * const ChartComponent::STROKE_COLOR = "strokeColor";
33 const char * const ChartComponent::STROKE_WIDTH = "strokeWidth";
34 const char * const ChartComponent::FILL_COLOR = "fillColor";
35 const char * const ChartComponent::GRADIENT = "gradient";
36 const char * const ChartComponent::LINE_STYLE = "lineStyle";
37 const char * const ChartComponent::SMOOTH = "smooth";
38 const char * const ChartComponent::HEAD_POINT = "headPoint";
39 const char * const ChartComponent::SHAPE = "shape";
40 const char * const ChartComponent::SIZE = "size";
41 const char * const ChartComponent::TOP_POINT = "topPoint";
42 const char * const ChartComponent::BOTTOM_POINT = "bottomPoint";
43 const char * const ChartComponent::X_AXIS = "xAxis";
44 const char * const ChartComponent::Y_AXIS = "yAxis";
45 const char * const ChartComponent::MIN = "min";
46 const char * const ChartComponent::MAX = "max";
47 const char * const ChartComponent::TYPE = "type";
48 const char * const ChartComponent::SERIES = "series";
49 const char * const ChartComponent::COLOR = "color";
50 const char * const ChartComponent::WIDTH = "width";
51 const char * const ChartComponent::LOOP = "loop";
52 const char * const ChartComponent::MARGIN = "margin";
53 const char * const ChartComponent::DISPLAY = "display";
54
ChartComponent(jerry_value_t options,jerry_value_t children,AppStyleManager * styleManager)55 ChartComponent::ChartComponent(jerry_value_t options, jerry_value_t children, AppStyleManager* styleManager)
56 : Component(options, children, styleManager),
57 xAxis_(nullptr),
58 yAxis_(nullptr),
59 yMinValue_(0),
60 yMaxValue_(0),
61 xMinValue_(0),
62 xMaxValue_(0),
63 options_(options),
64 chartView_(nullptr),
65 serials_(nullptr),
66 totalSerialsNum_(0),
67 dataSetsRecord_(UNDEFINED),
68 seriesOptions_(nullptr),
69 chartType_(const_cast<char *>(LINE)),
70 headPointStyle_(nullptr),
71 topPointStyle_(nullptr),
72 bottomPointStyle_(nullptr)
73 {
74 }
75
CreateNativeViews()76 bool ChartComponent::CreateNativeViews()
77 {
78 jerry_value_t attrsPropValue = jerryx_get_property_str(options_, ATTR_ATTRS);
79 jerry_value_t typeStrHandler = jerry_create_string(reinterpret_cast<const jerry_char_t *>(TYPE));
80 jerry_value_t hasTypeProp = jerry_has_property(attrsPropValue, typeStrHandler);
81 if (jerry_get_boolean_value(hasTypeProp)) {
82 jerry_value_t typeValHandler = jerry_get_property(attrsPropValue, typeStrHandler);
83 char *type = MallocStringOf(typeValHandler);
84 jerry_release_value(typeValHandler);
85 if ((type != nullptr) && !strcmp(type, BAR)) {
86 chartView_ = new UIChartPillar();
87 chartType_ = const_cast<char *>(BAR);
88 }
89 ACE_FREE(type);
90 }
91 ReleaseJerryValue(hasTypeProp, typeStrHandler, attrsPropValue, VA_ARG_END_FLAG);
92 if (!strcmp(chartType_, LINE)) {
93 if (chartView_ != nullptr) {
94 delete (chartView_);
95 chartView_ = nullptr;
96 }
97 chartView_ = new UIChartPolyline();
98 }
99 if (chartView_ == nullptr) {
100 HILOG_ERROR(HILOG_MODULE_ACE, "create chart view error");
101 return false;
102 }
103 return Init();
104 }
105
SetPrivateAttribute(uint16_t attrKeyId,jerry_value_t attrValue)106 bool ChartComponent::SetPrivateAttribute(uint16_t attrKeyId, jerry_value_t attrValue)
107 {
108 if ((chartView_ == nullptr) || !KeyParser::IsKeyValid(attrKeyId) || IS_UNDEFINED(attrValue)) {
109 HILOG_ERROR(HILOG_MODULE_ACE, "chart view has not been created");
110 return false;
111 }
112 bool result = true;
113 switch (attrKeyId) {
114 case K_DATASETS: {
115 dataSetsRecord_ = attrValue;
116 break;
117 }
118 case K_OPTIONS: {
119 result = SetOptions(attrValue);
120 break;
121 }
122 default: {
123 result = false;
124 break;
125 }
126 }
127 return result;
128 }
129
PostUpdate(uint16_t attrKeyId)130 void ChartComponent::PostUpdate(uint16_t attrKeyId)
131 {
132 UNUSED(attrKeyId);
133 chartView_->ClearDataSerial();
134 chartView_->Invalidate();
135 ClearAllDataSerials();
136 Reset();
137 PostRender();
138 }
139
PostRender()140 void ChartComponent::PostRender()
141 {
142 uint8_t serialsCount = jerry_get_array_length(dataSetsRecord_);
143 jerry_value_t data = jerry_create_string(reinterpret_cast<const jerry_char_t *>(DATA));
144 UpdateData(dataSetsRecord_, data, serialsCount);
145 jerry_release_value(data);
146 chartView_->Invalidate();
147 }
148
ReleaseNativeViews()149 void ChartComponent::ReleaseNativeViews()
150 {
151 if (chartView_) {
152 delete (chartView_);
153 chartView_ = nullptr;
154 }
155 ClearAllDataSerials();
156 if (seriesOptions_ != nullptr) {
157 if (seriesOptions_->head) {
158 delete(seriesOptions_->head);
159 seriesOptions_->head = nullptr;
160 }
161 if (seriesOptions_->top) {
162 delete(seriesOptions_->top);
163 seriesOptions_->top = nullptr;
164 }
165 if (seriesOptions_->bottom) {
166 delete(seriesOptions_->bottom);
167 seriesOptions_->bottom = nullptr;
168 }
169 delete(seriesOptions_);
170 seriesOptions_ = nullptr;
171 }
172 if (headPointStyle_ != nullptr) {
173 delete(headPointStyle_);
174 headPointStyle_ = nullptr;
175 }
176 if (topPointStyle_ != nullptr) {
177 delete(topPointStyle_);
178 topPointStyle_ = nullptr;
179 }
180 if (bottomPointStyle_ != nullptr) {
181 delete(bottomPointStyle_);
182 bottomPointStyle_ = nullptr;
183 }
184 }
185
GetComponentRootView() const186 inline UIView *ChartComponent::GetComponentRootView() const
187 {
188 return chartView_;
189 }
190
UpdateStrokeColorToSerial(jerry_value_t dataSet,UIChartDataSerial & dataserial)191 void ChartComponent::UpdateStrokeColorToSerial(jerry_value_t dataSet, UIChartDataSerial &dataserial)
192 {
193 if (!strcmp(chartType_, BAR)) {
194 HILOG_WARN(HILOG_MODULE_ACE, "bar not support stroke color set");
195 return;
196 }
197 UpdateColorToSerial(dataSet, dataserial, true);
198 }
199
UpdateFillColorToSerial(jerry_value_t dataSet,UIChartDataSerial & dataserial)200 void ChartComponent::UpdateFillColorToSerial(jerry_value_t dataSet, UIChartDataSerial& dataserial)
201 {
202 UpdateColorToSerial(dataSet, dataserial, false);
203 }
204
UpdateStrokeSmoothToSerial(UIChartDataSerial & dataserial)205 void ChartComponent::UpdateStrokeSmoothToSerial(UIChartDataSerial& dataserial)
206 {
207 dataserial.EnableSmooth(seriesOptions_->smooth);
208 }
209
UpdatePointStyle(UIChartDataSerial::PointStyle * pointStyle,uint32_t fillColor,uint32_t strokeColor,uint32_t radius,uint32_t strokeWidth)210 UIChartDataSerial::PointStyle *ChartComponent::UpdatePointStyle(UIChartDataSerial::PointStyle *pointStyle,
211 uint32_t fillColor, uint32_t strokeColor, uint32_t radius, uint32_t strokeWidth)
212 {
213 if (pointStyle == nullptr) {
214 pointStyle = new UIChartDataSerial::PointStyle();
215 if (pointStyle == nullptr) {
216 return nullptr;
217 }
218 }
219 pointStyle->fillColor = GetRGBColor(fillColor);
220 pointStyle->strokeColor = GetRGBColor(strokeColor);
221 pointStyle->radius = radius;
222 pointStyle->strokeWidth = strokeWidth;
223 return pointStyle;
224 }
225
UpdatePointToSerial(UIChartDataSerial * dataserial,PointType type)226 bool ChartComponent::UpdatePointToSerial(UIChartDataSerial* dataserial, PointType type)
227 {
228 switch (type) {
229 case PointType::HEAD: {
230 headPointStyle_ = UpdatePointStyle(headPointStyle_, seriesOptions_->head->fillColor,
231 seriesOptions_->head->strokeColor, seriesOptions_->head->size, seriesOptions_->head->strokeWidth);
232 if (headPointStyle_ == nullptr) {
233 HILOG_ERROR(HILOG_MODULE_ACE, "malloc headPointStyle heap error");
234 return false;
235 }
236 dataserial->SetHeadPointStyle(*headPointStyle_);
237 break;
238 }
239 case PointType::TOP: {
240 topPointStyle_ = UpdatePointStyle(topPointStyle_, seriesOptions_->top->fillColor,
241 seriesOptions_->top->strokeColor, seriesOptions_->top->size, seriesOptions_->top->strokeWidth);
242 if (topPointStyle_ == nullptr) {
243 HILOG_ERROR(HILOG_MODULE_ACE, "malloc topPointStyle heap error");
244 return false;
245 }
246 dataserial->SetTopPointStyle(*topPointStyle_);
247 break;
248 }
249 case PointType::BOTTOM: {
250 bottomPointStyle_ = UpdatePointStyle(bottomPointStyle_,
251 seriesOptions_->bottom->fillColor, seriesOptions_->bottom->strokeColor,
252 seriesOptions_->bottom->size, seriesOptions_->bottom->strokeWidth);
253 if (bottomPointStyle_ == nullptr) {
254 HILOG_ERROR(HILOG_MODULE_ACE, "malloc bottomPointStyle heap error");
255 return false;
256 }
257 dataserial->SetBottomPointStyle(*bottomPointStyle_);
258 break;
259 }
260 default: {
261 break;
262 }
263 }
264 return true;
265 }
266
UpdatePoints(UIChartDataSerial * dataserial)267 bool ChartComponent::UpdatePoints(UIChartDataSerial* dataserial)
268 {
269 if (seriesOptions_->isTopSet) {
270 if (!UpdatePointToSerial(dataserial, PointType::TOP)) {
271 return false;
272 }
273 dataserial->EnableTopPoint(true);
274 } else {
275 dataserial->EnableTopPoint(false);
276 }
277 if (seriesOptions_->isHeadSet) {
278 if (!UpdatePointToSerial(dataserial, PointType::HEAD)) {
279 return false;
280 }
281 dataserial->EnableHeadPoint(true);
282 } else {
283 dataserial->EnableHeadPoint(false);
284 }
285 if (seriesOptions_->isBottomSet) {
286 if (!UpdatePointToSerial(dataserial, PointType::BOTTOM)) {
287 return false;
288 }
289 dataserial->EnableBottomPoint(true);
290 } else {
291 dataserial->EnableBottomPoint(false);
292 }
293 return true;
294 }
295
UpdateGradientToSerial(jerry_value_t dataSet,UIChartDataSerial * dataserial)296 void ChartComponent::UpdateGradientToSerial(jerry_value_t dataSet, UIChartDataSerial* dataserial)
297 {
298 jerry_value_t jNeedGradient = jerry_create_string(reinterpret_cast<jerry_char_t *>(const_cast<char *>(GRADIENT)));
299 jerry_value_t hasGradientProperty = jerry_has_property(dataSet, jNeedGradient);
300 if (hasGradientProperty) {
301 bool needGradient = jerry_get_boolean_value(jerry_get_property(dataSet, jNeedGradient));
302 if (!strcmp(chartType_, LINE) && needGradient) {
303 dataserial->EnableGradient(true);
304 }
305 }
306 ReleaseJerryValue(hasGradientProperty, jNeedGradient, VA_ARG_END_FLAG);
307 }
308
UpdateValuesToSerial(jerry_value_t dataSet,UIChartDataSerial * dataserial,uint16_t dataLen)309 bool ChartComponent::UpdateValuesToSerial(jerry_value_t dataSet, UIChartDataSerial* dataserial, uint16_t dataLen)
310 {
311 bool isSetOk = true;
312 jerry_value_t jData = jerry_create_string(reinterpret_cast<const jerry_char_t *>(DATA));
313 jerry_value_t hasDataProp = jerry_has_property(dataSet, jData);
314 if (hasDataProp) {
315 jerry_value_t jDataValue = jerry_get_property(dataSet, jData);
316 uint16_t len = 0;
317 if (!strcmp(chartType_, BAR)) {
318 len = jerry_get_array_length(jDataValue);
319 } else {
320 if ((xMaxValue_ >= (UINT16_MAX - 1)) || (dataLen < xMinValue_)) {
321 HILOG_WARN(HILOG_MODULE_ACE, "customMaxCount or customMinValue is set out of boundary");
322 }
323 uint16_t customMaxCount = xMaxValue_ + 1; // the max data count specified by user
324 uint16_t actualMaxCount = dataLen - xMinValue_; // the actual max data count setted in data array
325 len = (customMaxCount < actualMaxCount) ? customMaxCount : actualMaxCount;
326 }
327 if (isSetOk) {
328 Point* pointArray = (len > 0) ? (static_cast<Point *>(ace_malloc(sizeof(Point) * len))) : nullptr;
329 if (pointArray == nullptr) {
330 HILOG_ERROR(HILOG_MODULE_ACE, "malloc point array memory heap failed");
331 isSetOk = false;
332 } else {
333 for (int i = 0; i < len; i++) {
334 pointArray[i] = { 0, 0 };
335 }
336 uint16_t interval = 0;
337 ParseDataValue(jDataValue, interval, pointArray, len);
338 dataserial->AddPoints(pointArray, len);
339 chartView_->AddDataSerial(dataserial);
340 ace_free(pointArray);
341 pointArray = nullptr;
342 }
343 }
344 jerry_release_value(jDataValue);
345 } else {
346 HILOG_ERROR(HILOG_MODULE_ACE, "data not set");
347 isSetOk = false;
348 }
349 ReleaseJerryValue(hasDataProp, jData, VA_ARG_END_FLAG);
350 // need to set after datas setted
351 return (isSetOk ? UpdatePoints(dataserial) : false);
352 }
353
AppendValuesToSerial(jerry_value_t dataSet,UIChartDataSerial * dataserial,uint16_t dataLen)354 bool ChartComponent::AppendValuesToSerial(jerry_value_t dataSet, UIChartDataSerial* dataserial, uint16_t dataLen)
355 {
356 if (dataserial == nullptr) {
357 HILOG_ERROR(HILOG_MODULE_ACE, "dataserial is null");
358 return false;
359 }
360 bool isSetOk = true;
361 jerry_value_t jData = jerry_create_string(reinterpret_cast<const jerry_char_t *>("data"));
362 jerry_value_t hasDataProp = jerry_has_property(dataSet, jData);
363 if (hasDataProp) {
364 jerry_value_t jDataValue = dataSet;
365 uint16_t interval = dataserial->GetDataCount();
366 Point* pointArray = (dataLen > 0) ? (static_cast<Point *>(ace_malloc(sizeof(Point) * dataLen))) : nullptr;
367 if (pointArray == nullptr) {
368 HILOG_ERROR(HILOG_MODULE_ACE, "malloc point array memory heap failed!");
369 isSetOk = false;
370 } else {
371 for (int i = 0; i < dataLen; i++) {
372 pointArray[i] = { 0, 0 };
373 }
374 ParseDataValue(jDataValue, interval, pointArray, dataLen);
375 AppendValues(*dataserial, pointArray, dataLen);
376 chartView_->RefreshChart();
377 ace_free(pointArray);
378 pointArray = nullptr;
379 }
380 } else {
381 HILOG_ERROR(HILOG_MODULE_ACE, "data not set!");
382 isSetOk = false;
383 }
384 ReleaseJerryValue(hasDataProp, jData, VA_ARG_END_FLAG);
385 return isSetOk;
386 }
387
AppendValues(UIChartDataSerial & dataserial,Point * pointArray,uint16_t dataLen)388 void ChartComponent::AppendValues(UIChartDataSerial& dataserial, Point* pointArray, uint16_t dataLen)
389 {
390 if (!(seriesOptions_->isLoopSet)) {
391 dataserial.AddPoints(pointArray, dataLen);
392 return;
393 }
394 // the index of the latest updated point (include add or modify)
395 uint16_t latestIndex = dataserial.GetLatestIndex();
396 // the length that will become after adding new data
397 uint16_t expectedDatasLen = latestIndex + dataLen + 1;
398 if ((dataLen == UINT16_MAX) || (UINT16_MAX - latestIndex) < (dataLen + 1)) {
399 HILOG_ERROR(HILOG_MODULE_ACE, "dataLen out of boundary");
400 return;
401 }
402 // the amount of data already in the current data series
403 uint16_t existingDataLen = dataserial.GetDataCount();
404 if (expectedDatasLen > (xMaxValue_ + 1)) {
405 if (latestIndex < existingDataLen - 1) {
406 // means need to modify the value between lastestIndex and existingDataLen
407 for (uint16_t i = 0; i < xMaxValue_ - latestIndex; i++) {
408 if (i >= dataLen) {
409 HILOG_ERROR(HILOG_MODULE_ACE, "append data error1");
410 return;
411 }
412 pointArray[i].x = i + latestIndex + 1;
413 dataserial.ModifyPoint(i + latestIndex + 1, pointArray[i]);
414 dataserial.HidePoint(i + latestIndex + 1, seriesOptions_->margin);
415 }
416 } else { // means need to add new data to the series
417 dataserial.AddPoints(pointArray, xMaxValue_ - latestIndex);
418 }
419 // Get the data set beyond the screen, and replace the existing data in the sequence one by one
420 // from the beginning
421 chartView_->RefreshChart();
422 for (uint16_t i = 0; i < (expectedDatasLen - (xMaxValue_ + 1)); i++) {
423 if (((xMaxValue_ - latestIndex) + i) >= dataLen) {
424 HILOG_ERROR(HILOG_MODULE_ACE, "append data error2");
425 return;
426 }
427 pointArray[(xMaxValue_ - latestIndex) + i].x = i;
428 dataserial.ModifyPoint(i, pointArray[(xMaxValue_ - latestIndex) + i]);
429 dataserial.HidePoint(i, seriesOptions_->margin);
430 }
431 } else { // after adding data, the length will not exceed the maximum value of the x axis
432 if (latestIndex < existingDataLen - 1) {
433 // means need to modify the value between lastestIndex and dataLen
434 for (uint16_t i = 0; i < dataLen; i++) {
435 pointArray[i].x = latestIndex + 1 + i;
436 dataserial.ModifyPoint(latestIndex + 1 + i, pointArray[i]);
437 dataserial.HidePoint(i + latestIndex + 1, seriesOptions_->margin);
438 }
439 } else { // means need to add new data to the series
440 dataserial.AddPoints(pointArray, dataLen);
441 }
442 }
443 }
444
ParseDataValue(jerry_value_t dataValue,uint16_t interval,Point * pointArray,uint16_t arrayLen)445 bool ChartComponent::ParseDataValue(jerry_value_t dataValue, uint16_t interval, Point* pointArray, uint16_t arrayLen)
446 {
447 for (size_t index = 0; index < arrayLen; index++) {
448 // interval == 0 means update series, otherwise means append data to series
449 jerry_value_t data = (interval == 0) ? jerry_get_property_by_index(dataValue, (index + xMinValue_)) :
450 jerry_get_property_by_index(dataValue, index);
451 if (!jerry_value_is_number(data)) {
452 jerry_release_value(data);
453 HILOG_ERROR(HILOG_MODULE_ACE, "chart data is not a number");
454 return false;
455 }
456 size_t dataValue = static_cast<size_t>(jerry_get_number_value(data));
457 pointArray[index].x = (index + interval);
458 if (dataValue < yMinValue_) {
459 HILOG_WARN(HILOG_MODULE_ACE, "the value %{public}d is less than min value, and will use minValue instead",
460 dataValue);
461 pointArray[index].y = yMinValue_;
462 } else if (dataValue > yMaxValue_) {
463 HILOG_WARN(HILOG_MODULE_ACE, "the value %{public}d is larger than max value, and will use maxValue instead",
464 dataValue);
465 pointArray[index].y = yMaxValue_;
466 } else {
467 pointArray[index].y = dataValue;
468 }
469 jerry_release_value(data);
470 }
471 return true;
472 }
473
AppendDatas(const jerry_value_t func,const jerry_value_t context,const jerry_value_t * args,const jerry_length_t argsNum)474 jerry_value_t ChartComponent::AppendDatas(const jerry_value_t func,
475 const jerry_value_t context,
476 const jerry_value_t *args,
477 const jerry_length_t argsNum)
478 {
479 uint8_t functionParamsNum = 1; // js append function just receive 1 number params
480 if (argsNum != functionParamsNum) {
481 HILOG_ERROR(HILOG_MODULE_ACE, "append function params error");
482 } else {
483 if (jerry_value_is_undefined(args[0])) {
484 HILOG_ERROR(HILOG_MODULE_ACE, "append function params error");
485 return UNDEFINED;
486 }
487 jerry_value_t jAppendDataObj = args[0];
488 uint8_t serialIndex = JerryGetIntegerProperty(jAppendDataObj, APPEND_SERIAL_INDEX);
489 jerry_value_t jDatas = jerryx_get_property_str(jAppendDataObj, DATA);
490 ChartComponent* chartComponent = ChartComponent::GetChartComponent(context);
491 if (chartComponent != nullptr) {
492 DataSerials* tarSerial = const_cast<DataSerials *>(GetDataSerial(chartComponent, serialIndex));
493 if (tarSerial != nullptr) {
494 chartComponent->AppendData(jDatas, tarSerial);
495 }
496 }
497 jerry_release_value(jDatas);
498 }
499 return UNDEFINED;
500 }
501
SetOptions(jerry_value_t options)502 bool ChartComponent::SetOptions(jerry_value_t options)
503 {
504 if (!SetOptionsAxis(options, true)) {
505 return false;
506 }
507 if (!SetOptionsAxis(options, false)) {
508 return false;
509 }
510 RecordOptionsSeries(options);
511 return true;
512 }
513
UpdateData(jerry_value_t dataSets,jerry_value_t keyName,uint8_t serialsCount)514 void ChartComponent::UpdateData(jerry_value_t dataSets, jerry_value_t keyName, uint8_t serialsCount)
515 {
516 if (serials_ != nullptr) {
517 chartView_->ClearDataSerial();
518 ClearAllDataSerials(); // clear all data serials
519 }
520 bool isSetOk = false;
521 for (uint8_t index = 0; index < serialsCount; index++) { // every data set
522 jerry_value_t dataSet = jerry_get_property_by_index(dataSets, index);
523 // check data is set correctly, if the data is not set correctly, need not to set other attribute left
524 jerry_value_t dataValue = jerry_get_property(dataSet, keyName);
525 if ((!jerry_value_is_undefined(dataValue)) && jerry_value_is_array(dataValue)) {
526 uint16_t dataLen = jerry_get_array_length(dataValue);
527 // add to serial linked list, delete all before next update or component finish
528 DataSerials* dataSerialNode = new DataSerials();
529 if (dataSerialNode == nullptr) {
530 HILOG_ERROR(HILOG_MODULE_ACE, "new dataSerialNode memory heap fail");
531 ReleaseJerryValue(dataValue, dataSet, VA_ARG_END_FLAG);
532 break;
533 }
534 AddDataSerial(dataSerialNode);
535 // create dataserial
536 uint16_t dataCount = 0;
537 if (!strcmp(chartType_, BAR)) {
538 jerry_value_t jData = jerry_create_string(reinterpret_cast<const jerry_char_t *>(DATA));
539 jerry_value_t jDataValue = jerry_get_property(dataSet, jData);
540 dataCount = jerry_get_array_length(jDataValue);
541 ReleaseJerryValue(jDataValue, jData, VA_ARG_END_FLAG);
542 } else {
543 dataCount = xMaxValue_ + 1;
544 }
545 UIChartDataSerial* dataserial = new UIChartDataSerial();
546 if (dataserial == nullptr) {
547 HILOG_ERROR(HILOG_MODULE_ACE, "new UIChartDataSerial memory heap fail");
548 ReleaseJerryValue(dataValue, dataSet, VA_ARG_END_FLAG);
549 break;
550 }
551 dataserial->SetMaxDataCount(dataCount);
552 dataSerialNode->dataSerial = dataserial;
553 isSetOk = UpdataDataInOrder(dataSet, *dataserial, dataLen);
554 } else {
555 HILOG_ERROR(HILOG_MODULE_ACE, "chart data is not defined or is not array");
556 }
557 ReleaseJerryValue(dataValue, dataSet, VA_ARG_END_FLAG);
558 if (!isSetOk) {
559 break;
560 }
561 }
562 }
563
UpdataDataInOrder(jerry_value_t dataSet,UIChartDataSerial & dataserial,uint16_t dataLen)564 bool ChartComponent::UpdataDataInOrder(jerry_value_t dataSet, UIChartDataSerial& dataserial, uint16_t dataLen)
565 {
566 UpdateStrokeColorToSerial(dataSet, dataserial);
567 UpdateFillColorToSerial(dataSet, dataserial);
568 UpdateGradientToSerial(dataSet, &dataserial);
569 UpdateStrokeSmoothToSerial(dataserial);
570 return UpdateValuesToSerial(dataSet, &dataserial, dataLen);
571 }
572
AppendData(jerry_value_t dataSet,DataSerials * dataSerialNode)573 void ChartComponent::AppendData(jerry_value_t dataSet, DataSerials* dataSerialNode)
574 {
575 if (dataSerialNode == nullptr) {
576 HILOG_ERROR(HILOG_MODULE_ACE, "data serial is null");
577 return;
578 }
579 if (!strcmp(chartType_, BAR)) {
580 HILOG_WARN(HILOG_MODULE_ACE, "bar not support append data");
581 return;
582 }
583 uint16_t dataLen = jerry_get_array_length(dataSet);
584 AppendValuesToSerial(dataSet, dataSerialNode->dataSerial, dataLen);
585 }
586
UpdateColorToSerial(jerry_value_t dataSet,UIChartDataSerial & dataserial,bool isStrokeColor)587 void ChartComponent::UpdateColorToSerial(jerry_value_t dataSet, UIChartDataSerial& dataserial, bool isStrokeColor)
588 {
589 bool isColorSet = false;
590 const char* styleName = isStrokeColor ? STROKE_COLOR : FILL_COLOR;
591 if (jerryx_has_property_str(dataSet, styleName)) {
592 isColorSet = true;
593 } else {
594 // Compatible with old versions (chart1.0)
595 styleName = COMMON_STYLE_BACKGROUND_COLOR;
596 if (jerryx_has_property_str(dataSet, styleName)) {
597 isColorSet = true;
598 }
599 }
600 const uint32_t defaultColorVal = 0xFF6384; // pink
601 uint32_t colorVal = defaultColorVal;
602 if (isColorSet) {
603 colorVal = GetColor(dataSet, const_cast<char *>(styleName), defaultColorVal);
604 }
605 ColorType bgColor = GetRGBColor(colorVal);
606 if (isStrokeColor) {
607 dataserial.SetLineColor(bgColor);
608 } else {
609 dataserial.SetFillColor(bgColor);
610 }
611 }
612
SetOptionsAxis(jerry_value_t attrValue,bool isXAxis)613 bool ChartComponent::SetOptionsAxis(jerry_value_t attrValue, bool isXAxis)
614 {
615 bool isSetOk = false;
616 jerry_value_t jAxisName = jerry_create_string(reinterpret_cast<const jerry_char_t *>(isXAxis ? X_AXIS : Y_AXIS));
617 jerry_value_t hasXAxisProp = jerry_has_property(attrValue, jAxisName);
618 if (!jerry_get_boolean_value(hasXAxisProp)) {
619 HILOG_ERROR(HILOG_MODULE_ACE, "xAxis and yAxis param must set");
620 } else {
621 jerry_value_t axisValue = jerry_get_property(attrValue, jAxisName);
622 isSetOk = SetOptionsAxisDataRange(axisValue, isXAxis);
623 if (isSetOk) {
624 SetOptionsAxisTick(axisValue, isXAxis);
625 isSetOk = SetOptionsAxisDisplay(axisValue, isXAxis);
626 }
627 if (isSetOk) {
628 SetOptionsAxisColor(axisValue, isXAxis);
629 }
630 jerry_release_value(axisValue);
631 }
632 ReleaseJerryValue(jAxisName, hasXAxisProp, VA_ARG_END_FLAG);
633 return isSetOk;
634 }
635
SetOptionsAxisDataRange(jerry_value_t xAxisValue,bool isXAxis)636 bool ChartComponent::SetOptionsAxisDataRange(jerry_value_t xAxisValue, bool isXAxis)
637 {
638 bool isSetOk = true;
639 const uint8_t defaultMinValue = 0;
640 const uint8_t defaultMaxValue = 100;
641 jerry_value_t jMinValue = jerryx_get_property_str(xAxisValue, MIN);
642 jerry_value_t jMaxValue = jerryx_get_property_str(xAxisValue, MAX);
643 double tempMinVal = jerry_get_number_value(jMinValue);
644 double tempMaxVal = jerry_get_number_value(jMaxValue);
645 uint16_t minValue = defaultMinValue;
646 uint16_t maxValue = defaultMaxValue;
647 if ((tempMinVal >= 0) && (tempMinVal <= UINT16_MAX)) {
648 minValue = static_cast<uint16_t>(tempMinVal);
649 }
650 if ((tempMaxVal >= 0) && (tempMaxVal <= UINT16_MAX)) {
651 maxValue = static_cast<uint16_t>(tempMaxVal);
652 }
653
654 if (maxValue == 0) {
655 if (!jerryx_has_property_str(xAxisValue, "max")) {
656 HILOG_WARN(HILOG_MODULE_ACE,
657 "max value is not defined, and will use default value %{public}d instead", defaultMaxValue);
658 maxValue = defaultMaxValue;
659 }
660 }
661 if (isXAxis) {
662 if (!strcmp(chartType_, BAR)) {
663 xAxis_->SetDataRange(0, 0);
664 } else {
665 isSetOk = SetOptionsAxisDataRange(minValue, maxValue, defaultMinValue, defaultMaxValue, true);
666 }
667 } else {
668 isSetOk = SetOptionsAxisDataRange(minValue, maxValue, defaultMinValue, defaultMaxValue, false);
669 }
670 ReleaseJerryValue(jMinValue, jMaxValue, VA_ARG_END_FLAG);
671 return isSetOk;
672 }
673
SetOptionsAxisDataRange(uint16_t minValue,uint16_t maxValue,uint8_t defaultMinValue,uint8_t defaultMaxValue,bool isXaxis)674 bool ChartComponent::SetOptionsAxisDataRange(uint16_t minValue, uint16_t maxValue, uint8_t defaultMinValue,
675 uint8_t defaultMaxValue, bool isXaxis)
676 {
677 bool isSetOk = true;
678 uint8_t supportMinValue = 0;
679 uint16_t supportedMaxValue = 65535;
680 const char * const xOrY = isXaxis ? "x" : "y";
681 if ((minValue < supportMinValue) || (minValue > supportedMaxValue)) {
682 HILOG_WARN(HILOG_MODULE_ACE,
683 "%{public}s min value: %{public}d is not between %{public}d ~ %{public}d, and will use default "
684 "value %{public}d instead",
685 xOrY, minValue, supportMinValue, supportedMaxValue, defaultMinValue);
686 minValue = defaultMinValue;
687 }
688 if ((maxValue < supportMinValue) || (maxValue > supportedMaxValue)) {
689 HILOG_WARN(HILOG_MODULE_ACE,
690 "%{public}s max value: %{public}d is not between %{public}d ~ %{public}d, and will use default "
691 "value %{public}d instead",
692 xOrY, maxValue, supportMinValue, supportedMaxValue, defaultMaxValue);
693 maxValue = defaultMaxValue;
694 }
695 if (minValue > maxValue) {
696 HILOG_WARN(HILOG_MODULE_ACE, "%{public}s min value is larger than max value, we will use default value", xOrY);
697 maxValue = defaultMaxValue;
698 minValue = defaultMinValue;
699 }
700 if (isXaxis) {
701 xAxis_->SetDataRange(0, maxValue - minValue);
702 xMaxValue_ = maxValue - minValue;
703 xMinValue_ = minValue;
704 } else {
705 yAxis_->SetDataRange(minValue, maxValue);
706 yMinValue_ = minValue;
707 yMaxValue_ = maxValue;
708 }
709 return isSetOk;
710 }
711
SetOptionsAxisTick(jerry_value_t xAxisValue,bool isXAxis)712 void ChartComponent::SetOptionsAxisTick(jerry_value_t xAxisValue, bool isXAxis)
713 {
714 jerry_value_t jAxisTickValue = jerryx_get_property_str(xAxisValue, "axisTick");
715 double tempAxisTickVal = jerry_get_number_value(jAxisTickValue);
716 int16_t axisTickValue;
717 const int8_t minTickValue = 1;
718 const int8_t maxTickValue = 20;
719 if ((tempAxisTickVal < minTickValue) || (tempAxisTickVal > maxTickValue)) {
720 int16_t defaultValue = 10; // default value, means total number of ticks
721 axisTickValue = defaultValue;
722 } else {
723 axisTickValue = static_cast<int16_t>(tempAxisTickVal);
724 }
725 jerry_release_value(jAxisTickValue);
726 if (isXAxis) {
727 xAxis_->SetMarkNum(axisTickValue);
728 } else {
729 yAxis_->SetMarkNum(axisTickValue);
730 }
731 }
732
SetOptionsAxisDisplay(jerry_value_t xAxisValue,bool isXAxis)733 bool ChartComponent::SetOptionsAxisDisplay(jerry_value_t xAxisValue, bool isXAxis)
734 {
735 bool displayValue = false; // default value, means not show axis
736 jerry_value_t jDisplayValue = jerryx_get_property_str(xAxisValue, DISPLAY);
737 if (!jerry_value_is_undefined(jDisplayValue)) {
738 displayValue = jerry_get_boolean_value(jDisplayValue);
739 }
740 if (isXAxis) {
741 xAxis_->SetVisible(displayValue);
742 } else {
743 yAxis_->SetVisible(displayValue);
744 }
745 jerry_release_value(jDisplayValue);
746 return true;
747 }
748
SetOptionsAxisColor(jerry_value_t xAxisValue,bool isXAxis)749 void ChartComponent::SetOptionsAxisColor(jerry_value_t xAxisValue, bool isXAxis)
750 {
751 const char * const styleName = COLOR;
752 uint32_t color = 0xc0c0c0; // default color
753 if (jerryx_has_property_str(xAxisValue, styleName)) {
754 uint16_t len = 0;
755 char* styleValue = JerryMallocStringProperty(xAxisValue, styleName, len);
756 uint8_t alpha = 0;
757 (void)ParseColor(styleValue, color, alpha);
758 ACE_FREE(styleValue);
759 }
760 ColorType axisColor = GetRGBColor(color);
761 if (isXAxis) {
762 xAxis_->SetLineColor(axisColor);
763 } else {
764 yAxis_->SetLineColor(axisColor);
765 }
766 }
767
RecordOptionsSeries(jerry_value_t options)768 void ChartComponent::RecordOptionsSeries(jerry_value_t options)
769 {
770 if (jerryx_has_property_str(options, SERIES)) {
771 jerry_value_t jSeriesVal = jerryx_get_property_str(options, SERIES);
772 RecordOptionsSeriesLineStyle(jSeriesVal);
773 RecordOptionsSeriesPoint(jSeriesVal, PointType::HEAD);
774 RecordOptionsSeriesPoint(jSeriesVal, PointType::TOP);
775 RecordOptionsSeriesPoint(jSeriesVal, PointType::BOTTOM);
776 RecordOptionsSeriesLoop(jSeriesVal);
777 jerry_release_value(jSeriesVal);
778 }
779 }
780
RecordOptionsSeriesLineStyle(jerry_value_t jSeriesVal)781 void ChartComponent::RecordOptionsSeriesLineStyle(jerry_value_t jSeriesVal)
782 {
783 char* styleName = const_cast<char *>(LINE_STYLE);
784 if (!jerryx_has_property_str(jSeriesVal, styleName)) {
785 return;
786 }
787 jerry_value_t jLineStyleVal = jerryx_get_property_str(jSeriesVal, styleName);
788 styleName = const_cast<char *>(WIDTH);
789 uint16_t widthVal = GetSizeVal(jLineStyleVal, styleName, 1);
790 chartView_->SetStyle(STYLE_LINE_WIDTH, widthVal); // chart width set can affect all the series
791 seriesOptions_->width = widthVal;
792 styleName = const_cast<char *>(SMOOTH);
793 if (jerryx_has_property_str(jLineStyleVal, styleName)) {
794 jerry_value_t jSmoothVal = jerryx_get_property_str(jLineStyleVal, styleName);
795 seriesOptions_->smooth = jerry_get_boolean_value(jSmoothVal);
796 jerry_release_value(jSmoothVal);
797 }
798 jerry_release_value(jLineStyleVal);
799 }
800
RecordOptionsSeriesPoint(jerry_value_t jSeriesVal,PointType type)801 void ChartComponent::RecordOptionsSeriesPoint(jerry_value_t jSeriesVal, PointType type)
802 {
803 char* styleName = nullptr;
804 switch (type) {
805 case PointType::HEAD: {
806 styleName = const_cast<char *>(HEAD_POINT);
807 break;
808 }
809 case PointType::TOP: {
810 styleName = const_cast<char *>(TOP_POINT);
811 break;
812 }
813 case PointType::BOTTOM: {
814 styleName = const_cast<char *>(BOTTOM_POINT);
815 break;
816 }
817 default: {
818 break;
819 }
820 }
821 if ((styleName == nullptr) || !jerryx_has_property_str(jSeriesVal, styleName)) {
822 return;
823 }
824 SetOptionsInfo(jSeriesVal, type, styleName);
825 }
826
SetOptionsInfo(jerry_value_t jSeriesVal,PointType type,char * styleName)827 void ChartComponent::SetOptionsInfo(jerry_value_t jSeriesVal, PointType type, char* styleName)
828 {
829 jerry_value_t jPointStyleVal = jerryx_get_property_str(jSeriesVal, styleName);
830 styleName = const_cast<char *>(SIZE);
831 uint8_t defaultValue = 4;
832 uint8_t size = GetSizeVal(jPointStyleVal, styleName, defaultValue);
833 uint32_t defaultColorVal = 0xff0000;
834 styleName = const_cast<char *>(STROKE_COLOR);
835 uint32_t strokeColor = GetColor(jPointStyleVal, styleName, defaultColorVal);
836 defaultValue = 1;
837 styleName = const_cast<char *>(STROKE_WIDTH);
838 uint8_t strokeWidth = GetSizeVal(jPointStyleVal, styleName, defaultValue);
839 styleName = const_cast<char *>(FILL_COLOR);
840 uint32_t fillColor = GetColor(jPointStyleVal, styleName, defaultColorVal);
841 bool isDisplay = GetDisplayStatus(jPointStyleVal);
842
843 jerry_release_value(jPointStyleVal);
844 switch (type) {
845 case PointType::HEAD: {
846 seriesOptions_->isHeadSet = isDisplay;
847 seriesOptions_->head->size = size;
848 seriesOptions_->head->strokeColor = strokeColor;
849 seriesOptions_->head->fillColor = fillColor;
850 seriesOptions_->head->strokeWidth = strokeWidth;
851 break;
852 }
853 case PointType::TOP: {
854 seriesOptions_->isTopSet = isDisplay;
855 seriesOptions_->top->size = size;
856 seriesOptions_->top->strokeColor = strokeColor;
857 seriesOptions_->top->fillColor = fillColor;
858 seriesOptions_->top->strokeWidth = strokeWidth;
859 break;
860 }
861 case PointType::BOTTOM: {
862 seriesOptions_->isBottomSet = isDisplay;
863 seriesOptions_->bottom->size = size;
864 seriesOptions_->bottom->strokeColor = strokeColor;
865 seriesOptions_->bottom->fillColor = fillColor;
866 seriesOptions_->bottom->strokeWidth = strokeWidth;
867 break;
868 }
869 default: {
870 break;
871 }
872 }
873 }
874
RecordOptionsSeriesLoop(jerry_value_t jSeriesVal)875 void ChartComponent::RecordOptionsSeriesLoop(jerry_value_t jSeriesVal)
876 {
877 char* styleName = const_cast<char *>(LOOP);
878 if (!jerryx_has_property_str(jSeriesVal, styleName)) {
879 return;
880 }
881
882 jerry_value_t jLoopStyleVal = jerryx_get_property_str(jSeriesVal, styleName);
883 seriesOptions_->isLoopSet = GetDisplayStatus(jLoopStyleVal);
884
885 styleName = const_cast<char *>(MARGIN);
886 if (!jerryx_has_property_str(jLoopStyleVal, styleName)) {
887 seriesOptions_->margin = 1;
888 } else {
889 int16_t marginVal = JerryGetIntegerProperty(jLoopStyleVal, styleName);
890 seriesOptions_->margin = marginVal;
891 }
892 jerry_release_value(jLoopStyleVal);
893 }
894
Reset()895 inline void ChartComponent::Reset()
896 {
897 totalSerialsNum_ = 0;
898 }
899
AddDataSerial(DataSerials * serial)900 void ChartComponent::AddDataSerial(DataSerials *serial)
901 {
902 if (serial == nullptr) {
903 return;
904 }
905 if (serials_) {
906 serial->next = serials_;
907 totalSerialsNum_++;
908 } else {
909 totalSerialsNum_ = 1;
910 }
911 serials_ = serial;
912 }
913
GetChartComponent(jerry_value_t nativeElement)914 ChartComponent* ChartComponent::GetChartComponent(jerry_value_t nativeElement)
915 {
916 ChartComponent* chartComponent =
917 reinterpret_cast<ChartComponent *>(ComponentUtils::GetComponentFromBindingObject(nativeElement));
918 if (chartComponent == nullptr) {
919 HILOG_ERROR(HILOG_MODULE_ACE, "get binded component fail");
920 }
921 return chartComponent;
922 }
923
GetDataSerial(ChartComponent * chartComponent,uint8_t index)924 const DataSerials* ChartComponent::GetDataSerial(ChartComponent* chartComponent, uint8_t index)
925 {
926 if (chartComponent == nullptr) {
927 HILOG_ERROR(HILOG_MODULE_ACE, "chartComponent is null");
928 return nullptr;
929 }
930 uint8_t targetSerial = index + 1;
931 if (targetSerial > chartComponent->totalSerialsNum_) {
932 HILOG_ERROR(HILOG_MODULE_ACE, "data serial index should not larger than total serials num - 1");
933 return nullptr;
934 }
935 targetSerial = chartComponent->totalSerialsNum_ - targetSerial + 1; // serials_ is added reversed before
936 DataSerials* serial = chartComponent->serials_;
937 while (targetSerial > 1) {
938 serial = serial->next;
939 targetSerial--;
940 }
941 return serial;
942 }
943
ClearDataSerialsNode(DataSerials * serial)944 void ChartComponent::ClearDataSerialsNode(DataSerials* serial)
945 {
946 if (serial == nullptr) {
947 return;
948 }
949 if (serial->next) {
950 ClearDataSerialsNode(serial->next);
951 }
952 if (serial->dataSerial) {
953 delete (serial->dataSerial);
954 serial->dataSerial = nullptr;
955 }
956 delete (serial);
957 serial = nullptr;
958 }
959
ClearAllDataSerials()960 void ChartComponent::ClearAllDataSerials()
961 {
962 ClearDataSerialsNode(serials_);
963 serials_ = nullptr;
964 }
965
GetSizeVal(jerry_value_t obj,const char * const styleName,uint16_t defaultValue)966 uint16_t ChartComponent::GetSizeVal(jerry_value_t obj, const char * const styleName, uint16_t defaultValue)
967 {
968 if (jerryx_has_property_str(obj, styleName)) {
969 uint16_t len = 0;
970 char* sizeVal = JerryMallocStringProperty(obj, styleName, len);
971 if (sizeVal == nullptr) {
972 HILOG_WARN(HILOG_MODULE_ACE, "Get Style String value failed, return default value!");
973 return defaultValue;
974 }
975 uint16_t size = strtol(sizeVal, nullptr, DEC);
976 ace_free(sizeVal);
977 sizeVal = nullptr;
978 return size;
979 }
980 return defaultValue;
981 }
982
GetColor(jerry_value_t obj,const char * const styleName,uint32_t defaultValue)983 uint32_t ChartComponent::GetColor(jerry_value_t obj, const char * const styleName, uint32_t defaultValue)
984 {
985 uint8_t alpha = 0;
986 uint32_t color = defaultValue;
987 uint16_t len = 0;
988 char* styleValue = JerryMallocStringProperty(obj, styleName, len);
989 if (!ParseColor(styleValue, color, alpha)) {
990 HILOG_WARN(HILOG_MODULE_ACE, "color format error");
991 }
992 ACE_FREE(styleValue);
993 return color;
994 }
995
GetDisplayStatus(jerry_value_t obj)996 bool ChartComponent::GetDisplayStatus(jerry_value_t obj)
997 {
998 if (!jerryx_has_property_str(obj, DISPLAY)) {
999 return true;
1000 }
1001 jerry_value_t jDisplayValue = jerryx_get_property_str(obj, DISPLAY);
1002 return jerry_get_boolean_value(jDisplayValue);
1003 }
1004
Init()1005 bool ChartComponent::Init()
1006 {
1007 seriesOptions_ = new SeriesOptions();
1008 if (seriesOptions_ == nullptr) {
1009 HILOG_ERROR(HILOG_MODULE_ACE, "malloc seriesOptions heap error");
1010 return false;
1011 }
1012 seriesOptions_->head = new PointOptions();
1013 if (seriesOptions_->head == nullptr) {
1014 HILOG_ERROR(HILOG_MODULE_ACE, "malloc PointOptions head heap error");
1015 return false;
1016 }
1017 seriesOptions_->top = new PointOptions();
1018 if (seriesOptions_->top == nullptr) {
1019 HILOG_ERROR(HILOG_MODULE_ACE, "malloc PointOptions top heap error");
1020 return false;
1021 }
1022 seriesOptions_->bottom = new PointOptions();
1023 if (seriesOptions_->bottom == nullptr) {
1024 HILOG_ERROR(HILOG_MODULE_ACE, "malloc PointOptions bottom heap error");
1025 return false;
1026 }
1027
1028 xAxis_ = &(chartView_->GetXAxis());
1029 yAxis_ = &(chartView_->GetYAxis());
1030 if ((xAxis_ == nullptr) || (yAxis_ == nullptr)) {
1031 HILOG_ERROR(HILOG_MODULE_ACE, "get axis error");
1032 return false;
1033 }
1034 const int8_t originPosition = 0;
1035 chartView_->SetPosition(originPosition, originPosition);
1036 chartView_->SetStyle(StyleDefault::GetBrightStyle());
1037 chartView_->SetStyle(STYLE_BACKGROUND_OPA, 0);
1038 chartView_->SetStyle(STYLE_BORDER_OPA, 0);
1039 chartView_->SetStyle(STYLE_BORDER_WIDTH, 0);
1040 chartView_->SetStyle(STYLE_PADDING_LEFT, 0);
1041 RegisterNamedFunction(FUNC_JS_API, AppendDatas);
1042 return true;
1043 }
1044 } // namespace ACELite
1045 } // namespace OHOS
1046