微信小程序canvas 实现信用图表

前言:APP当时模仿着阿里支付宝画了一个图标,当初是以java去实现的。现在在开发公司的微信小程序,又根据当时写的代码通过微信小程序canvas的相关接口。从头又画了一次,对微信小程序的canvas理解更加深刻了。在这里直接贴一下代码,记录一下。也给需要的小伙伴一些参考。

效果图:


wxml:

<!--pages/mine/report/report.wxml-->
<view class='container'>
  <canvas canvas-id="credit-canvas" class='credit-canvas'></canvas>

</view>
js:

// pages/mine/report/report.js
Page({

  /**
   * 页面的初始数据
   */
  data: {
    canvasWidth: 0,
    canvasHeight: 0,
    currentNum: 500,
    timeText:"2017-12"
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    //获取画布大小
    const that = this;
    wx.createSelectorQuery().select(".credit-canvas").boundingClientRect(function (rect) {
      that.setData({
        canvasWidth: rect.width,
        canvasHeight: rect.height
      })
    }).exec()
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    this.drawCredit();
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
    this.timeout = setTimeout(this.drawCredit, 100);
  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  },
  drawCredit: function () {
    const that = this;
    const ctx = wx.createCanvasContext('credit-canvas');
    // 圆弧半径
    const radius = this.data.canvasWidth * 3 / 10;
    // 内圆宽度
    const sweepInWidth = 10;
    // 外圆宽度
    const sweepOutWidth = 3;
    // 圆弧初始的弧度
    const startAngle = 0.9 * Math.PI;
    // 圆弧结束的弧度
    const endAngle = 2.1 * Math.PI;
    // 圆弧扫过的弧度
    const sweepAngle = 1.2 * Math.PI;
    // 信用分值
    let currentNum = that.data.currentNum
    // 信用评级
    const leverText = ["C", "CC", "CCC", "B", "BB", "BBB", "A", "AA", "AAA"];
    // 信用等级
    const creditLeverText = ["差", "欠佳", "一般", "较好", "良好", "优良"];
    ctx.translate(this.data.canvasWidth / 2, this.data.canvasHeight * 3 / 4);
    // 画内外圆弧
    function drawRound() {
      // 内圆
      // 保存画布
      ctx.save();
      // 每次设置画笔时要调用这个beginPath,非则以最后一次为准。
      ctx.beginPath();
      // 设置画笔宽度
      ctx.setLineWidth(sweepInWidth);
      // 设置画笔颜色
      ctx.setStrokeStyle('rgba(255, 255, 255, 0.2)')
      // 画内圆弧形,角度为162度~378度,起始位置由于调用过ctx.translate(this.data.canvasWidth/2,this.data.canvasHeight*3/4);,所以在中心位置
      ctx.arc(0, 0, radius, startAngle, endAngle);
      // 描绘路径边框
      ctx.stroke();
      // 画外圆
      ctx.beginPath()
      ctx.setLineWidth(sweepOutWidth);
      ctx.setStrokeStyle('rgba(255, 255, 255, 0.2)')
      ctx.arc(0, 0, radius + 10, startAngle, endAngle);
      ctx.stroke();
      // 还原画布
      ctx.restore();
    }

    function drawScale() {
      // 画刻度
      const startNum = 300;
      // 画布旋转弧度
      const angle = 6 * Math.PI / 180;
      ctx.save();
      ctx.rotate((-1.5 * Math.PI) + startAngle)
      for (let i = 0; i <= 36; i++) {
        if (i % 6 === 0) {
          //画粗刻度并写数值
          ctx.beginPath()
          ctx.setLineWidth(2)
          ctx.setStrokeStyle('rgba(255, 255, 255, 0.7)')
          ctx.moveTo(0, -radius - sweepInWidth / 2);
          ctx.lineTo(0, -radius + sweepInWidth / 2 + 1);
          ctx.stroke()

          // 设置文字画笔          
          ctx.setFontSize(9)
          ctx.setTextAlign('center')
          ctx.setFillStyle('rgba(255, 255, 255, 0.4)')
          if (i === 36) {
            ctx.fillText(">1000", 0, -radius + 15)
          } else if (i === 0) {
            ctx.fillText("0-300", 0, -radius + 15)
          } else {
            ctx.fillText(startNum + (i / 6 * 100) + "", 0, -radius + 15)
          }
        } else {
          ctx.beginPath()
          ctx.setLineWidth(1)
          ctx.setStrokeStyle('rgba(255, 255, 255, 0.4)')
          ctx.moveTo(0, -radius - sweepInWidth / 2);
          ctx.lineTo(0, -radius + sweepInWidth / 2 + 1);
          ctx.stroke()
        }
        if (i === 3 || i === 9 || i === 15 || i === 21 || i === 27 || i === 33) {
          ctx.fillText(leverText[((i - 3) / 6) + 3], 0, -radius + 15)
        }
        ctx.rotate(angle)
      }
      // 还原画布
      ctx.restore();
    }

    function drawIndicator() {
      ctx.save();
      let sweep = 0;
      if (currentNum <= 300) {
        sweep = 0;
      } else if (currentNum <= 800 && currentNum > 300) {
        sweep = (currentNum - 300) * sweepAngle / 600;
      } else if (currentNum > 800 && currentNum <= 1000) {
        sweep = (5 * sweepAngle / 6) + ((currentNum - 800) * sweepAngle / 1200);
      } else {
        sweep = sweepAngle;
      }

      // 画指示点圆弧
      const grd = ctx.createLinearGradient(0, 0, 200, 0)
      grd.addColorStop(0, 'rgba(255, 255, 255, 0.4)')
      grd.addColorStop(1, 'rgba(255, 255, 255, 0.7)')
      ctx.beginPath()
      ctx.setStrokeStyle(grd)
      ctx.setLineWidth(sweepOutWidth);
      ctx.arc(0, 0, radius + 10, startAngle, startAngle+sweep);
      ctx.stroke()
      // 画指示点
      let x = (radius + 10) * Math.cos(startAngle + sweep)
      let y = (radius + 10) * Math.sin(startAngle + sweep)
      ctx.beginPath()
      ctx.setStrokeStyle('white')
      ctx.fill()
      ctx.arc(x,y,3,0,2*Math.PI)
      ctx.stroke()
      // 还原画布
      ctx.restore();
    }

    function drawCenterText(){
      ctx.save();
      //设置文字画笔
      ctx.beginPath();
      ctx.setFontSize(radius/6)
      ctx.setTextAlign('center')
      ctx.setFillStyle('white')
      let lever="信用等级:"
      if (currentNum < 100) {
        lever += leverText[0];
      } else if (currentNum >= 100 && currentNum < 200) {
        lever += leverText[1];
      } else if (currentNum >= 200 && currentNum < 300) {
        lever += leverText[2];
      } else if (currentNum >= 300 && currentNum < 400) {
        lever += leverText[3];
      } else if (currentNum >= 400 && currentNum < 500) {
        lever += leverText[4];
      } else if (currentNum >= 500 && currentNum < 600) {
        lever += leverText[5];
      } else if (currentNum >= 600 && currentNum < 700) {
        lever += leverText[6];
      } else if (currentNum >= 700 && currentNum < 800) {
        lever += leverText[7];
      } else if (currentNum >= 800) {
        lever += leverText[8];
      }
      ctx.fillText(lever, 0, -radius / 2)

      // 绘制信用分值
      ctx.setFontSize(radius / 4)
      ctx.fillText(currentNum, 0, -radius / 6)

      // 绘制信用评估
      let content = "信用";
      let maxNum=1000;
      if (currentNum < maxNum * 4 / 10) {
        content += creditLeverText[0];
      } else if (currentNum >= maxNum * 4 / 10 && currentNum < maxNum * 5 / 10) {
        content += creditLeverText[1];
      } else if (currentNum >= maxNum * 5 / 10 && currentNum < maxNum * 6 / 10) {
        content += creditLeverText[2];
      } else if (currentNum >= maxNum * 6 / 10 && currentNum < maxNum * 7 / 10) {
        content += creditLeverText[3];
      } else if (currentNum >= maxNum * 7 / 10 && currentNum < maxNum * 8 / 10) {
        content += creditLeverText[4];
      } else if (currentNum >= maxNum * 8 / 10) {
        content += creditLeverText[5];
      }
      ctx.setFontSize(radius / 4)
      ctx.fillText(content, 0, radius / 8)

      // 评估时间
      ctx.setFontSize(15)
      ctx.setFillStyle('rgba(255,255,255,0.4)')
      ctx.fillText("评估时间:" + that.data.timeText, 0, radius / 3)

      // 还原画布
      ctx.restore();

      console.log("正在画画.....")
    }

    drawRound();
    drawScale();
    drawIndicator();
    drawCenterText();
    ctx.draw()
  },

})


wxss:

/* pages/mine/report/report.wxss */
page{
  height: 100%;
}

.credit-canvas{
  width: 100%;
  height: 35%;
  background-image: url("http://www.datacubr.com/img/bg_report.png");
  background-size: 100% 100%;
  background-repeat: no-repeat;
}




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值