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