canvas实现一个‘百分比数据’可视化

514 阅读2分钟


引子:ui设计出一个这样的效果,你打算怎么实现?

我是用canvas实现的,开发了一个组件,通过配置参数props可以设置宽高,颜色(自己根据ui设计改组件里的源码),缝隙宽度等属性。代码如下:

<template><div class="progressBarStyle"> <el-row>    <el-col :span="24">      <div class="canvasStyle">        <canvas id="progressBarCanvas" width="610" height="70">          此浏览器不支持canvas!        </canvas>      </div>    </el-col>  </el-row></div></template>

<script>export default {  name: 'progressBar',  props: {    settingParams: {      type: Object,      default () {        return {}      }    }  },  data () {    return {      defaultParams: {        // 此数值取7~92之间,不然图会变形。0和100单独处理        progressNum: 8,        // 宽度        progressW: 600,        // 高度        progressH: 48,        // 中间缝隙宽度        gapW: 10      }    }  },  mounted () {    // 合并参数    this.defaultParams = Object.assign({}, this.defaultParams, this.settingParams)    // 初始化绘图    this.initProgressBar()  },  watch: {    defaultParams () {      this.initProgressBar()    }  },  methods: {    /**     * 绘制左边     * leftLenBottom 左边图的底部宽度     * leftLenTop 左边图的顶部宽度     * */    renderLeft (leftLenBottom, leftLenTop) {      let pCan = document.getElementById('progressBarCanvas')      let pCo = pCan.getContext('2d')      let gradient = pCo.createLinearGradient(32, 0, this.defaultParams.progressW, 0)      gradient.addColorStop(0, '#FF8686')      gradient.addColorStop(1, '#E98245')
      let gradient1 = pCo.createLinearGradient(32, 0, this.defaultParams.progressW, 0)      gradient1.addColorStop(0, 'rgba(221,151,20,0.47)')      gradient1.addColorStop(1, 'rgba(206,110,77,1)')      pCo.strokeStyle = gradient      pCo.fillStyle = gradient1
      pCo.beginPath()      pCo.moveTo(32, 0)      pCo.lineTo(32, this.defaultParams.progressH)      pCo.lineTo(leftLenBottom, this.defaultParams.progressH)      pCo.lineTo(leftLenTop, 0)      pCo.closePath()      pCo.stroke()      pCo.fill()    },    /**     * 绘制右边     * rightLenBottom 右边图的底部宽度     * rightLenTop 右边图的顶部宽度     * */    renderRight (rightLenBottom, rightLenTop) {      let pCan = document.getElementById('progressBarCanvas')      let pCo = pCan.getContext('2d')      let gradient2 = pCo.createLinearGradient(0, 0, this.defaultParams.progressW, 0)      gradient2.addColorStop(0, '#6BE5FF')      gradient2.addColorStop(1, '#3AEC96')      let gradient3 = pCo.createLinearGradient(0, 0, this.defaultParams.progressW, 0)      gradient3.addColorStop(0, 'rgba(121,246,211,0.49)')      gradient3.addColorStop(1, 'rgba(58,120,236,0.53)')      pCo.strokeStyle = gradient2      pCo.fillStyle = gradient3
      pCo.beginPath()      pCo.moveTo(rightLenTop + this.defaultParams.gapW, 0)      pCo.lineTo(this.defaultParams.progressW, 0)      pCo.lineTo(this.defaultParams.progressW, this.defaultParams.progressH)      pCo.lineTo(rightLenBottom + this.defaultParams.gapW, this.defaultParams.progressH)      pCo.closePath()      pCo.stroke()      pCo.fill()    },    // 绘图    initProgressBar () {      let pCan = document.getElementById('progressBarCanvas')      let pCo = pCan.getContext('2d')      pCo.clearRect(0, 0, this.defaultParams.progressW, this.defaultParams.progressH)      let len = this.defaultParams.progressNum      let leftLenBottom = 0      let leftLenTop = 0      // 输入的progressNum数字小于0按0处理      if (len <= 0) {        leftLenBottom = 0        leftLenTop = 0        this.renderRight(leftLenBottom, leftLenTop)      } else if (len >= 100) {        // 输入的progressNum数字大于100按全长处理        leftLenBottom = this.defaultParams.progressW        leftLenTop = this.defaultParams.progressW        this.renderLeft(leftLenBottom, leftLenTop)      } else {        // 一般情况处理,当gapW变化时,这里可能还需要调整        len = len < 7 ? 7 : len        len = len > 92 ? 92 : len
        leftLenBottom = this.defaultParams.progressW * len / 100 + 36        leftLenTop = this.defaultParams.progressW * len / 100 - 10
        this.renderLeft(leftLenBottom, leftLenTop)        this.renderRight(leftLenBottom, leftLenTop)      }    }  }}</script>

<style lang="scss" scoped>.progressBarStyle {  width: 100%;  height: 76px;}.canvasStyle {  text-align: left;}</style>

使用的方法和一般的组件使用一样,

import progressBar from './progressBar'

components内注册一下:

<progressBar :settingParams="{progressNum: videoStorageData.used * 100, gapW: 16, progressH: 20, progressW: 400}" />

ok,这样就可以了。改进的地方就是对传进来的props参数是极端值时的处理。代码中已有一些写法,还有就是做到颜色可配置,多传几个参数即可。