1 /*
2 * Copyright (c) 2021-2022 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 "frameworks/bridge/common/dom/dom_chart.h"
17
18 #include "frameworks/bridge/common/utils/utils.h"
19 #include "core/components/common/properties/color_factory.h"
20
21 namespace OHOS::Ace::Framework {
22 namespace {
23
24 const char LIGHT_RED_COLOR[] = "#EB4034";
25 const char LIGHT_GREEN_COLOR[] = "#AEEB34";
26 const char LIGHT_BLUE_COLOR[] = "#34EBD9";
27 constexpr double PROGRESS_DEFAULT_MAX_VALUE = 100.0;
28 constexpr uint32_t METHOD_APPEND_ARGS_SIZE = 1;
29
30 } // namespace
31
GetSpecializedComponent()32 RefPtr<Component> DOMChart::GetSpecializedComponent()
33 {
34 if (chartType_ == ChartType::BAR || chartType_ == ChartType::LINE) {
35 return chartChild_;
36 }
37 if (chartType_ == ChartType::GAUGE) {
38 return progressChild_;
39 }
40 return dataPanelChild_;
41 }
42
DOMChart(NodeId nodeId,const std::string & nodeName)43 DOMChart::DOMChart(NodeId nodeId, const std::string& nodeName) : DOMNode(nodeId, nodeName) {}
44
SetChartAttrOptions(const ChartOptions & chartOptions)45 void DOMChart::SetChartAttrOptions(const ChartOptions& chartOptions)
46 {
47 chartOptions_ = chartOptions;
48 }
49
SetChartAttrDatasets(const std::vector<MainChart> & datasets)50 void DOMChart::SetChartAttrDatasets(const std::vector<MainChart>& datasets)
51 {
52 chartDatasets_ = datasets;
53 isResetPosition_ = false;
54 position_ = 0;
55 seriesNum_ = 0;
56 lineData_.clear();
57 isSetFirst_ = false;
58 }
59
SetChartAttrSegments(const std::vector<Segment> & segments)60 void DOMChart::SetChartAttrSegments(const std::vector<Segment>& segments)
61 {
62 segments_ = segments;
63 }
64
SetSpecializedAttr(const std::pair<std::string,std::string> & attr)65 bool DOMChart::SetSpecializedAttr(const std::pair<std::string, std::string>& attr)
66 {
67 // this map should be sorted by key.
68 static const LinearMapNode<void (*)(const std::string&, DOMChart&)> chartAttrsOperators[] = {
69 { DOM_CHART_ANIMATION_DURATION,
70 [](const std::string& val, DOMChart& chart) {
71 chart.animationDuration_ = StringToDouble(val);
72 } },
73 { DOM_AUTO_SCALE,
74 [](const std::string& val, DOMChart& chart) {
75 chart.autoScale_ = StringToBool(val);
76 } },
77 { DOM_EFFECTS_ON,
78 [](const std::string& val, DOMChart& chart) {
79 chart.showEffect_ = StringToBool(val);
80 } },
81 { DOM_PROGRESS_PERCENT,
82 [](const std::string& val, DOMChart& chart) {
83 chart.percent_ = StringToDouble(val);
84 if (chart.percent_ > chart.max_) {
85 chart.percent_ = chart.max_;
86 }
87 if (chart.percent_ < chart.min_) {
88 chart.percent_ = chart.min_;
89 }
90 } },
91 { DOM_CHART_TYPE,
92 [](const std::string& val, DOMChart& chart) {
93 if (val == DOM_CHART_TYPE_GAUGE) {
94 chart.chartType_ = ChartType::GAUGE;
95 } else if (val == DOM_CHART_TYPE_BAR) {
96 chart.chartType_ = ChartType::BAR;
97 } else if (val == DOM_CHART_TYPE_LINE) {
98 chart.chartType_ = ChartType::LINE;
99 } else if (val == DOM_CHART_TYPE_PROGRESS) {
100 chart.chartType_ = ChartType::PROGRESS;
101 } else if (val == DOM_CHART_TYPE_RAINBOW) {
102 chart.chartType_ = ChartType::RAINBOW;
103 } else if (val == DOM_CHART_TYPE_LOADING) {
104 chart.chartType_ = ChartType::LOADING;
105 } else {
106 chart.chartType_ = ChartType::LINE;
107 }
108 } },
109 };
110 auto operatorIter = BinarySearchFindIndex(chartAttrsOperators, ArraySize(chartAttrsOperators), attr.first.c_str());
111 if (operatorIter != -1) {
112 chartAttrsOperators[operatorIter].value(attr.second, *this);
113 return true;
114 }
115 return false;
116 }
117
SetSpecializedStyle(const std::pair<std::string,std::string> & style)118 bool DOMChart::SetSpecializedStyle(const std::pair<std::string, std::string>& style)
119 {
120 // this map should be sorted by key.
121 static const LinearMapNode<void (*)(const std::string&, DOMChart&)> chartStylesOperators[] = {
122 { DOM_BACKGROUND_COLOR,
123 [](const std::string& val, DOMChart& chart) {
124 if (chart.chartType_ == ChartType::LINE || (chart.chartType_ == ChartType::BAR) ||
125 (chart.chartType_ == ChartType::GAUGE)) {
126 auto declaration = chart.GetDeclaration();
127 if (declaration) {
128 auto backgroundColor = chart.ParseColor(val);
129 declaration->GetBackDecoration()->SetBackgroundColor(backgroundColor);
130 declaration->SetHasBackGroundColor(true);
131 declaration->SetHasDecorationStyle(true);
132 return;
133 }
134 }
135 chart.backgroundColor_ = chart.ParseColor(val);
136 chart.trackColorSet_ = true;
137 } },
138 { DOM_CENTER_X,
139 [](const std::string& val, DOMChart& chart) {
140 chart.centerX_.first = StringToDouble(val);
141 chart.centerX_.second = true;
142 } },
143 { DOM_CENTER_Y,
144 [](const std::string& val, DOMChart& chart) {
145 chart.centerY_.first = StringToDouble(val);
146 chart.centerY_.second = true;
147 } },
148 { DOM_COLORS_ARRAY,
149 [](const std::string& val, DOMChart& chart) {
150 chart.colors_.clear();
151 StringUtils::StringSplitter(val, ',', chart.colors_);
152 } },
153 { DOM_TEXT_FONT_FAMILY,
154 [](const std::string& val, DOMChart& chart) {
155 chart.fontFamily_ = ConvertStrToFontFamilies(val);
156 } },
157 { DOM_TEXT_FONT_SIZE,
158 [](const std::string& val, DOMChart& chart) {
159 chart.textSize_ = StringToDouble(val);
160 } },
161 { DOM_PROGRESS_RADIUS,
162 [](const std::string& val, DOMChart& chart) {
163 chart.radius_.first = StringToDouble(val);
164 chart.radius_.second = true;
165 } },
166 { DOM_START_DEGREE,
167 [](const std::string& val, DOMChart& chart) {
168 chart.startAngle_.first = StringToDouble(val);
169 chart.startAngle_.second = true;
170 } },
171 { DOM_PROGRESS_STROKE_WIDTH,
172 [](const std::string& val, DOMChart& chart) {
173 chart.strokeWidth_.first = chart.ParseDimension(val);
174 chart.strokeWidth_.second = true;
175 } },
176 { DOM_SWEEP_DEGREE,
177 [](const std::string& val, DOMChart& chart) {
178 chart.totalAngle_.first = StringToDouble(val);
179 chart.totalAngle_.second = true;
180 } },
181 { DOM_WEIGHTS_ARRAY,
182 [](const std::string& val, DOMChart& chart) {
183 chart.weights_.clear();
184 StringUtils::StringSplitter(val, ',', chart.weights_);
185 } },
186 };
187 auto operatorIter =
188 BinarySearchFindIndex(chartStylesOperators, ArraySize(chartStylesOperators), style.first.c_str());
189 if (operatorIter != -1) {
190 chartStylesOperators[operatorIter].value(style.second, *this);
191 return true;
192 }
193 return false;
194 }
195
OnSetStyleFinished()196 void DOMChart::OnSetStyleFinished()
197 {
198 // colors or weight are illegal, and set default color and weight
199 if (colors_.empty() || weights_.empty() || colors_.size() != weights_.size()) {
200 colors_.push_back(ParseColor(LIGHT_RED_COLOR));
201 colors_.push_back(ParseColor(LIGHT_GREEN_COLOR));
202 colors_.push_back(ParseColor(LIGHT_BLUE_COLOR));
203 // equally separate the range
204 weights_.push_back(1);
205 weights_.push_back(1);
206 weights_.push_back(1);
207 }
208 if (!centerY_.second || !centerX_.second || !radius_.second) {
209 centerY_.first = -1.0;
210 centerX_.first = -1.0;
211 radius_.first = -1.0;
212 centerY_.second = false;
213 centerX_.second = false;
214 radius_.second = false;
215 }
216 }
217
218 // Sets other properties of a point, except coordinates.
SetPoint(PointInfo & pointInfo,PointInfo getPointInfo)219 void DOMChart::SetPoint(PointInfo& pointInfo, PointInfo getPointInfo)
220 {
221 if (!getPointInfo.GetFillColorString().empty()) {
222 getPointInfo.SetFillColor(ParseColor(getPointInfo.GetFillColorString()));
223 }
224 pointInfo.SetFillColor(getPointInfo.GetFillColor());
225 if (!getPointInfo.GetStrokeColorString().empty()) {
226 getPointInfo.SetStrokeColor(ParseColor(getPointInfo.GetStrokeColorString()));
227 }
228 pointInfo.SetStrokeColor(getPointInfo.GetStrokeColor());
229 pointInfo.SetPointStrokeWidth(getPointInfo.GetPointStrokeWidth());
230 pointInfo.SetPointSize(getPointInfo.GetPointSize());
231 pointInfo.SetPointShape(getPointInfo.GetPointShape());
232 pointInfo.SetDisplay(getPointInfo.GetDisplay());
233 }
234
SetChart(MainChart & chartDataset)235 void DOMChart::SetChart(MainChart& chartDataset)
236 {
237 chartDataset.SetLineWidth(chartOptions_.GetLineWidth());
238 chartDataset.SetSmoothFlag(chartOptions_.GetSmoothFlag());
239 chartDataset.SetLineGradient(chartOptions_.GetLineGradient());
240 chartDataset.SetWholeLineGradient(chartOptions_.GetWholeLineGradient());
241 chartDataset.SetTargetColor(chartOptions_.GetTargetColor());
242 chartDataset.SetErasePointNumber(chartOptions_.GetErasePointNumber());
243 chartDataset.SetTextSize(textSize_);
244 chartDataset.SetFontFamily(fontFamily_);
245
246 auto points = chartDataset.GetData();
247 if (points.empty()) {
248 return;
249 }
250
251 // parse color from color string
252 for (auto& point : points) {
253 auto pointInfo = point.GetPointInfo();
254 if (!pointInfo.GetStrokeColorString().empty()) {
255 pointInfo.SetStrokeColor(ParseColor(pointInfo.GetStrokeColorString()));
256 }
257 if (!pointInfo.GetFillColorString().empty()) {
258 pointInfo.SetFillColor(ParseColor(pointInfo.GetFillColorString()));
259 }
260 auto segment = point.GetSegmentInfo();
261 if (!segment.GetColorString().empty()) {
262 segment.SetSegmentColor(ParseColor(segment.GetColorString()));
263 }
264 auto text = point.GetTextInfo();
265 if (!text.GetColorString().empty()) {
266 text.SetColor(ParseColor(text.GetColorString()));
267 }
268 point.SetPointInfo(pointInfo);
269 point.SetSegmentInfo(segment);
270 point.SetTextInfo(text);
271 }
272
273 // remove points out of range. get topPoint and bottomPoint.
274 sort(points.begin(), points.end(),
275 [](LineInfo a, LineInfo b) { return a.GetPointInfo().GetX() < b.GetPointInfo().GetX(); });
276
277 PointInfo headPoint;
278 PointInfo topPoint = points.begin()->GetPointInfo();
279 PointInfo bottomPoint = points.begin()->GetPointInfo();
280
281 for (auto pointInfo = points.begin(); pointInfo != points.end();) {
282 auto point = pointInfo->GetPointInfo();
283 auto segment = pointInfo->GetSegmentInfo();
284 if (segment.GetSegmentColor() == Color::TRANSPARENT) {
285 segment.SetSegmentColor(chartDataset.GetStrokeColor());
286 pointInfo->SetSegmentInfo(segment);
287 }
288 if ((chartType_ == ChartType::LINE && point.GetX() < chartOptions_.GetXAxis().min) ||
289 (chartType_ == ChartType::LINE && point.GetX() > chartOptions_.GetXAxis().max) ||
290 ((chartType_ != ChartType::LINE && chartType_ != ChartType::BAR)
291 && (point.GetY() < chartOptions_.GetYAxis().min || point.GetY() > chartOptions_.GetYAxis().max))) {
292 points.erase(pointInfo);
293 } else {
294 if (point.GetY() > topPoint.GetY()) {
295 topPoint = point;
296 }
297 if (point.GetY() < bottomPoint.GetY()) {
298 bottomPoint = point;
299 }
300 ++pointInfo;
301 }
302 }
303 chartDataset.SetData(points);
304
305 if (!points.empty()) {
306 headPoint = points[points.size() - 1].GetPointInfo();
307 SetPoint(headPoint, chartOptions_.GetHeadPoint());
308 chartDataset.SetHeadPoint(headPoint);
309 }
310
311 SetPoint(topPoint, chartOptions_.GetTopPoint());
312 chartDataset.SetTopPoint(topPoint);
313
314 SetPoint(bottomPoint, chartOptions_.GetBottomPoint());
315 chartDataset.SetBottomPoint(bottomPoint);
316 }
317
PrepareSpecializedComponent()318 void DOMChart::PrepareSpecializedComponent()
319 {
320 if (chartType_ == ChartType::GAUGE) {
321 if (!progressChild_) {
322 progressChild_ =
323 AceType::MakeRefPtr<ProgressComponent>(0.0, 0.0, 0.0, PROGRESS_DEFAULT_MAX_VALUE, ProgressType::GAUGE);
324 }
325 progressChild_->SetValue(percent_);
326 progressChild_->SetMaxValue(max_);
327 progressChild_->SetMinValue(min_);
328 progressChild_->GetTrack()->SetIndicatorFlag(true);
329 progressChild_->GetTrack()->SetSectionsStyle(colors_, weights_);
330 progressChild_->GetTrack()->SetTrackThickness(strokeWidth_.first);
331 progressChild_->GetTrack()->GetTrackInfo()->SetStartDegree(startAngle_.first);
332 progressChild_->GetTrack()->GetTrackInfo()->SetSweepDegree(totalAngle_.first);
333 progressChild_->GetTrack()->SetCenterX(centerX_.first);
334 progressChild_->GetTrack()->SetCenterY(centerY_.first);
335 progressChild_->GetTrack()->SetRadius(radius_.first);
336 } else if (chartType_ == ChartType::BAR || chartType_ == ChartType::LINE) {
337 if (!chartChild_) {
338 chartChild_ = AceType::MakeRefPtr<ChartComponent>(chartType_);
339 }
340 chartChild_->SetHorizontalOption(chartOptions_.GetXAxis());
341 chartChild_->SetVerticalOption(chartOptions_.GetYAxis());
342 // Convert the data in options to mainchart
343 for (auto& charDataset : chartDatasets_) {
344 SetChart(charDataset);
345 }
346 chartChild_->SetMainCharts(chartDatasets_);
347 } else if (chartType_ == ChartType::PROGRESS || chartType_ == ChartType::LOADING) {
348 dataPanelChild_ = AceType::MakeRefPtr<ProgressDataPanelComponent>(chartType_);
349 dataPanelChild_->InitalStyle(GetThemeManager());
350 dataPanelChild_->SetEffects(showEffect_);
351 if (trackColorSet_) {
352 dataPanelChild_->SetTrackColor(backgroundColor_);
353 }
354 dataPanelChild_->SetAutoScale(autoScale_);
355 if (segments_.empty()) {
356 return;
357 }
358 auto progressDataPanel = AceType::DynamicCast<ProgressDataPanelComponent>(dataPanelChild_);
359 if (segments_[0].GetColorType() == SegmentStyleType::USE_COLOR) {
360 progressDataPanel->SetStartColor(segments_[0].GetStartColor());
361 progressDataPanel->SetEndColor(segments_[0].GetEndColor());
362 } else if (segments_[0].GetColorType() == SegmentStyleType::USE_GRADIENT) {
363 auto& colorManager = ColorFactory::GetInstance();
364 auto colorPair = colorManager.GetColorTuple(segments_[0].GetColorDescriptor());
365 progressDataPanel->SetStartColor(colorPair.first);
366 progressDataPanel->SetEndColor(colorPair.second);
367 }
368 // for else case, keep default color
369 progressDataPanel->SetProgressValue(segments_[0].GetValue());
370 if (strokeWidth_.second) {
371 dataPanelChild_->SetThickness(strokeWidth_.first);
372 }
373 } else if (chartType_ == ChartType::RAINBOW) {
374 dataPanelChild_ = AceType::MakeRefPtr<PercentageDataPanelComponent>(chartType_);
375 dataPanelChild_->SetAnimationDuration(animationDuration_);
376 dataPanelChild_->SetEffects(showEffect_);
377 dataPanelChild_->SetAutoScale(autoScale_);
378 auto percentageDataPanel = AceType::DynamicCast<PercentageDataPanelComponent>(dataPanelChild_);
379 // the angle range is from 0 to 360.
380 percentageDataPanel->SetStartDegree(startAngle_.second ? startAngle_.first : 0.0);
381 percentageDataPanel->SetSweepDegree(totalAngle_.second ? totalAngle_.first : 360.0);
382 percentageDataPanel->ClearSegment();
383 if (segments_.empty()) {
384 return;
385 }
386 for (const auto& segment : segments_) {
387 percentageDataPanel->AppendSegment(segment);
388 }
389 dataPanelChild_->InitalStyle(GetThemeManager());
390 if (trackColorSet_) {
391 dataPanelChild_->SetTrackColor(backgroundColor_);
392 }
393 if (strokeWidth_.second) {
394 dataPanelChild_->SetThickness(strokeWidth_.first);
395 }
396 }
397 }
398
CallSpecializedMethod(const std::string & method,const std::string & args)399 void DOMChart::CallSpecializedMethod(const std::string& method, const std::string& args)
400 {
401 if (method != DOM_METHOD_APPEND) {
402 return;
403 }
404 std::unique_ptr<JsonValue> argsValue = JsonUtil::ParseJsonString(args);
405 if (!argsValue || !argsValue->IsArray() || argsValue->GetArraySize() != METHOD_APPEND_ARGS_SIZE) {
406 return;
407 }
408
409 std::unique_ptr<JsonValue> serialValue = argsValue->GetArrayItem(0)->GetValue("serial");
410 if (!serialValue || !serialValue->IsNumber()) {
411 return;
412 }
413 seriesNum_ = serialValue->GetInt();
414
415 std::unique_ptr<JsonValue> dataValue = argsValue->GetArrayItem(0)->GetValue("data");
416 if (!dataValue || !dataValue->IsArray()) {
417 return;
418 }
419
420 int32_t arraySize = dataValue->GetArraySize();
421 auto chartDatas = chartChild_->GetMainCharts();
422 if (seriesNum_ < 0 || (static_cast<size_t>(seriesNum_) >= chartDatas.size())) {
423 LOGW("series number is greater or equal to the size of chart");
424 return;
425 }
426 if (!isSetFirst_) {
427 isSetFirst_ = true;
428 for (int32_t i = 0; i < static_cast<int32_t>(chartDatas.size()); i++) {
429 lineData_.emplace_back(chartOptions_.GetXAxis().min, false);
430 }
431 }
432
433 // get the head point position of the series data to be updated.
434 position_ = lineData_[seriesNum_].first;
435 isResetPosition_ = lineData_[seriesNum_].second;
436
437 for (int32_t i = 0; i < arraySize; i++) {
438 std::unique_ptr<JsonValue> coorVal = dataValue->GetArrayItem(i);
439 if (!coorVal || !coorVal->IsNumber()) {
440 return;
441 }
442 int32_t coorY = coorVal->GetInt();
443 if (coorY <= chartOptions_.GetYAxis().max && coorY >= chartOptions_.GetYAxis().min) {
444 UpdateChartData(coorY, chartDatas);
445 }
446 }
447
448 // save the head point position of the updated series data.
449 lineData_[seriesNum_].first = position_;
450 lineData_[seriesNum_].second = isResetPosition_;
451
452 UpdateTopBottomPoint(chartDatas);
453
454 chartChild_->SetMainCharts(chartDatas);
455 auto node = DOMNode::GetRootComponent();
456 node->MarkNeedUpdate();
457 auto pipelineContext = pipelineContext_.Upgrade();
458 if (!pipelineContext) {
459 return;
460 }
461 pipelineContext->ScheduleUpdate(node);
462 }
463
UpdateTopBottomPoint(std::vector<MainChart> & data)464 void DOMChart::UpdateTopBottomPoint(std::vector<MainChart>& data)
465 {
466 Point bottomPt = Point(0, 0);
467 Point topPt = Point(0, 0);
468 auto pointVec = data[seriesNum_].GetData();
469 double minY = pointVec[0].GetPointInfo().GetY();
470 double maxY = pointVec[0].GetPointInfo().GetY();
471
472 for (auto iter : pointVec) {
473 if (iter.GetPointInfo().GetY() <= minY) {
474 bottomPt.SetX(iter.GetPointInfo().GetX());
475 bottomPt.SetY(iter.GetPointInfo().GetY());
476 minY = iter.GetPointInfo().GetY();
477 }
478 if (iter.GetPointInfo().GetY() >= maxY) {
479 topPt.SetX(iter.GetPointInfo().GetX());
480 topPt.SetY(iter.GetPointInfo().GetY());
481 maxY = iter.GetPointInfo().GetY();
482 }
483 }
484 auto bottomPoint = data[seriesNum_].GetBottomPoint();
485 bottomPoint.SetX(bottomPt.GetX());
486 bottomPoint.SetY(bottomPt.GetY());
487 data[seriesNum_].SetBottomPoint(bottomPoint);
488
489 auto topPoint = data[seriesNum_].GetTopPoint();
490 topPoint.SetX(topPt.GetX());
491 topPoint.SetY(topPt.GetY());
492 data[seriesNum_].SetTopPoint(topPoint);
493 }
494
UpdateChartData(int32_t coorY,std::vector<MainChart> & data)495 void DOMChart::UpdateChartData(int32_t coorY, std::vector<MainChart>& data)
496 {
497 if (isResetPosition_) {
498 position_ = position_ + 1;
499 } else {
500 position_ = static_cast<int32_t>(data[seriesNum_].GetData().size());
501 }
502 if (position_ > chartOptions_.GetXAxis().max || position_ < chartOptions_.GetXAxis().min) {
503 return;
504 }
505 if (chartOptions_.GetLoop() && position_ > chartOptions_.GetXAxis().max - 1) {
506 isResetPosition_ = true;
507 position_ = chartOptions_.GetXAxis().min;
508 Point coor = Point(position_, coorY);
509 PointInfo point = PointInfo(coor);
510 SegmentInfo segment;
511 segment.SetSegmentColor(data[seriesNum_].GetStrokeColor());
512 LineInfo line = LineInfo(point);
513 line.SetSegmentInfo(segment);
514 data[seriesNum_].ReplaceData(position_, line);
515 data[seriesNum_].SetErasePointNumber(chartOptions_.GetErasePointNumber());
516 data[seriesNum_].SetHeadPointIndex(position_);
517 } else {
518 Point coor = Point(position_, coorY);
519 PointInfo point = PointInfo(coor);
520 SegmentInfo segment;
521 segment.SetSegmentColor(data[seriesNum_].GetStrokeColor());
522 LineInfo line = LineInfo(point);
523 line.SetSegmentInfo(segment);
524 if (!isResetPosition_) {
525 data[seriesNum_].AppendData(line);
526 } else {
527 data[seriesNum_].ReplaceData(position_, line);
528 data[seriesNum_].SetHeadPointIndex(position_);
529 }
530 }
531 auto headPoint = data[seriesNum_].GetHeadPoint();
532 headPoint.SetX(position_);
533 headPoint.SetY(coorY);
534 data[seriesNum_].SetHeadPoint(headPoint);
535 }
536
537 } // namespace OHOS::Ace::Framework
538