canvas之旅系列----(一)

787 阅读3分钟

使用canvas绘制柱状图

使用canvasApi来绘制一个柱状图,其效果如下。gitee源码地址github源码地址

canva绘制柱状图

想要绘制上图所示的一个柱状图,我们需要将整个过程分为如下几个步骤

  • 绘制坐标轴

    • 绘制坐标轴
    • 添加文字
    • 添加刻度
  • 绘制柱状图

接下来展示一如何一步一步的来绘制出如图的一个柱状图。

准备工作

在echarts使用中,有很多的配置,为了我们在绘制柱状图的过程中能够更加方便,首先创建一个和Echarts类似的一个配置项

const canvas = document.getElementById('canvas')
const context = canvas.getContext('2d')
let options = {
  chartZone: [50, 50, 700, 450],//坐标轴的顶点
  yAxisLable: ['0', '100', '200', '300', '400'],//y轴刻度
  yMax: 400,//y轴最大值
  xAxisLable: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],//x轴刻度
  data: [10, 50, 200, 330, 390, 320, 220],//数据
  barStyle: {//状状体的的配置
    width: 70,
    color: '#1abc9c'
  }
}

drawBarChart(options)

function drawBarChart(options) {
  context.fillStyle = '#ffffff'
  context.fillRect(0, 0, canvas.width, canvas.height)
  context.fillStyle = '#000000'
  drawAxis(options)
  drawYLable(options)
  drawXLable(options)
  // drawData(options)
  drawDataWithGradient(options)
  //如想将绘制的图形保存为jpg,可使用以下代码
  // let el = document.createElement('a')
  // el.href = canvas.toDataURL("image/jpeg")
  // el.download = '柱状图.jpg'
  // el.click()
}

绘制坐标轴

y轴绘制

function drawYLable (options) {
  let lables = options.yAxisLable
  let yLength = (options.chartZone[3] - options.chartZone[1]) * 0.98
  let gap = yLength / (lables.length - 1)

  lables.forEach(function (lable, index) {
    // 填标签
    let offset = context.measureText(lable).width + 20
    context.strokeStyle = '#eaeaea'
    context.font = '16px'
    context.fillText(lable, options.chartZone[0] - offset, options.chartZone[3] - index * gap)
    // 绘制小间隔
    context.beginPath()
    context.strokeStyle = '#353535'
    context.moveTo(options.chartZone[0] - 10, options.chartZone[3] - index * gap)
    context.lineTo(options.chartZone[0], options.chartZone[3] - index * gap)
    context.stroke()
    // 绘制横向辅助线
    if(index !== 0) {
      context.beginPath()
      context.setLineDash([8, 8])
      context.strokeStyle = '#aeaeae'
      context.strokeWidth = 2
      context.moveTo(options.chartZone[0], options.chartZone[3] - index * gap)
      context.lineTo(options.chartZone[2], options.chartZone[3] - index * gap)
      context.stroke()
      context.setLineDash([])
      context.strokeWidth = 4
    }
  })
}

坐标轴的绘制主要包括了轴的绘制和标刻两个工作,x轴的绘制类似y轴绘制。但再y轴的绘制中,加入了横向的一个辅助线的绘制,采用了虚线绘制,在绘制完成后要改回实线。

x轴绘制略。

数据绘制

function drawData(options) {
  let data = options.data
  let yLength = (options.chartZone[3] - options.chartZone[1]) * 0.98
  let xLength = (options.chartZone[2] - options.chartZone[0]) * 0.98
  let gap = xLength / options.xAxisLable.length

  data.forEach(function(item, index) {
    let x0 = options.chartZone[2] - (options.xAxisLable.length - index) * gap + gap / 2 - options.barStyle.width / 2
    let height = item / options.yMax * yLength
    let y0 = options.chartZone[3] - height
    let width = options.barStyle.width
    context.fillStyle = options.barStyle.color ||'#1abc9c'
    context.fillRect(x0, y0, width, height)
  })
}

数据的绘制就是在对应位置上绘制上一个矩形。如果想会绘制一个带渐变的矩形,可以使用createLinearGradient方法:

function drawDataWithGradient(options) {
  let data = options.data
  let yLength = (options.chartZone[3] - options.chartZone[1]) * 0.98
  let xLength = (options.chartZone[2] - options.chartZone[0]) * 0.98
  let gap = xLength / options.xAxisLable.length
  let fillStyleGradient = context.createLinearGradient((options.chartZone[0]+options.chartZone[2])/2, options.chartZone[1],(options.chartZone[0]+options.chartZone[2])/2, options.chartZone[3])
  fillStyleGradient.addColorStop(0, options.barStyle.color || '#1abc9c')
  fillStyleGradient.addColorStop(1, 'rgba(1, 176, 241, 1)')

  data.forEach(function(item, index) {
    let x0 = options.chartZone[2] - (options.xAxisLable.length - index) * gap + gap / 2 - options.barStyle.width / 2
    let height = item / options.yMax * yLength
    let y0 = options.chartZone[3] - height
    let width = options.barStyle.width
    context.fillStyle = fillStyleGradient
    context.fillRect(x0, y0, width, height)
  })
}

总结

对于canvas绘图而言,其核心就是计算各个图形改绘制在哪里,从对矩形图的绘制可以看出,先找准坐标轴的顶点,其他都是依照坐标轴的位置来进行绘制的。所以在canvas的绘图过程中,首要便是找准参考点,其他位置则相对于参考点计算并绘制即可。