canvas 绘制柱状图表

复制代码即可用

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title>canvas</title>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <style>
      .box {
        position: absolute;
        top: 10px;
        left: 10px;
        border: 1px solid greenyellow;
      }
      #canvas {
        border: 1px solid green;
      }
      #rightBottom {
        width: 50px;
        height: 50px;
        border: 1px solid red;
        position: absolute;
        bottom: 0;
        right: 0;
        cursor: se-resize;
      }
      #centerBox {
        width: 50px;
        height: 50px;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-left: -25px;
        margin-top: -25px;
        border: 1px solid red;
        cursor: pointer;
      }
    </style>
  </head>
  <body>
    <div class="box">
      <canvas id="canvas" width="600" height="500"></canvas>
      <div id="centerBox"></div>
      <div id="rightBottom"></div>
    </div>

    <script>
      let data = [
        { xAxis: 2012, value: 2141 },
        { xAxis: 2013, value: 1499 },
        { xAxis: 2014, value: 3260 },
        { xAxis: 2015, value: 1170 },
        { xAxis: 2016, value: 970 },
        { xAxis: 2017, value: 2350 }
      ]
      let canvas = document.getElementById('canvas'),
        ctx = canvas.getContext('2d'),
        width = null,
        height = null,
        current = 0,
        yRatio = 0,
        padding = 0,
        yNumber = 0,
        yLength = 0,
        xLength = 0,
        box = document.querySelector('#rightBottom'),
        flag = false,
        centerBox = document.querySelector('#centerBox'),
        totalBox = document.querySelector('.box'),
        moveFlag = false
      resize()
      function resize() {
        width = canvas.width
        height = canvas.height
        padding = 50
        if (flag) {
          current = 99
        }
        init()
        looping()
      }

      function init() {
        //=== 坐标轴 ===
        ctx.beginPath()
        ctx.lineWidth = 1
        //y轴
        ctx.moveTo(padding + 0.5, height - padding + 0.5)
        ctx.lineTo(padding + 0.5, padding + 0.5)
        ctx.stroke()
        //x轴
        ctx.moveTo(padding + 0.5, height - padding + 0.5)
        ctx.lineTo(width - padding + 0.5, height - padding + 0.5)
        ctx.stroke()
        //y轴 x轴 刻度和值
        yNumber = 5
        yLength = Math.floor((height - padding * 2) / yNumber)
        xLength = Math.floor((width - padding * 2) / data.length)
        yRatio = yLength / 700
        // ctx.beginPath()
        ctx.textAlign = 'center'
        ctx.fillStyle = '#000'
        ctx.strokeStyle = '#000'
        // y轴刻度和值

        for (let i = 0; i < yLength; i++) {
          let y = 700 * (i + 1),
            ylen = yLength * (i + 1)

          ctx.moveTo(padding + 5, height - padding - ylen)
          ctx.lineTo(padding, height - padding - ylen)
          ctx.stroke()
          ctx.fillText(y, padding - 15, height - padding - ylen + 5)
        }
        // x轴刻度和值
        for (let j = 0; j < data.length; j++) {
          let xAxis = data[j].xAxis,
            xlen = yLength * (j + 1)
          ctx.moveTo(padding + xlen, height - padding)
          ctx.lineTo(padding + xlen, height - padding + 5)
          ctx.stroke() // 画轴线上的刻度
          ctx.fillText(
            xAxis,
            padding + xlen - xLength / 2,
            height - padding + 15
          ) // 填充文字
        }
      }
      function looping() {
        looped = requestAnimationFrame(looping)
        if (current < 100) {
          // current 用来计算当前柱状的高度占最终高度的百分之几,通过不断循环实现柱状上升的动画
          current = current + 3 > 100 ? 100 : current + 3
          drawAnimation()
        } else {
          window.cancelAnimationFrame(looped)
          looped = null
        }
      }

      function drawAnimation() {
        for (let i = 0; i < data.length; i++) {
          var x = Math.ceil(((data[i].value * current) / 100) * yRatio)
          var y = height - padding - x
          ctx.fillRect(padding + xLength * (i + 0.2), y, xLength / 2, x)
          // 保存每个柱状的信息
          data[i].left = padding + xLength / 4 + xLength * i
          data[i].top = y
          data[i].right = padding + (3 * xLength) / 4 + xLength * i
          data[i].bottom = height - padding
        }
      }

      // 实现canva 的缩放

      box.onmousedown = e => {
        e.stopPropagation()
        flag = true
        let boxWidth = width,
          boxHeight = height,
          xClick = e.pageX,
          yClick = e.pageY

        window.onmousemove = event => {
          if (flag) {
            let eX = event.pageX,
              eY = event.pageY,
              absX = (eX - xClick) / boxWidth,
              absY = (eY - yClick) / boxHeight

            canvas.width = (1 + absX) * boxWidth
            canvas.height = (1 + absY) * boxHeight
            resize()
          }
        }
      }

      window.onmouseup = () => {
        flag = false
        moveFlag = false
      }

      centerBox.onmousedown = e => {
        moveFlag = true
      }
      centerBox.onmouseup = e => {
        moveFlag = false
      }
      totalBox.onmousedown = e => {
        let boxTop = e.pageX - totalBox.offsetLeft,
          boxLeft = e.pageY - totalBox.offsetTop
        window.onmousemove = event => {
          if (moveFlag) {
            let eX = event.pageX - boxTop,
              eY = event.pageY - boxLeft

            totalBox.style.top = eY + 'px'
            totalBox.style.left = eX + 'px'
          }
        }
      }
    </script>
  </body>
</html>

发布了45 篇原创文章 · 获赞 14 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/cmchenmei/article/details/84344667