HarmonyOS-MPChart根据y轴刻度绘制渐变色曲线

2024-06-23 14:12

本文主要是介绍HarmonyOS-MPChart根据y轴刻度绘制渐变色曲线,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

本文是基于鸿蒙三方库mpchart(OpenHarmony-SIG/ohos-MPChart)的使用,自定义绘制方法,绘制一条颜色渐变的曲线。

mpchart本身的绘制功能是不支持颜色渐变的曲线的,只支持渐变色填充大块颜色。那么当我们的需求曲线根据y轴的刻度发生变化,就需要自定义绘制方法了。

从图中我们可以看到,左边的y轴是一个从底部到顶部颜色渐变的直线,从绿色渐变到红色,而且数据曲线根据y轴刻度做同样的渐变色。所以我们需要修改的就是两个部件的绘制效果,一个是左y轴的绘制效果,一个是数据线的绘制效果。它们涉及到两个绘制类:

YAxisRenderer 和 LineChartRenderer

首先来看数据线的绘制方法,因为这里以曲线为例,所以我们只需要修改绘制曲线的方法,找到mpchart源码中LineChartRenderer类的drawCubicBezier方法,我们自定义一个MyDataRender类继承自LineChartRenderer类,然后将LineChartRenderer类的drawCubicBezier方法复制到自定义的类中,在其基础上做修改:

主要的修改就是将canvas的strokeStyle设置为我们通过createLinearGradient方法创建的渐变色效果。这段代码创建了一个从底部到顶部的垂直渐变,颜色从绿色到红色变化,并将这个渐变应用到了Canvas的描边样式中。

完整代码如下:

