折线图绘制思路

  • 绘制坐标轴
    • 利用 Canvas 画布缩放的能力

const createCoordinateSystem = () => {
  context.scale(1, -1)
  context.translate(0, -height)

  context.beginPath()
  context.moveTo(0, 0)
  context.lineTo(width, 0)
  context.stroke()
  context.strokeStyle = '#000'

  context.beginPath()
  context.moveTo(0, 0)
  context.lineTo(0, height)
  context.stroke()
  context.strokeStyle = '#000'
}
  • 绘制平行 X 轴的线条

for (let i = 0; i < 6; i++) {
  context.translate(0, 30)
  createLine(0, 0, width, 0)
}
  • 绘制刻度

context.save()
// 绘制坐标轴
...

context.restore()
for (let i = 0; i < 8; i++) {
  createLine(0, 0, 0, -5)
  context.lineWidth = 0.2
  context.translate(45, 0)
}
  • 绘制 x 轴下方文字

// 绘制 x 轴下方文字
ctx.save()
ctx.scale(1, -1)
for (let i = 0; i < xArr.length; i++) {
  ctx.fillStyle = '#000'
  if (i === 0) {
    const textWidth = ctx.measureText(xArr[i])
    ctx.translate(perXLength / 2 - textWidth.width / 2, 15)
  } else {
    ctx.translate(perXLength, 0)
  }
  ctx.fillText(xArr[i], 0, 0)
}
ctx.restore()
  • 绘制折线与圆
// 绘制折线
ctx.save()
for (let i = 0; i < xArr.length - 1; i++) {
  ctx.fillStyle = '#000'
  const curPointX = (1 / 2 + i) * perXLength
  const curPointY = valueArr[i]
  const nextPointX = (1 / 2 + i + 1) * perXLength
  const nextPointY = valueArr[i + 1]
  this.drawLine({ ctx: ctx, x0: curPointX, y0: curPointY, x1: nextPointX, y1: nextPointY })
}
ctx.restore()

// 绘制圆
ctx.save()
for (let i = 0; i < xArr.length - 1; i++) {
  ctx.fillStyle = '#000'
  const pointX = (1 / 2 + i + 1) * perXLength
  const pointY = valueArr[i + 1]
  ctx.beginPath()
  ctx.arc(pointX, pointY, 2, 0, Math.PI * 2, true)
  ctx.stroke()
}
ctx.restore()

todo: 平滑的折线图: https://juejin.cn/post/6950684708443258894#heading-23