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 "core/components/chart/rosen_render_chart.h"
17
18 #ifndef USE_ROSEN_DRAWING
19 #include "include/core/SkColor.h"
20 #include "include/core/SkPaint.h"
21 #include "include/effects/Sk1DPathEffect.h"
22 #include "include/effects/SkGradientShader.h"
23 #endif
24 #ifndef USE_GRAPHIC_TEXT_GINE
25 #include "txt/paragraph_builder.h"
26 #include "txt/paragraph_txt.h"
27 #else
28 #include "rosen_text/typography.h"
29 #include "rosen_text/typography_create.h"
30 #endif
31
32 #include "core/components/font/rosen_font_collection.h"
33 #include "core/pipeline/base/rosen_render_context.h"
34
35 namespace OHOS::Ace {
36 namespace {
37
38 #ifndef WEARABLE_PRODUCT
39 constexpr double EDGE_PADDING = 20.0;
40 constexpr double TEXT_PADDING = 10.0;
41 #else
42 constexpr double EDGE_PADDING = 2.0;
43 constexpr double TEXT_PADDING = 1.0;
44 #endif
45 constexpr double TICK_LENGTH = 5.0;
46 constexpr double RATIO_CONSTANT = 1.732;
47 constexpr double BARS_INTERVAL_PROPORTION = 0.3;
48 constexpr double BAR_INTERVAL_PROPORTION = 0.1;
49 constexpr double DEFAULT_AXISTICK = 10.0;
50 constexpr double DEFAULT_AXIS_STROKE_WIDTH = 3.0;
51 constexpr double BEZIER_CONSTANT = 6.0;
52 constexpr double DOUBLE_TEXT_PADDING = TEXT_PADDING * 2;
53 constexpr int32_t MIN_SDK_VERSION = 6;
54
55 } // namespace
56
Update(const RefPtr<Component> & component)57 void RosenRenderChart::Update(const RefPtr<Component>& component)
58 {
59 RenderChart::Update(component);
60 }
61
ConvertDataToPosition(const Rect & paintRegion,const PointInfo & point)62 Offset RosenRenderChart::ConvertDataToPosition(const Rect& paintRegion, const PointInfo& point)
63 {
64 double xLength = horizontal_.max - horizontal_.min;
65 double yLength = vertical_.max - vertical_.min;
66 if (NearEqual(xLength, 0.0) || NearEqual(yLength, 0.0)) {
67 return Offset(0, 0);
68 }
69 return Offset(paintRegion.GetOffset().GetX() + (point.GetX() - horizontal_.min) * paintRegion.Width() / xLength,
70 paintRegion.GetOffset().GetY() + paintRegion.Height() -
71 (point.GetY() - vertical_.min) * paintRegion.Height() / yLength);
72 }
73
Paint(RenderContext & context,const Offset & offset)74 void RosenRenderChart::Paint(RenderContext& context, const Offset& offset)
75 {
76 if (LessOrEqual(vertical_.max, vertical_.min)) {
77 vertical_.min = 0.0;
78 vertical_.max = 100.0;
79 }
80 if (LessOrEqual(horizontal_.max, horizontal_.min)) {
81 horizontal_.min = 0.0;
82 horizontal_.max = 100.0;
83 }
84 Rect verticalPaintRegion =
85 Rect(offset.GetX(), offset.GetY(), GetLayoutSize().Width() * 0.1, GetLayoutSize().Height());
86 Rect horizontalPaintRegion =
87 Rect(offset.GetX(), offset.GetY() + GetLayoutSize().Height() - GetLayoutSize().Height() * 0.1,
88 GetLayoutSize().Width(), GetLayoutSize().Height() * 0.1);
89 Rect dataRegion;
90 if (!vertical_.display && !horizontal_.display && type_ == ChartType::LINE) {
91 dataRegion = Rect(offset.GetX() + EDGE_PADDING, offset.GetY() + DOUBLE_TEXT_PADDING,
92 GetLayoutSize().Width() - 2 * EDGE_PADDING, GetLayoutSize().Height() - 2 * DOUBLE_TEXT_PADDING);
93 } else {
94 PaintVerticalAxis(context, offset, verticalPaintRegion);
95 PaintHorizontalAxis(context, horizontalPaintRegion);
96 dataRegion = Rect(offset.GetX() + tickHorizontalOffset_ + EDGE_PADDING, offset.GetY() + EDGE_PADDING,
97 horizontal_.tickNumber * tickHorizontalOffset_, vertical_.tickNumber * tickOffset_);
98 }
99 if (!dataRegion.IsValid()) {
100 LOGW("chart paint data region is not valid height:%{public}lf, width:%{public}lf. do not paint data",
101 dataRegion.Height(), dataRegion.Width());
102 return;
103 }
104 // We Do not clip here(compare with FlutterRenderChart).
105 // Cliping here may cause Axis not display when horizontal_.display = true or vertical_.display = true
106 paintWidth_ = dataRegion.GetSize().Width();
107 PaintDatas(context, dataRegion);
108 }
109
110 #ifndef USE_ROSEN_DRAWING
PaintStylePoints(SkCanvas * canvas,const Rect & paintRegion,const MainChart & chartData)111 void RosenRenderChart::PaintStylePoints(SkCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
112 {
113 SkPaint paint;
114 paint.setAntiAlias(true);
115
116 for (const auto& points : chartData.GetData()) {
117 const PointInfo& point = points.GetPointInfo();
118 if (point.GetDisplay()) {
119 PaintPoint(canvas, ConvertDataToPosition(paintRegion, point), paint, point);
120 }
121 }
122 PointInfo headPoint = chartData.GetHeadPoint();
123 if (headPoint.GetDisplay()) {
124 PaintPoint(canvas, ConvertDataToPosition(paintRegion, headPoint), paint, headPoint);
125 }
126 PointInfo topPoint = chartData.GetTopPoint();
127 if (topPoint.GetDisplay()) {
128 PaintPoint(canvas, ConvertDataToPosition(paintRegion, topPoint), paint, topPoint);
129 }
130 PointInfo bottomPoint = chartData.GetBottomPoint();
131 if (bottomPoint.GetDisplay()) {
132 PaintPoint(canvas, ConvertDataToPosition(paintRegion, bottomPoint), paint, bottomPoint);
133 }
134 }
135 #else
PaintStylePoints(RSCanvas * canvas,const Rect & paintRegion,const MainChart & chartData)136 void RosenRenderChart::PaintStylePoints(RSCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
137 {
138 RSPen pen;
139 RSBrush brush;
140 pen.SetAntiAlias(true);
141 brush.SetAntiAlias(true);
142
143 for (const auto& points : chartData.GetData()) {
144 const PointInfo& point = points.GetPointInfo();
145 if (point.GetDisplay()) {
146 PaintPoint(canvas, ConvertDataToPosition(paintRegion, point), pen, brush, point);
147 }
148 }
149 PointInfo headPoint = chartData.GetHeadPoint();
150 if (headPoint.GetDisplay()) {
151 PaintPoint(canvas, ConvertDataToPosition(paintRegion, headPoint), pen, brush, headPoint);
152 }
153 PointInfo topPoint = chartData.GetTopPoint();
154 if (topPoint.GetDisplay()) {
155 PaintPoint(canvas, ConvertDataToPosition(paintRegion, topPoint), pen, brush, topPoint);
156 }
157 PointInfo bottomPoint = chartData.GetBottomPoint();
158 if (bottomPoint.GetDisplay()) {
159 PaintPoint(canvas, ConvertDataToPosition(paintRegion, bottomPoint), pen, brush, bottomPoint);
160 }
161 }
162 #endif
163
164 #ifndef USE_ROSEN_DRAWING
PaintText(SkCanvas * canvas,const Rect & paintRegion,const MainChart & chartData)165 void RosenRenderChart::PaintText(SkCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
166 #else
167 void RosenRenderChart::PaintText(RSCanvas* canvas, const Rect& paintRegion, const MainChart& chartData)
168 #endif
169 {
170 if (chartData.GetData().empty()) {
171 return;
172 }
173
174 auto fontCollection = RosenFontCollection::GetInstance().GetFontCollection();
175 if (!fontCollection) {
176 LOGW("PaintText: fontCollection is null");
177 return;
178 }
179 #ifndef USE_GRAPHIC_TEXT_GINE
180 txt::ParagraphStyle style;
181 txt::TextStyle txtStyle;
182 txtStyle.font_size = chartData.GetTextSize();
183 txtStyle.font_families = chartData.GetFontFamily();
184 txtStyle.font_weight = txt::FontWeight::w400;
185 std::unique_ptr<txt::ParagraphBuilder> builder;
186 double paragraphSize = paintRegion.Width() / chartData.GetData().size();
187 style.max_lines = 1;
188 #else
189 Rosen::TypographyStyle style;
190 Rosen::TextStyle txtStyle;
191 txtStyle.fontSize = chartData.GetTextSize();
192 txtStyle.fontFamilies = chartData.GetFontFamily();
193 txtStyle.fontWeight = Rosen::FontWeight::W400;
194 std::unique_ptr<Rosen::TypographyCreate> builder;
195 double paragraphSize = paintRegion.Width() / chartData.GetData().size();
196 style.maxLines = 1;
197 #endif
198 for (const auto& point : chartData.GetData()) {
199 const TextInfo& text = point.GetTextInfo();
200 const PointInfo& pointInfo = point.GetPointInfo();
201 Offset pointPosition = ConvertDataToPosition(paintRegion, pointInfo);
202 txtStyle.color = text.GetColor().GetValue();
203 #ifndef USE_GRAPHIC_TEXT_GINE
204 builder = txt::ParagraphBuilder::CreateTxtBuilder(style, fontCollection);
205 builder->PushStyle(txtStyle);
206 builder->AddText(StringUtils::Str8ToStr16(text.GetTextValue()));
207 auto paragraph = builder->Build();
208 #else
209 builder = Rosen::TypographyCreate::Create(style, fontCollection);
210 builder->PushStyle(txtStyle);
211 builder->AppendText(StringUtils::Str8ToStr16(text.GetTextValue()));
212 auto paragraph = builder->CreateTypography();
213 #endif
214 paragraph->Layout(paragraphSize);
215 Size textSize = Size(paragraph->GetMinIntrinsicWidth(), paragraph->GetHeight());
216 if (text.GetPlacement() == Placement::TOP) {
217 paragraph->Paint(canvas, pointPosition.GetX() - textSize.Width() / 2,
218 pointPosition.GetY() - textSize.Height() - TEXT_PADDING);
219 } else if (text.GetPlacement() == Placement::BOTTOM) {
220 paragraph->Paint(canvas, pointPosition.GetX() - textSize.Width() / 2,
221 pointPosition.GetY() + TEXT_PADDING);
222 }
223 }
224 }
225
226 #ifndef USE_ROSEN_DRAWING
SetEdgeStyle(const PointInfo & point,SkPaint & paint) const227 void RosenRenderChart::SetEdgeStyle(const PointInfo& point, SkPaint& paint) const
228 {
229 paint.setStyle(SkPaint::Style::kStroke_Style);
230 paint.setStrokeWidth(NormalizeToPx(point.GetPointStrokeWidth()));
231 paint.setColor(point.GetStrokeColor().GetValue());
232 }
233 #else
SetEdgeStyle(const PointInfo & point,RSPen & pen) const234 void RosenRenderChart::SetEdgeStyle(const PointInfo& point, RSPen& pen) const
235 {
236 pen.SetWidth(NormalizeToPx(point.GetPointStrokeWidth()));
237 pen.SetColor(point.GetStrokeColor().GetValue());
238 }
239 #endif
240
241 #ifndef USE_ROSEN_DRAWING
PaintPoint(SkCanvas * canvas,const Offset & offset,SkPaint paint,const PointInfo & point)242 void RosenRenderChart::PaintPoint(SkCanvas* canvas, const Offset& offset, SkPaint paint, const PointInfo& point)
243 {
244 paint.setColor(point.GetFillColor().GetValue());
245 paint.setStyle(SkPaint::Style::kFill_Style);
246 double pointSize = NormalizeToPx(point.GetPointSize());
247 double halfThickness = NormalizeToPx(point.GetPointStrokeWidth()) / 2;
248 double innerRadius = pointSize / 2 - halfThickness;
249 // first fill point color, then draw edge of point.
250 switch (point.GetPointShape()) {
251 case PointShape::CIRCLE: {
252 canvas->drawCircle(offset.GetX(), offset.GetY(), innerRadius, paint);
253 SetEdgeStyle(point, paint);
254 canvas->drawCircle(offset.GetX(), offset.GetY(), pointSize / 2, paint);
255 break;
256 }
257 case PointShape::SQUARE: {
258 canvas->drawRect(SkRect::MakeLTRB(offset.GetX() - innerRadius, offset.GetY() - innerRadius,
259 offset.GetX() + innerRadius, offset.GetY() + innerRadius),
260 paint);
261 SetEdgeStyle(point, paint);
262 canvas->drawRect(SkRect::MakeLTRB(offset.GetX() - pointSize / 2, offset.GetY() - pointSize / 2,
263 offset.GetX() + pointSize / 2, offset.GetY() + pointSize / 2),
264 paint);
265 break;
266 }
267 case PointShape::TRIANGLE: {
268 SkPath path;
269 path.moveTo(offset.GetX(), offset.GetY() - innerRadius);
270 path.lineTo(offset.GetX() - RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
271 path.lineTo(offset.GetX() + RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
272 path.close();
273 canvas->drawPath(path, paint);
274 path.reset();
275 path.moveTo(offset.GetX(), offset.GetY() - pointSize / 2);
276 path.lineTo(offset.GetX() - RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
277 path.lineTo(offset.GetX() + RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
278 path.close();
279 SetEdgeStyle(point, paint);
280 canvas->drawPath(path, paint);
281 break;
282 }
283 default: {
284 canvas->drawCircle(offset.GetX(), offset.GetY(), innerRadius, paint);
285 SetEdgeStyle(point, paint);
286 canvas->drawCircle(offset.GetX(), offset.GetY(), pointSize / 2, paint);
287 break;
288 }
289 }
290 }
291 #else
PaintPoint(RSCanvas * canvas,const Offset & offset,RSPen pen,RSBrush brush,const PointInfo & point)292 void RosenRenderChart::PaintPoint(
293 RSCanvas* canvas, const Offset& offset, RSPen pen, RSBrush brush, const PointInfo& point)
294 {
295 pen.SetColor(point.GetFillColor().GetValue());
296 brush.SetColor(point.GetFillColor().GetValue());
297
298 double pointSize = NormalizeToPx(point.GetPointSize());
299 double halfThickness = NormalizeToPx(point.GetPointStrokeWidth()) / 2;
300 double innerRadius = pointSize / 2 - halfThickness;
301 // first fill point color, then draw edge of point.
302 switch (point.GetPointShape()) {
303 case PointShape::CIRCLE: {
304 canvas->AttachBrush(brush);
305 canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), innerRadius);
306 canvas->DetachBrush();
307 SetEdgeStyle(point, pen);
308 canvas->AttachPen(pen);
309 canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), pointSize / 2);
310 canvas->DetachPen();
311 break;
312 }
313 case PointShape::SQUARE: {
314 canvas->AttachBrush(brush);
315 canvas->DrawRect(RSRect(offset.GetX() - innerRadius, offset.GetY() - innerRadius,
316 offset.GetX() + innerRadius, offset.GetY() + innerRadius));
317 canvas->DetachBrush();
318 SetEdgeStyle(point, pen);
319 canvas->AttachPen(pen);
320 canvas->DrawRect(RSRect(offset.GetX() - pointSize / 2, offset.GetY() - pointSize / 2,
321 offset.GetX() + pointSize / 2, offset.GetY() + pointSize / 2));
322 canvas->DetachPen();
323 break;
324 }
325 case PointShape::TRIANGLE: {
326 RSRecordingPath path;
327 path.MoveTo(offset.GetX(), offset.GetY() - innerRadius);
328 path.LineTo(offset.GetX() - RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
329 path.LineTo(offset.GetX() + RATIO_CONSTANT * innerRadius / 2, offset.GetY() + innerRadius / 2);
330 path.Close();
331 canvas->AttachBrush(brush);
332 canvas->DrawPath(path);
333 canvas->DetachBrush();
334 path.Reset();
335 path.MoveTo(offset.GetX(), offset.GetY() - pointSize / 2);
336 path.LineTo(offset.GetX() - RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
337 path.LineTo(offset.GetX() + RATIO_CONSTANT * pointSize / 4, offset.GetY() + pointSize / 4);
338 path.Close();
339 SetEdgeStyle(point, pen);
340 canvas->AttachPen(pen);
341 canvas->DrawPath(path);
342 canvas->DetachPen();
343 break;
344 }
345 default: {
346 canvas->AttachBrush(brush);
347 canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), innerRadius);
348 canvas->DetachBrush();
349 SetEdgeStyle(point, pen);
350 canvas->AttachPen(pen);
351 canvas->DrawCircle(RSPoint(offset.GetX(), offset.GetY()), pointSize / 2);
352 canvas->DetachPen();
353 break;
354 }
355 }
356 }
357 #endif
358
PaintDatas(RenderContext & context,const Rect & paintRect)359 void RosenRenderChart::PaintDatas(RenderContext& context, const Rect& paintRect)
360 {
361 auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
362 if (!canvas) {
363 LOGE("Paint canvas is null");
364 return;
365 }
366 if (NearEqual(paintRect.Width(), 0.0) || NearEqual(paintRect.Height(), 0.0)) {
367 LOGE("data paint region width:%{public}lf height:%{public}lf", paintRect.Width(), paintRect.Height());
368 return;
369 }
370 if (type_ == ChartType::LINE) {
371 PaintLinearGraph(canvas, paintRect);
372 } else {
373 #ifndef USE_ROSEN_DRAWING
374 SkPaint paint;
375 paint.setAntiAlias(true);
376 paint.setStyle(SkPaint::Style::kStrokeAndFill_Style);
377 #else
378 RSPen pen;
379 RSBrush brush;
380 pen.SetAntiAlias(true);
381 brush.SetAntiAlias(true);
382 #endif
383
384 const int32_t barGroupNumber = static_cast<int32_t>(mainCharts_.size());
385 auto barsAreaNumber = horizontal_.tickNumber;
386 for (int32_t barGroupIndex = 0; barGroupIndex < barGroupNumber; ++barGroupIndex) {
387 auto barGroup = mainCharts_[barGroupIndex];
388 #ifndef USE_ROSEN_DRAWING
389 paint.setColor(barGroup.GetFillColor().GetValue());
390 PaintBar(canvas, paint, barGroup.GetData(), paintRect, barGroupNumber, barsAreaNumber, barGroupIndex);
391 #else
392 pen.SetColor(barGroup.GetFillColor().GetValue());
393 brush.SetColor(barGroup.GetFillColor().GetValue());
394 PaintBar(canvas, pen, brush, barGroup.GetData(), paintRect, barGroupNumber, barsAreaNumber, barGroupIndex);
395 #endif
396 }
397 }
398 }
399
UpdateLineGradientPoint(const std::vector<LineInfo> & pointInfo,const MainChart & line,const Rect & paintRect)400 void RosenRenderChart::UpdateLineGradientPoint(
401 const std::vector<LineInfo>& pointInfo, const MainChart& line, const Rect& paintRect)
402 {
403 if (line.GetHeadPointIndex() > 0 && line.GetErasePointNumber() > 0) {
404 startGradientIndex_ = static_cast<size_t>(line.GetHeadPointIndex() + line.GetErasePointNumber() - 1);
405 endGradientIndex_ = startGradientIndex_ + 1;
406 if (static_cast<size_t>(startGradientIndex_) >= pointInfo.size()) {
407 startGradientIndex_ = pointInfo.size() - 1;
408 }
409 if (static_cast<size_t>(endGradientIndex_) >= pointInfo.size()) {
410 endGradientIndex_ = pointInfo.size() - 1;
411 }
412 startGradientPoint_ = ConvertDataToPosition(paintRect, pointInfo[startGradientIndex_].GetPointInfo());
413 endGradientPoint_ = ConvertDataToPosition(paintRect, pointInfo[endGradientIndex_].GetPointInfo());
414 } else {
415 startGradientPoint_ = Offset(0.0, 0.0);
416 endGradientPoint_ = Offset(0.0, 0.0);
417 gradientOfLine_ = false;
418 }
419 }
420
421 #ifndef USE_ROSEN_DRAWING
PaintLinearGraph(SkCanvas * canvas,const Rect & paintRect)422 void RosenRenderChart::PaintLinearGraph(SkCanvas* canvas, const Rect& paintRect)
423 #else
424 void RosenRenderChart::PaintLinearGraph(RSCanvas* canvas, const Rect& paintRect)
425 #endif
426 {
427 for (const auto& line : mainCharts_) {
428 const auto& pointInfo = line.GetData();
429 if (pointInfo.empty()) {
430 // there is no data in current data set, and skip this line
431 continue;
432 }
433 auto previousSegment = pointInfo[0].GetSegmentInfo();
434 auto previousPoint = pointInfo[0].GetPointInfo();
435 Offset previousPosition = ConvertDataToPosition(paintRect, previousPoint);
436 startOffset_ = previousPosition;
437 #ifndef USE_ROSEN_DRAWING
438 SkPath edgePath;
439 SkPath gradientPath;
440 edgePath.moveTo(previousPosition.GetX(), previousPosition.GetY());
441 gradientPath.moveTo(previousPosition.GetX(), paintRect.Bottom());
442 gradientPath.lineTo(previousPosition.GetX(), previousPosition.GetY());
443 #else
444 RSRecordingPath edgePath;
445 RSRecordingPath gradientPath;
446 edgePath.MoveTo(previousPosition.GetX(), previousPosition.GetY());
447 gradientPath.MoveTo(previousPosition.GetX(), paintRect.Bottom());
448 gradientPath.LineTo(previousPosition.GetX(), previousPosition.GetY());
449 #endif
450
451 UpdateLineGradientPoint(pointInfo, line, paintRect);
452
453 for (size_t index = 1; index < pointInfo.size(); index++) {
454 const auto& currentPoint = pointInfo[index].GetPointInfo();
455 Offset currentPosition = ConvertDataToPosition(paintRect, currentPoint);
456 if (line.GetSmoothFlag()) {
457 bool isEnd = previousSegment != pointInfo[index].GetSegmentInfo();
458 AddCubicPath(gradientPath, paintRect, line.GetData(), index, isEnd);
459 AddCubicPath(edgePath, paintRect, line.GetData(), index, isEnd);
460 } else {
461 #ifndef USE_ROSEN_DRAWING
462 gradientPath.lineTo(currentPosition.GetX(), currentPosition.GetY());
463 edgePath.lineTo(currentPosition.GetX(), currentPosition.GetY());
464 #else
465 gradientPath.LineTo(currentPosition.GetX(), currentPosition.GetY());
466 edgePath.LineTo(currentPosition.GetX(), currentPosition.GetY());
467 #endif
468 }
469 wholeLineGradient_ = line.GetWholeLineGradient();
470 if (wholeLineGradient_) {
471 targetColor_ = line.GetTargetColor();
472 }
473 int32_t i = static_cast<int32_t>(index);
474 if ((line.GetHeadPointIndex() > 0) && (i > line.GetHeadPointIndex()) &&
475 (i <= line.GetHeadPointIndex() + line.GetErasePointNumber())) {
476 #ifndef USE_ROSEN_DRAWING
477 gradientPath.reset();
478 if (i < line.GetHeadPointIndex() + line.GetErasePointNumber()) {
479 edgePath.reset();
480 edgePath.moveTo(currentPosition.GetX(), currentPosition.GetY());
481 } else {
482 edgePath.lineTo(currentPosition.GetX(), currentPosition.GetY());
483 gradientPath.moveTo(currentPosition.GetX(), paintRect.Bottom());
484 gradientPath.lineTo(currentPosition.GetX(), currentPosition.GetY());
485 gradientOfLine_ = true;
486 }
487 #else
488 gradientPath.Reset();
489 if (i < line.GetHeadPointIndex() + line.GetErasePointNumber()) {
490 edgePath.Reset();
491 edgePath.MoveTo(currentPosition.GetX(), currentPosition.GetY());
492 } else {
493 edgePath.LineTo(currentPosition.GetX(), currentPosition.GetY());
494 gradientPath.MoveTo(currentPosition.GetX(), paintRect.Bottom());
495 gradientPath.LineTo(currentPosition.GetX(), currentPosition.GetY());
496 gradientOfLine_ = true;
497 }
498 #endif
499 previousSegment = pointInfo[index].GetSegmentInfo();
500 previousPoint = currentPoint;
501 previousPosition = currentPosition;
502 continue;
503 }
504 if (previousSegment != pointInfo[index].GetSegmentInfo() ||
505 (line.GetHeadPointIndex() > 0 && line.GetHeadPointIndex() == i)) {
506 #ifndef USE_ROSEN_DRAWING
507 gradientPath.lineTo(currentPosition.GetX(), paintRect.Bottom());
508 gradientPath.close();
509 if (line.GetGradient()) {
510 PaintLineGradient(canvas, gradientPath, paintRect, line.GetFillColor(), line.GetTopPoint());
511 }
512 PaintLineEdge(canvas, edgePath, previousSegment, line.GetLineWidth(), false);
513 // print gradient
514 gradientPath.reset();
515 edgePath.reset();
516 previousSegment = pointInfo[index].GetSegmentInfo();
517 previousPoint = currentPoint;
518 previousPosition = currentPosition;
519 edgePath.moveTo(previousPosition.GetX(), previousPosition.GetY());
520 gradientPath.moveTo(previousPosition.GetX(), paintRect.Bottom());
521 gradientPath.lineTo(previousPosition.GetX(), previousPosition.GetY());
522 #else
523 gradientPath.LineTo(currentPosition.GetX(), paintRect.Bottom());
524 gradientPath.Close();
525 if (line.GetGradient()) {
526 PaintLineGradient(canvas, gradientPath, paintRect, line.GetFillColor(), line.GetTopPoint());
527 }
528 PaintLineEdge(canvas, edgePath, previousSegment, line.GetLineWidth(), false);
529 // print gradient
530 gradientPath.Reset();
531 edgePath.Reset();
532 previousSegment = pointInfo[index].GetSegmentInfo();
533 previousPoint = currentPoint;
534 previousPosition = currentPosition;
535 edgePath.MoveTo(previousPosition.GetX(), previousPosition.GetY());
536 gradientPath.MoveTo(previousPosition.GetX(), paintRect.Bottom());
537 gradientPath.LineTo(previousPosition.GetX(), previousPosition.GetY());
538 #endif
539 } else {
540 previousSegment = pointInfo[index].GetSegmentInfo();
541 previousPoint = currentPoint;
542 previousPosition = currentPosition;
543 }
544 }
545 #ifndef USE_ROSEN_DRAWING
546 gradientPath.lineTo(previousPosition.GetX(), paintRect.Bottom());
547 gradientPath.close();
548 #else
549 gradientPath.LineTo(previousPosition.GetX(), paintRect.Bottom());
550 gradientPath.Close();
551 #endif
552 if (line.GetGradient()) {
553 PaintLineGradient(canvas, gradientPath, paintRect, line.GetFillColor(), line.GetTopPoint());
554 }
555 PaintLineEdge(canvas, edgePath, previousSegment, line.GetLineWidth(), true);
556 PaintStylePoints(canvas, paintRect, line);
557 PaintText(canvas, paintRect, line);
558 }
559 }
560
561 #ifndef USE_ROSEN_DRAWING
PaintLineEdge(SkCanvas * canvas,SkPath & path,const SegmentInfo segmentInfo,double thickness,bool drawGradient)562 void RosenRenderChart::PaintLineEdge(
563 SkCanvas* canvas, SkPath& path, const SegmentInfo segmentInfo, double thickness, bool drawGradient)
564 {
565 SkPaint paint;
566 paint.setAntiAlias(true);
567 paint.setColor(segmentInfo.GetSegmentColor().GetValue());
568 if (segmentInfo.GetLineType() == LineType::DASHED) {
569 SkPath subPath;
570 subPath.addRRect(
571 SkRRect::MakeRectXY(SkRect::MakeXYWH(0.0, -0.5 * thickness, segmentInfo.GetSolidWidth(), thickness),
572 0.5 * thickness, 0.5 * thickness));
573 paint.setPathEffect(SkPath1DPathEffect::Make(subPath, segmentInfo.GetSpaceWidth() +
574 segmentInfo.GetSolidWidth(), 5.0f, SkPath1DPathEffect::kMorph_Style));
575 } else {
576 paint.setStrokeWidth(thickness);
577 }
578 if (wholeLineGradient_) {
579 double end = startGradientPoint_.GetX();
580 if (NearZero(end)) {
581 end = startOffset_.GetX() + paintWidth_;
582 }
583 SkPoint points[2] = { SkPoint::Make(startOffset_.GetX(), 0.0f), SkPoint::Make(end, 0.0f) };
584 SkColor colors[2] = { segmentInfo.GetSegmentColor().GetValue(), targetColor_.GetValue() };
585 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2, SkTileMode::kClamp, 0, nullptr));
586 }
587 if (gradientOfLine_ && drawGradient) {
588 SkPoint points[2] = { SkPoint::Make(startGradientPoint_.GetX(), 0.0f),
589 SkPoint::Make(endGradientPoint_.GetX(), 0.0f) };
590 SkColor colors[2] = { segmentInfo.GetSegmentColor().ChangeAlpha(0).GetValue(),
591 segmentInfo.GetSegmentColor().GetValue() };
592 paint.setShader(SkGradientShader::MakeLinear(points, colors, nullptr, 2, SkTileMode::kClamp, 0, nullptr));
593 }
594 paint.setStyle(SkPaint::Style::kStroke_Style);
595 canvas->drawPath(path, paint);
596 }
597 #else
PaintLineEdge(RSCanvas * canvas,RSPath & path,const SegmentInfo segmentInfo,double thickness,bool drawGradient)598 void RosenRenderChart::PaintLineEdge(
599 RSCanvas* canvas, RSPath& path, const SegmentInfo segmentInfo, double thickness, bool drawGradient)
600 {
601 RSPen pen;
602 pen.SetAntiAlias(true);
603 pen.SetColor(segmentInfo.GetSegmentColor().GetValue());
604 if (segmentInfo.GetLineType() == LineType::DASHED) {
605 RSRecordingPath subPath;
606 subPath.AddRoundRect(
607 RSRoundRect(RSRect(0.0, -0.5 * thickness, segmentInfo.GetSolidWidth(), thickness - 0.5 * thickness),
608 0.5 * thickness, 0.5 * thickness));
609 pen.SetPathEffect(RSPathEffect::CreatePathDashEffect(
610 subPath, segmentInfo.GetSpaceWidth() + segmentInfo.GetSolidWidth(), 5.0f, RSPathDashStyle::MORPH));
611 } else {
612 pen.SetWidth(thickness);
613 }
614 if (wholeLineGradient_) {
615 double end = startGradientPoint_.GetX();
616 if (NearZero(end)) {
617 end = startOffset_.GetX() + paintWidth_;
618 }
619 std::vector<RSPoint> points = { RSPoint(startOffset_.GetX(), 0.0f), RSPoint(end, 0.0f) };
620 std::vector<RSColorQuad> colors = { segmentInfo.GetSegmentColor().GetValue(), targetColor_.GetValue() };
621 std::vector<RSScalar> pos = { 0.0f };
622 pen.SetShaderEffect(
623 RSShaderEffect::CreateLinearGradient(points.at(0), points.at(1), colors, pos, RSTileMode::CLAMP));
624 }
625 if (gradientOfLine_ && drawGradient) {
626 std::vector<RSPoint> points = { RSPoint(startGradientPoint_.GetX(), 0.0f),
627 RSPoint(endGradientPoint_.GetX(), 0.0f) };
628 std::vector<RSColorQuad> colors = { segmentInfo.GetSegmentColor().ChangeAlpha(0).GetValue(),
629 segmentInfo.GetSegmentColor().GetValue() };
630 std::vector<RSScalar> pos = { 0.0f };
631 pen.SetShaderEffect(
632 RSShaderEffect::CreateLinearGradient(points.at(0), points.at(1), colors, pos, RSTileMode::CLAMP));
633 }
634 canvas->AttachPen(pen);
635 canvas->DrawPath(path);
636 canvas->DetachPen();
637 }
638 #endif
639
640 #ifndef USE_ROSEN_DRAWING
PaintLineGradient(SkCanvas * canvas,SkPath & path,const Rect & paintRect,Color fillColor,const PointInfo & peekPoint)641 void RosenRenderChart::PaintLineGradient(
642 SkCanvas* canvas, SkPath& path, const Rect& paintRect, Color fillColor, const PointInfo& peekPoint)
643 {
644 SkPaint paint;
645 paint.setAntiAlias(true);
646 paint.setShader(CreateFillGradientShader(paintRect, fillColor, ConvertDataToPosition(paintRect, peekPoint).GetY()));
647
648 paint.setStyle(SkPaint::Style::kStrokeAndFill_Style);
649 canvas->drawPath(path, paint);
650 }
651 #else
PaintLineGradient(RSCanvas * canvas,RSPath & path,const Rect & paintRect,Color fillColor,const PointInfo & peekPoint)652 void RosenRenderChart::PaintLineGradient(
653 RSCanvas* canvas, RSPath& path, const Rect& paintRect, Color fillColor, const PointInfo& peekPoint)
654 {
655 RSPen pen;
656 RSBrush brush;
657 pen.SetAntiAlias(true);
658 brush.SetAntiAlias(true);
659 pen.SetShaderEffect(
660 CreateFillGradientShader(paintRect, fillColor, ConvertDataToPosition(paintRect, peekPoint).GetY()));
661 brush.SetShaderEffect(
662 CreateFillGradientShader(paintRect, fillColor, ConvertDataToPosition(paintRect, peekPoint).GetY()));
663 canvas->AttachPen(pen);
664 canvas->AttachBrush(brush);
665 canvas->DrawPath(path);
666 canvas->DetachPen();
667 canvas->DetachBrush();
668 }
669 #endif
670
671 #ifndef USE_ROSEN_DRAWING
CreateFillGradientShader(const Rect & paintRect,const Color & fillColor,double top)672 sk_sp<SkShader> RosenRenderChart::CreateFillGradientShader(const Rect& paintRect, const Color& fillColor, double top)
673 {
674 SkPoint points[2] = { SkPoint::Make(paintRect.GetOffset().GetX(), top),
675 SkPoint::Make(paintRect.GetOffset().GetX(), paintRect.GetOffset().GetY() + paintRect.Height()) };
676 SkColor colors[2] = { fillColor.GetValue(), fillColor.ChangeAlpha(0).GetValue() };
677 return SkGradientShader::MakeLinear(points, colors, nullptr, 2, SkTileMode::kClamp, 0, nullptr);
678 }
679 #else
CreateFillGradientShader(const Rect & paintRect,const Color & fillColor,double top)680 std::shared_ptr<RSShaderEffect> RosenRenderChart::CreateFillGradientShader(
681 const Rect& paintRect, const Color& fillColor, double top)
682 {
683 std::vector<RSPoint> points = { RSPoint(paintRect.GetOffset().GetX(), top),
684 RSPoint(paintRect.GetOffset().GetX(), paintRect.GetOffset().GetY() + paintRect.Height()) };
685 std::vector<RSColorQuad> colors = { fillColor.GetValue(), fillColor.ChangeAlpha(0).GetValue() };
686 std::vector<RSScalar> pos = { 0.0f };
687
688 return RSShaderEffect::CreateLinearGradient(points.at(0), points.at(1), colors, pos, RSTileMode::CLAMP);
689 }
690 #endif
691
CalculateControlA(const Offset & prev,const Offset & cur,const Offset & next)692 Offset RosenRenderChart::CalculateControlA(const Offset& prev, const Offset& cur, const Offset& next)
693 {
694 return Offset(cur.GetX() + (next.GetX() - prev.GetX()) / BEZIER_CONSTANT,
695 cur.GetY() + (next.GetY() - prev.GetY()) / BEZIER_CONSTANT);
696 }
697
CalculateControlB(const Offset & cur,const Offset & next,const Offset & nextNext)698 Offset RosenRenderChart::CalculateControlB(const Offset& cur, const Offset& next, const Offset& nextNext)
699 {
700 return Offset(next.GetX() - (nextNext.GetX() - cur.GetX()) / BEZIER_CONSTANT,
701 next.GetY() - (nextNext.GetY() - cur.GetY()) / BEZIER_CONSTANT);
702 }
703
704 #ifndef USE_ROSEN_DRAWING
PaintLine(uint32_t startIndex,const std::vector<LineInfo> & line,SkPath & path,const MainChart & data,const Rect & paintRect)705 int32_t RosenRenderChart::PaintLine(
706 uint32_t startIndex, const std::vector<LineInfo>& line, SkPath& path, const MainChart& data, const Rect& paintRect)
707 #else
708 int32_t RosenRenderChart::PaintLine(
709 uint32_t startIndex, const std::vector<LineInfo>& line, RSPath& path, const MainChart& data, const Rect& paintRect)
710 #endif
711 {
712 uint32_t index = startIndex;
713 startIndex_ = startIndex;
714 bool startPoint = true;
715 for (; index < line.size(); index++) {
716 const auto& point = line[index].GetPointInfo();
717 if (point.GetX() > horizontal_.max || point.GetX() < horizontal_.min || point.GetY() > vertical_.max ||
718 point.GetY() < vertical_.min) {
719 continue;
720 }
721 if (startPoint) {
722 Offset position = ConvertDataToPosition(paintRect, point);
723 #ifndef USE_ROSEN_DRAWING
724 if (data.GetGradient() && !drawLine_) {
725 path.moveTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
726 path.lineTo(position.GetX(), position.GetY());
727 } else {
728 path.moveTo(position.GetX(), position.GetY());
729 }
730 #else
731 if (data.GetGradient() && !drawLine_) {
732 path.MoveTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
733 path.LineTo(position.GetX(), position.GetY());
734 } else {
735 path.MoveTo(position.GetX(), position.GetY());
736 }
737 #endif
738 startPoint = false;
739 } else if (index == line.size() - 1 ||
740 (data.GetHeadPointIndex() >= 0 && (index == static_cast<uint32_t>(data.GetHeadPointIndex())))) {
741 Offset position = ConvertDataToPosition(paintRect, point);
742 #ifndef USE_ROSEN_DRAWING
743 if (data.GetSmoothFlag()) {
744 AddCubicPath(path, paintRect, line, index, true);
745 } else {
746 path.lineTo(position.GetX(), position.GetY());
747 }
748 if (data.GetGradient() && !drawLine_) {
749 path.lineTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
750 }
751 #else
752 if (data.GetSmoothFlag()) {
753 AddCubicPath(path, paintRect, line, index, true);
754 } else {
755 path.LineTo(position.GetX(), position.GetY());
756 }
757 if (data.GetGradient() && !drawLine_) {
758 path.LineTo(position.GetX(), paintRect.GetOffset().GetY() + paintRect.GetSize().Height());
759 }
760 #endif
761 index += 1;
762 break;
763 } else {
764 if (data.GetSmoothFlag()) {
765 AddCubicPath(path, paintRect, line, index, false);
766 } else {
767 Offset position = ConvertDataToPosition(paintRect, point);
768 #ifndef USE_ROSEN_DRAWING
769 path.lineTo(position.GetX(), position.GetY());
770 #else
771 path.LineTo(position.GetX(), position.GetY());
772 #endif
773 }
774 }
775 }
776 return index;
777 }
778
779 #ifndef USE_ROSEN_DRAWING
AddCubicPath(SkPath & path,const Rect & paintRect,const std::vector<LineInfo> & line,uint32_t index,bool isEnd)780 void RosenRenderChart::AddCubicPath(
781 SkPath& path, const Rect& paintRect, const std::vector<LineInfo>& line, uint32_t index, bool isEnd)
782 #else
783 void RosenRenderChart::AddCubicPath(
784 RSPath& path, const Rect& paintRect, const std::vector<LineInfo>& line, uint32_t index, bool isEnd)
785 #endif
786 {
787 // use control point A = [(Xi + (Xi+1 - Xi-1) / 4), (Yi + (Yi+1 - Yi-1) / 4)]
788 // and control point B = [(Xi+1 - (Xi+2 - Xi) / 4), (Yi+1 - (Yi+2 - Yi) / 4)]
789 if (index > 0 && index < line.size()) {
790 Offset prev = ConvertDataToPosition(
791 paintRect, line[(index < 2 || index - 2 < startIndex_) ? startIndex_ : index - 2].GetPointInfo());
792 Offset cur = ConvertDataToPosition(paintRect, line[index - 1].GetPointInfo());
793 Offset next = ConvertDataToPosition(paintRect, line[index].GetPointInfo());
794 Offset nextNext = ConvertDataToPosition(paintRect,
795 (isEnd || index + 1 >= line.size()) ? line[index].GetPointInfo() : line[index + 1].GetPointInfo());
796 Offset controlA = CalculateControlA(prev, cur, next);
797 Offset controlB = CalculateControlB(cur, next, nextNext);
798 #ifndef USE_ROSEN_DRAWING
799 path.cubicTo(controlA.GetX(), controlA.GetY(), controlB.GetX(), controlB.GetY(), next.GetX(), next.GetY());
800 #else
801 path.CubicTo(controlA.GetX(), controlA.GetY(), controlB.GetX(), controlB.GetY(), next.GetX(), next.GetY());
802 #endif
803 } else {
804 LOGW("index out of region");
805 }
806 }
807
PaintHorizontalAxis(RenderContext & context,const Rect & paintRect)808 void RosenRenderChart::PaintHorizontalAxis(RenderContext& context, const Rect& paintRect)
809 {
810 auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
811 if (!canvas) {
812 LOGE("Paint canvas is null");
813 return;
814 }
815 const Offset offset = paintRect.GetOffset();
816 #ifndef USE_ROSEN_DRAWING
817 SkPaint paint;
818 paint.setAntiAlias(true);
819 paint.setColor(horizontal_.color.GetValue());
820 paint.setStyle(SkPaint::Style::kStroke_Style);
821 paint.setStrokeWidth(DEFAULT_AXIS_STROKE_WIDTH);
822 #else
823 RSPen pen;
824 pen.SetAntiAlias(true);
825 pen.SetColor(horizontal_.color.GetValue());
826 pen.SetWidth(DEFAULT_AXIS_STROKE_WIDTH);
827 #endif
828
829 if ((horizontal_.tickNumber <= 0) || (horizontal_.tickNumber + 1 == 0)) {
830 horizontal_.tickNumber = DEFAULT_AXISTICK;
831 }
832 tickHorizontalOffset_ = (paintRect.Width() - 2 * EDGE_PADDING) / (horizontal_.tickNumber + 1);
833
834 if (!horizontal_.display) {
835 return;
836 }
837
838 double tickPosition = EDGE_PADDING + tickHorizontalOffset_;
839 #ifndef USE_ROSEN_DRAWING
840 for (int32_t index = 0; index < horizontal_.tickNumber; index++) {
841 canvas->drawLine(offset.GetX() + tickPosition, offset.GetY(), offset.GetX() + tickPosition,
842 offset.GetY() + TICK_LENGTH, paint);
843 tickPosition += tickHorizontalOffset_;
844 }
845
846 canvas->drawLine(offset.GetX(), offset.GetY() + 0.5 * TICK_LENGTH, offset.GetX() + paintRect.Width(),
847 offset.GetY() + 0.5 * TICK_LENGTH, paint);
848 #else
849 canvas->AttachPen(pen);
850 for (int32_t index = 0; index < horizontal_.tickNumber; index++) {
851 canvas->DrawLine(RSPoint(offset.GetX() + tickPosition, offset.GetY()),
852 RSPoint(offset.GetX() + tickPosition, offset.GetY() + TICK_LENGTH));
853 tickPosition += tickHorizontalOffset_;
854 }
855
856 canvas->DrawLine(RSPoint(offset.GetX(), offset.GetY() + 0.5 * TICK_LENGTH),
857 RSPoint(offset.GetX() + paintRect.Width(), offset.GetY() + 0.5 * TICK_LENGTH));
858 canvas->DetachPen();
859 #endif
860 }
861
PaintVerticalAxis(RenderContext & context,const Offset & offset,const Rect & paintRect)862 void RosenRenderChart::PaintVerticalAxis(RenderContext& context, const Offset& offset, const Rect& paintRect)
863 {
864 auto canvas = static_cast<RosenRenderContext*>(&context)->GetCanvas();
865 if (!canvas) {
866 LOGE("Paint canvas is null");
867 return;
868 }
869
870 #ifndef USE_ROSEN_DRAWING
871 SkPaint paint;
872 paint.setAntiAlias(true);
873 paint.setColor(vertical_.color.GetValue());
874 paint.setStyle(SkPaint::Style::kStroke_Style);
875 paint.setStrokeWidth(DEFAULT_AXIS_STROKE_WIDTH);
876 #else
877 RSPen pen;
878 pen.SetAntiAlias(true);
879 pen.SetColor(vertical_.color.GetValue());
880 pen.SetWidth(DEFAULT_AXIS_STROKE_WIDTH);
881 #endif
882
883 if ((vertical_.tickNumber <= 0) || (vertical_.tickNumber + 1 == 0)) {
884 vertical_.tickNumber = DEFAULT_AXISTICK;
885 }
886 tickOffset_ = (paintRect.Height() - 2 * EDGE_PADDING) / (vertical_.tickNumber + 1);
887
888 if (!vertical_.display) {
889 return;
890 }
891
892 double tickPosition = EDGE_PADDING + tickOffset_;
893 #ifndef USE_ROSEN_DRAWING
894 for (int32_t index = 0; index < vertical_.tickNumber; index++) {
895 canvas->drawLine(offset.GetX() + paintRect.Width() - TICK_LENGTH, offset.GetY() + tickPosition,
896 offset.GetX() + paintRect.Width(), offset.GetY() + tickPosition, paint);
897 tickPosition += tickOffset_;
898 }
899
900 canvas->drawLine(offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY(),
901 offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY() + paintRect.Height(), paint);
902 #else
903 canvas->AttachPen(pen);
904 for (int32_t index = 0; index < vertical_.tickNumber; index++) {
905 canvas->DrawLine(RSPoint(offset.GetX() + paintRect.Width() - TICK_LENGTH, offset.GetY() + tickPosition),
906 RSPoint(offset.GetX() + paintRect.Width(), offset.GetY() + tickPosition));
907 tickPosition += tickOffset_;
908 }
909
910 canvas->DrawLine(RSPoint(offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY()),
911 RSPoint(offset.GetX() + paintRect.Width() - 0.5 * TICK_LENGTH, offset.GetY() + paintRect.Height()));
912 canvas->DetachPen();
913 #endif
914 }
915
916 #ifndef USE_ROSEN_DRAWING
PaintBar(SkCanvas * canvas,SkPaint & paint,const std::vector<LineInfo> & barGroupData,const Rect & paintRect,int32_t barGroupNum,int32_t barsAreaNum,int32_t barGroupIndex)917 void RosenRenderChart::PaintBar(SkCanvas* canvas, SkPaint& paint, const std::vector<LineInfo>& barGroupData,
918 const Rect& paintRect, int32_t barGroupNum, int32_t barsAreaNum, int32_t barGroupIndex)
919 #else
920 void RosenRenderChart::PaintBar(RSCanvas* canvas, RSPen& pen, RSBrush brush, const std::vector<LineInfo>& barGroupData,
921 const Rect& paintRect, int32_t barGroupNum, int32_t barsAreaNum, int32_t barGroupIndex)
922 #endif
923 {
924 if (NearEqual(paintRect.Width(), 0.0) || NearEqual(paintRect.Height(), 0.0)) {
925 LOGE("data paint region width:%{public}lf height:%{public}lf", paintRect.Width(), paintRect.Height());
926 return;
927 }
928 const int32_t barSize = static_cast<int32_t>(barGroupData.size());
929 for (int32_t barIndex = 0; barIndex < barSize; ++barIndex) {
930 const auto point = barGroupData[barIndex].GetPointInfo();
931 // If the actual number of data exceeds Tick, the extra part will not be laid out
932 if (barIndex >= barsAreaNum) {
933 return;
934 }
935 auto barsAreaPaintRect = GetBarsAreaPaintRect(paintRect, barIndex);
936 double barInterval = BARS_INTERVAL_PROPORTION;
937 auto context = GetContext().Upgrade();
938 if (context && context->GetMinPlatformVersion() >= MIN_SDK_VERSION) {
939 barInterval = 0;
940 }
941 auto barAreaPaintRect = GetBarAreaPaintRect(barsAreaPaintRect, barGroupIndex, barGroupNum, barInterval);
942 Offset position = ConvertDataToPosition(paintRect, point);
943 // barAreaPaintRect left add bar interval is originX
944 auto originX = barAreaPaintRect.GetOffset().GetX() +
945 (BAR_INTERVAL_PROPORTION / 2) * barAreaPaintRect.Width();
946 auto originY = position.GetY();
947
948 #ifndef USE_ROSEN_DRAWING
949 canvas->drawRect(
950 SkRect::MakeLTRB(originX, originY, originX + barAreaPaintRect.Width() * (1 - BAR_INTERVAL_PROPORTION),
951 paintRect.GetOffset().GetY() + paintRect.Height()),
952 paint);
953 #else
954 canvas->AttachPen(pen);
955 canvas->AttachBrush(brush);
956 canvas->DrawRect(RSRect(originX, originY, originX + barAreaPaintRect.Width() * (1 - BAR_INTERVAL_PROPORTION),
957 paintRect.GetOffset().GetY() + paintRect.Height()));
958 canvas->DetachPen();
959 canvas->DetachBrush();
960 #endif
961 }
962 }
963
GetBarsAreaPaintRect(const Rect & paintRect,int32_t barsAreaIndex)964 Rect RosenRenderChart::GetBarsAreaPaintRect(const Rect& paintRect, int32_t barsAreaIndex)
965 {
966 auto barsAreaWidth = paintRect.Width() / horizontal_.tickNumber;
967 auto barsAreaHeight = paintRect.Height();
968 Rect barsAreaRect =
969 Rect(paintRect.Left() + barsAreaIndex * barsAreaWidth, paintRect.Top(), barsAreaWidth, barsAreaHeight);
970 return barsAreaRect;
971 }
972
GetBarAreaPaintRect(const Rect & barsAreaPaintRect,int32_t barGroupIndex,int32_t barGroupNumber,double barInterval)973 Rect RosenRenderChart::GetBarAreaPaintRect(
974 const Rect& barsAreaPaintRect, int32_t barGroupIndex, int32_t barGroupNumber, double barInterval)
975 {
976 // Divide 30% of the horizontal space of barsArea into 2 parts as left and right intervals,
977 // and divide the remaining part by barGroupNumber to get barAreaWidth
978 auto barAreaWidth = (1 - barInterval) * barsAreaPaintRect.Width() / barGroupNumber;
979 auto barAreaHeight = barsAreaPaintRect.Height();
980 // After leaving the interval, the left border of the barArea area is obtained
981 auto barAreaLeft =
982 barsAreaPaintRect.Left() + barInterval / 2 * barsAreaPaintRect.Width() + barGroupIndex * barAreaWidth;
983 Rect barAreaRect = Rect(barAreaLeft, barsAreaPaintRect.Top(), barAreaWidth, barAreaHeight);
984 return barAreaRect;
985 }
986
987 } // namespace OHOS::Ace
988