import { EntryOhos, ILineDataSet, Style, Transformer, Utils, LineChartRenderer } from '@ohos/mpchart';export default class MyDataRender extends LineChartRenderer{protected drawCubicBezier(c: CanvasRenderingContext2D, dataSet: ILineDataSet) {if (!this.mChart || !this.mXBounds) {return;}const phaseY: number = this.mAnimator ? this.mAnimator.getPhaseY() : 1;const trans: Transformer | null = this.mChart.getTransformer(dataSet.getAxisDependency());this.mXBounds.set(this.mChart, dataSet);const intensity: number = dataSet.getCubicIntensity();let cubicPath = new Path2D();// cubicPath.reset();if (this.mXBounds.range >= 1) {let prevDx: number = 0;let prevDy: number = 0;let curDx: number = 0;let curDy: number = 0;// Take an extra point from the left, and an extra from the right.// That's because we need 4 points for a cubic bezier (cubic=4), otherwise we get lines moving and doing weird stuff on the edges of the chart.// So in the starting `prev` and `cur`, go -2, -1// And in the `lastIndex`, add +1const firstIndex: number = this.mXBounds.min + 1;const lastIndex: number = this.mXBounds.min + this.mXBounds.range;let prevPrev: EntryOhos | null;let prev: EntryOhos | null = dataSet.getEntryForIndex(Math.max(firstIndex - 2, 0));let cur: EntryOhos | null = dataSet.getEntryForIndex(Math.max(firstIndex - 1, 0));let next: EntryOhos | null = cur;let nextIndex: number = -1;if (cur === null) return;Utils.resetContext2DWithoutFont(c, this.mRenderPaint);// let the spline startcubicPath.moveTo(cur.getX(), cur.getY() * phaseY);for (let j: number = this.mXBounds.min + 1; j <= this.mXBounds.range + this.mXBounds.min; j++) {prevPrev = prev;prev = cur;cur = nextIndex === j ? next : dataSet.getEntryForIndex(j);nextIndex = j + 1 < dataSet.getEntryCount() ? j + 1 : j;next = dataSet.getEntryForIndex(nextIndex);prevDx = (cur.getX() - prevPrev.getX()) * intensity;prevDy = (cur.getY() - prevPrev.getY()) * intensity;curDx = (next.getX() - prev.getX()) * intensity;curDy = (next.getY() - prev.getY()) * intensity;cubicPath.bezierCurveTo(prev.getX() + prevDx,(prev.getY() + prevDy) * phaseY,cur.getX() - curDx,(cur.getY() - curDy) * phaseY,cur.getX(),cur.getY() * phaseY);}}// if filled is enabled, close the pathif (dataSet.isDrawFilledEnabled()) {let cubicFillPath: Path2D = new Path2D();// cubicFillPath.reset();cubicFillPath.addPath(cubicPath);if (c && trans) {this.drawCubicFill(c, dataSet, cubicFillPath, trans, this.mXBounds);}}// this.mRenderPaint.setColor(dataSet.getColor());// this.mRenderPaint.setStyle(Style.STROKE);let grad = c.createLinearGradient(0, this.mChart.getHeight(), 0, 0);grad.addColorStop(0.0, '#00ff00')grad.addColorStop(1.0, '#ff0000')c.strokeStyle = grad;if (trans) {cubicPath = trans.pathValueToPixel(cubicPath);}Utils.resetContext2DWithoutFont(c, this.mRenderPaint);c.beginPath();c.stroke(cubicPath);c.closePath();this.mRenderPaint.setDashPathEffect(null);}
}

数据线的绘制方法修改完了,之后就是修改y轴的绘制方法了。与数据线的绘制类似,定义一个自定义类MyAxisRender继承自YAxisRenderer类,然后修改绘制左y轴的方法,即renderAxisLine方法:

同样是创建了一个从底部到顶部的垂直渐变,颜色从绿色到红色变化,并将这个渐变应用到了Canvas的描边样式中。

完整代码如下:

import { EntryOhos, ILineDataSet, Style, Transformer, Utils, LineChartRenderer, XAxisRenderer,YAxisRenderer,AxisDependency} from '@ohos/mpchart';export default class MyAxisRender extends YAxisRenderer{public renderAxisLine(c: CanvasRenderingContext2D, extraLength: number): void {if (!this.mYAxis || !this.mViewPortHandler || !this.mYAxis.isEnabled() || !this.mYAxis.isDrawAxisLineEnabled()) {return;}if (this.mAxisLinePaint) {this.mAxisLinePaint.setColor(this.mYAxis.getAxisLineColor());this.mAxisLinePaint.setStrokeWidth(this.mYAxis.getAxisLineWidth());Utils.resetContext2DWithoutFont(c, this.mAxisLinePaint);if (this.mYAxis.getAxisDependency() == AxisDependency.LEFT) {c.beginPath()let grad = c.createLinearGradient(0, this.mViewPortHandler.contentBottom() + extraLength, 0, this.mViewPortHandler.contentTop());grad.addColorStop(0.0, '#00ff00')grad.addColorStop(1.0, '#ff0000')c.strokeStyle = grad;c.moveTo(this.mViewPortHandler.contentLeft(), this.mViewPortHandler.contentTop());c.lineTo(this.mViewPortHandler.contentLeft(), this.mViewPortHandler.contentBottom() + extraLength)c.stroke();c.closePath();} else {c.beginPath()c.moveTo(this.mViewPortHandler.contentRight(), this.mViewPortHandler.contentTop());c.lineTo(this.mViewPortHandler.contentRight(), this.mViewPortHandler.contentBottom() + extraLength)c.stroke();c.closePath();}}}}

 最后就是使用代码了,代码如下:

import {JArrayList,EntryOhos,ILineDataSet,LineData,LineChart,LineChartModel,Mode,LineDataSet,AxisDependency,XAxisPosition,
} from '@ohos/mpchart';
import MyAxisRender from './MyAxisRender';
import data from '@ohos.telephony.data';
import MyAxisLeftRender from './MyAxisRender';
import MyDataRender from './MyDataRender';@Entry
@Component
struct Index {private model: LineChartModel = new LineChartModel();aboutToAppear() {// 创建一个 JArrayList 对象,用于存储 EntryOhos 类型的数据let values: JArrayList<EntryOhos> = new JArrayList<EntryOhos>();// 循环生成 1 到 20 的随机数据,并添加到 values 中for (let i = 1; i <= 20; i++) {values.add(new EntryOhos(i, Math.random() * 100));}// 创建 LineDataSet 对象,使用 values 数据,并设置数据集的名称为 'DataSet'let dataSet = new LineDataSet(values, 'DataSet');dataSet.setMode(Mode.CUBIC_BEZIER);dataSet.setDrawCircles(false);let dataSetList: JArrayList<ILineDataSet> = new JArrayList<ILineDataSet>();dataSetList.add(dataSet);// 创建 LineData 对象,使用 dataSetList数据,并将其传递给modellet lineData: LineData = new LineData(dataSetList);this.model?.setData(lineData);this.model.getAxisLeft()?.setAxisLineWidth(2);this.model.getXAxis()?.setPosition(XAxisPosition.BOTTOM);this.model.getAxisRight()?.setEnabled(false);this.model.getDescription()?.setEnabled(false);this.model.setRenderer(new MyDataRender(this.model, this.model.getAnimator()!, this.model.getViewPortHandler()))this.model.setRendererLeftYAxis(new MyAxisLeftRender(this.model.getViewPortHandler(), this.model.getAxisLeft()!, this.model.getTransformer(AxisDependency.LEFT)!))}build() {Column() {LineChart({ model: this.model }).width('100%').height('50%').backgroundColor(Color.White)}}
}

其中主要修改的代码就是这里,设置了绘制y轴线的类和绘制数据的类为我们自定义的两个类:

this.model.setRenderer(new MyDataRender(this.model, this.model.getAnimator()!, this.model.getViewPortHandler()))
this.model.setRendererLeftYAxis(new MyAxisLeftRender(this.model.getViewPortHandler(), this.model.getAxisLeft()!, this.model.getTransformer(AxisDependency.LEFT)!))

好了,再看一遍绘制效果:

这篇关于HarmonyOS-MPChart根据y轴刻度绘制渐变色曲线的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1087387

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

【WebGPU Unleashed】1.1 绘制三角形

一部2024新的WebGPU教程,作者Shi Yan。内容很好,翻译过来与大家共享,内容上会有改动,加上自己的理解。更多精彩内容尽在 dt.sim3d.cn ,关注公众号【sky的数孪技术】,技术交流、源码下载请添加微信号:digital_twin123 在 3D 渲染领域,三角形是最基本的绘制元素。在这里,我们将学习如何绘制单个三角形。接下来我们将制作一个简单的着色器来定义三角形内的像素

Flutter 进阶:绘制加载动画

绘制加载动画:由小圆组成的大圆 1. 定义 LoadingScreen 类2. 实现 _LoadingScreenState 类3. 定义 LoadingPainter 类4. 总结 实现加载动画 我们需要定义两个类:LoadingScreen 和 LoadingPainter。LoadingScreen 负责控制动画的状态,而 LoadingPainter 则负责绘制动画。

利用matlab bar函数绘制较为复杂的柱状图,并在图中进行适当标注

示例代码和结果如下:小疑问:如何自动选择合适的坐标位置对柱状图的数值大小进行标注?😂 clear; close all;x = 1:3;aa=[28.6321521955954 26.2453660695847 21.69102348512086.93747104431360 6.25442246899816 3.342835958564245.51365061796319 4.87

PR曲线——一个更敏感的性能评估工具

在不均衡数据集的情况下,精确率-召回率(Precision-Recall, PR)曲线是一种非常有用的工具,因为它提供了比传统的ROC曲线更准确的性能评估。以下是PR曲线在不均衡数据情况下的一些作用: 关注少数类:在不均衡数据集中,少数类的样本数量远少于多数类。PR曲线通过关注少数类(通常是正类)的性能来弥补这一点,因为它直接评估模型在识别正类方面的能力。 精确率与召回率的平衡:精确率(Pr

【HarmonyOS】-TaskPool和Worker的对比实践

ArkTS提供了TaskPool与Worker两种多线程并发方案,下面我们将从其工作原理、使用效果对比两种方案的差异,进而选择适用于ArkTS图片编辑场景的并发方案。 TaskPool与Worker工作原理 TaskPool与Worker两种多线程并发能力均是基于 Actor并发模型实现的。Worker主、子线程通过收发消息进行通信;TaskPool基于Worker做了更多场景化的功能封装,例

YOLOv8/v10+DeepSORT多目标车辆跟踪(车辆检测/跟踪/车辆计数/测速/禁停区域/绘制进出线/绘制禁停区域/车道车辆统计)

01:YOLOv8 + DeepSort 车辆跟踪 该项目利用YOLOv8作为目标检测模型,DeepSort用于多目标跟踪。YOLOv8负责从视频帧中检测出车辆的位置,而DeepSort则负责关联这些检测结果,从而实现车辆的持续跟踪。这种组合使得系统能够在视频流中准确地识别并跟随特定车辆。 02:YOLOv8 + DeepSort 车辆跟踪 + 任意绘制进出线 在此基础上增加了用户

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数

【鸿蒙HarmonyOS NEXT】页面之间相互传递参数 一、环境说明二、页面之间相互传参 一、环境说明 DevEco Studio 版本: API版本:以12为主 二、页面之间相互传参 说明: 页面间的导航可以通过页面路由router模块来实现。页面路由模块根据页面url找到目标页面,从而实现跳转。通过页面路由模块,可以使用不同的url访问不同的页面,包括跳转到U

HarmonyOS】ArkTS学习之基于TextTimer的简易计时器的elapsedTime最小时间单位问题

本文旨在纪录自己对TextTimer使用过程的疑惑问题 我在查看教程时候,发现很多博客在onTimer(event: (utc: number, elapsedTime: number) => void) 这里提到elapsedTime:计时器经过的时间,单位为毫秒。我不清楚是否为版本问题。 在我查看version11和version10的api时候,说的都是设置格式的最小单位。 经过个人检验的

使用matplotlib绘制散点图、柱状图和饼状图-学习篇

一、散点图 Python代码如下: num_points = 100x = np.random.rand(num_points) #x点位随机y = np.random.rand(num_points) #y点位随机colors = np.random.rand(num_points) #颜色随机sizes = 1000 * np.random.rand(num_points) # 大