鸿蒙NEXT开发浅进阶到精通04:基于 Canvas 实现 XY 轴折线图单例

写在前面

在鸿蒙 Next 应用开发的领域中,数据可视化是提升用户体验和交互性的关键环节。本文将结合实际案例,深入解析如何利用鸿蒙 Next 的 Canvas API 实现一个基础的 XY 轴折线图,帮助开发者快速掌握数据可视化的核心技术。

在许多应用场景中,如统计报表、数据分析等,折线图能够直观地展示数据随时间或其他维度的变化趋势。鸿蒙 Next 提供了强大的 Canvas 绘图能力,它允许开发者在应用中动态绘制各种图形,是实现数据可视化的理想选择。本文案例通过 Canvas API 在鸿蒙 Next 应用中绘制一个简单的 XY 轴折线图,展示一段时间内的数据变化。

核心代码解析

1-创建画图容器和配置画图参数

  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)


   Canvas(this.context)
        .width('90%')
        .height(300)
        .backgroundColor('rgba(0,0,0,0.5)')

2-确定x轴个点画横轴上的日期(所有的标点和划线动作放在onready里,后续参考使用时可以放在对应逻辑内)

2.1这里注意鸿蒙Canvas的坐标轴方向,在y轴上是跟我们数学上的常用y轴方向是反向的,所以在定义任何点的y轴时,你可以选择负值,或者用你的高度来减去你想要的y轴值,画出来才正常,本案例使用后者

  • 绘制 X 轴标题:通过设置fonttextAlign属性,使用fillText方法在指定位置绘制 X 轴上的日期标签,如 “2-10”、“2-11” 等。
  • 绘制 Y 轴值:同样利用fillText方法,根据数据对应的 Y 坐标绘制 Y 轴上的数据值,如 “90”、“170” 等。
  • 绘制折线:通过多次调用beginPathmoveTolineTostroke方法,分阶段绘制折线。每次调用beginPath开始新的路径绘制,moveTo确定起点,lineTo连接各个数据点,最后stroke绘制出折线。例如,第一段折线从(30, 300 - 50)连接到(90, 300 - 90)

cke_44268.png

2.2画x轴横轴日期

 // x轴标题
          this.context.font = '15vp sans-serif'
          this.context.textAlign = 'center'
          // 又因为y轴和我们的容器高度相同所以,本案例y轴反向时,横轴上的y坐标值都是300,以此类推
          this.context.fillText("2-10", 30, 300)
          this.context.fillText("2-11", 90, 300)
          this.context.fillText("2-12", 150, 300)
          this.context.fillText("2-13", 210, 300)
          this.context.fillText("2-14", 270, 300)
          this.context.fillText("2-15", 330, 300)
          this.context.fillText("2-16", 390, 300)

2.3确定两个点,画第一根线

 // y轴值
//  第一根线的两个点
          this.context.textAlign = 'end'
          this.context.fillText("90", 90, 300-90)
          this.context.fillText("170", 210, 300-170)

          // 第1段划线
          this.context.beginPath()
          this.context.lineWidth = 3
          this.context.strokeStyle = 'rgb(255,0,0)'
          this.context.moveTo(30, 300-50)
          this.context.lineTo(90,300-90)
          this.context.stroke()

2.4好的,正常来说,粘贴上面的代码,你就可以得到第一根线了,然后我们画完,这里考虑新手和总结规律,并没有使用Foreach,对一组点数据数据来进行优化

 
        // 第二段划线
          this.context.moveTo(90,300-90)
          this.context.lineTo(150,300-140)//起始为x0,结尾为最后一个数据的x
          this.context.stroke()
          // 第3段划线
          this.context.moveTo(150,300-140)
          this.context.lineTo(210,300-170)
          this.context.stroke()
           // 第4-5-6---n段划线

2.5我们再看其中的主要API

执行划线this.context.beginPath()

一根线的起点this.context.moveTo(30, 300-50)

一根线的终点this.context.lineTo(90,300-90)

渲染划线路径this.context.stroke()

官网API文档中心,在这里页面ctrl+f搜对应的方法名即可

// 画点
 this.context.fillText("2-10", 30, 300)
//  执行划线
 this.context.beginPath()
//  设置线宽和颜色
          this.context.lineWidth = 3
          this.context.strokeStyle = 'rgb(255,0,0)'
          // 起始点
          this.context.moveTo(30, 300-50)
          // 一根线终点
          this.context.lineTo(90,300-90)
          // 渲染路径
          this.context.stroke()

2.6这里提示大家,可以先在纸上或者Excel中画出来你想要的效果折线图,这样在画后面的多根线,就不会迷乱,

然后,老惯例上完全代码,

@Entry
@Component
struct Page3 {
  @State img: string = '';
  private settings: RenderingContextSettings = new RenderingContextSettings(true)
  private context: CanvasRenderingContext2D = new CanvasRenderingContext2D(this.settings)
  build() {
    Column() {
      Canvas(this.context)
        .width('90%')
        .height(300)
        .backgroundColor('rgba(0,0,0,0.5)')
        .onReady(() => {
          // x轴标题
          this.context.font = '15vp sans-serif'
          this.context.textAlign = 'center'
          this.context.fillText("2-10", 30, 300)
          this.context.fillText("2-11", 90, 300)
          this.context.fillText("2-12", 150, 300)
          this.context.fillText("2-13", 210, 300)
          this.context.fillText("2-14", 270, 300)
          this.context.fillText("2-15", 330, 300)
          this.context.fillText("2-16", 390, 300)
          // y轴值
          this.context.textAlign = 'end'
          this.context.fillText("90", 90, 300-90)
          this.context.fillText("170", 210, 300-170)

          // 第1段划线
          this.context.beginPath()
          this.context.lineWidth = 3
          this.context.strokeStyle = 'rgb(255,0,0)'
          this.context.moveTo(30, 300-50)
          this.context.lineTo(90,300-90)
          this.context.stroke()
          // 第二段划线
          this.context.moveTo(90,300-90)
          this.context.lineTo(150,300-140)
          this.context.stroke()
          // 第3段划线
          this.context.moveTo(150,300-140)
          this.context.lineTo(210,300-170)
          this.context.stroke()
          // 第4段划线
          this.context.moveTo(210,300-170)
          this.context.lineTo(270,300-230)
          this.context.stroke()
          // 第5段划线
          this.context.moveTo(270,300-230)
          this.context.lineTo(330,300-260)
          this.context.stroke()
          // 第6段划线
          this.context.moveTo(330,300-260)
          this.context.lineTo(390,300-290)
          this.context.stroke()
        //   新起一条线路横线标记每个y值
          this.context.beginPath()
          this.context.strokeStyle = 'rgb(5,66,230)'
          this.context.lineWidth = 1
          this.context.setLineDash([10,20])
          this.context.moveTo(0,300-90) //起始为x0,结尾为最后一个数据的x
          this.context.lineTo(390,300-90)
          this.context.stroke()
          //   新起一条线路横线标记每个y值
          this.context.beginPath()
          this.context.strokeStyle = 'rgb(5,66,230)'
          this.context.lineWidth = 1
          this.context.setLineDash([10,20])
          this.context.moveTo(0,300-170) //起始为x0,结尾为最后一个数据的x
          this.context.lineTo(390,300-170)
          this.context.stroke()
        })
    }
    .height('100%')
    .width('100%')
    .alignItems(HorizontalAlign.Center)
    .margin({top :100})
  }
}

写在最后

通过简单的逐步分析案例,相信你可以有更多拓展

  1. 数据动态绑定:目前案例中的数据是硬编码在绘图逻辑中的,实际应用中可通过在更新数据的逻辑中执行画线操作,只要数据是动态接收的就可以动态画线,从后端接口或本地数据源动态获取数据,实现图表的实时更新。
  2. 图表交互性:可以添加触摸事件监听器,实现图表的缩放、平移、数据点提示等交互功能,提升用户体验。
  3. 图表样式优化:进一步丰富折线图的样式,如添加数据点标记、不同颜色区分折线、添加图例说明等,使图表更加专业和美观。
  4. 多图表类型支持:基于 Canvas 的绘图能力,拓展支持柱状图、饼图等其他常见的数据可视化图表类型,满足多样化的业务需求。

如果看到这里,不妨点个赞加个关注哦,嘿嘿,就很棒

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值