美文网首页
小程序canvas自定义圆弧进度条(不是显示在最上层)---进化

小程序canvas自定义圆弧进度条(不是显示在最上层)---进化

作者: hao_developer | 来源:发表于2023-04-22 09:15 被阅读0次

    效果图对比 上边使用wx.createCanvasContext('circle'),canva画出来的会显示在最上层,下边使用wx.createSelectorQuery()canvas画出来会显示正常

    如果想在使用canvas做的自定义组件的当前页面要显示弹出框或者是蒙层,wx.createCanvasContext('circle')画出来的永远都是显示在页面最上层,wx.createSelectorQuery()画出来的显示正常

    如果在页面中使用canvas,使用wx.createSelectorQuery()
    如果是自定义组件使用canvas,使用wx.createSelectorQuery().in(this)

    image.png

    效果图

    image.png

    思路

    考虑到背景是不变的,把背景和会动的分为两个canvas来进行画


    image.png
    image.png

    wxss

    page{
      background: #fd7895;
    }
    
    .component-slider {
      width: 90%;
      position: relative;
      margin: 0rpx auto 0rpx;
      padding: 70rpx 0 70rpx;
    }
    
    /* 盒子 */
    .slider-box {
      width: 88%;
      margin: 0 auto;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
    
    /* 未选中区线 */
    .slider-line {
      width: 100%;
      height: 10rpx;
      background: rgba(91, 150, 246, 0.1);
      margin: 0 auto;
      position: absolute;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
    }
    
    /* 选中区线 */
    .slider-line-active {
      position: absolute;
      left: 0;
      top: 50%;
      transform: translate(0, -50%);
      height: 10rpx;
      background: #5B96F6;
    }
    
    /* slider按钮 */
    .slider-btn {
      width: 70rpx;
      height: 35rpx;
      background: #5B96F6;
      border-radius: 20rpx;
    }
    
    /* 显示的数字 */
    .slider-number {
      width: 100%;
      position: absolute;
      bottom: -10rpx;
    }
    
    .slider-number text {
      position: absolute;
      top: 0;
      font-size: 24rpx;
      color: #999999;
      transition: all 0.3s;
    }
    
    /* 当前选中的数字 */
    .slider-number text.active {
      font-size: 32rpx;
      color: #5B96F6;
      transition: all 0.3s;
    }
    
    /* slider组件设置透明 */
    slider {
      opacity: 0;
    }
    

    wxml

    
    <view style="position: relative;margin-top: 100rpx;">
      <canvas id="circle" type="2d" style="border: 1rpx solid red;width: 90vw;height: 90vw;margin: 0 auto;"></canvas>
      <canvas id="circle2" type="2d" style="border: 1rpx solid green;width: 90vw;height: 90vw;margin: 0 auto;position: absolute;top: 0;right: 0;bottom: 0;left: 0;z-index: 10;"></canvas>
    </view>
    <view style="display: flex;flex-direction: row;margin-top: 50rpx;padding: 0 40rpx;">
      <button bindtap="btnHandler" data-type="{{1}}" type="default" style="margin-right: 50rpx;">加+1</button>
      <button bindtap="btnHandler" data-type="{{2}}" type="default">减-1</button>
    </view>
    <view style="display: flex;flex-direction: row;margin-top: 50rpx;padding: 0 40rpx;">
      <button bindtap="clickHandler" data-type="{{1}}" type="default" style="margin-right: 50rpx;">开始</button>
      <button bindtap="clickHandler" data-type="{{2}}" type="default">结束</button>
    </view>
    

    js

    const app = getApp();
    
    Page({
      data: {
        min: 0, // 最小限制 
        max: 5, // 最大限制
        value: 60, // 当前value
        zu: [],
        addId: null,
        reduceId: null,
        centerPoint: 0,
        radius: 0,
        whiteRadius: 0,
        subCircleth: 0,
        sexth: 0,
        ctx: null,
        ctx2: null,
        canvas: null,
      },
      onLoad(option) {
        this.initData();
      },
      onShow() {},
      initData() {
        const width = app.globalData.width * 0.9;
        const height = app.globalData.width * 0.9;
        this.data.radius = width / 2 - 80;
        this.data.centerPoint = { //中心点
          x: width / 2,
          y: height / 2
        };
        this.data.whiteRadius = this.data.radius * 0.7;
        this.data.subCircleth = this.data.radius * 0.3;
        this.data.sexth = this.data.radius * 0.05;
    
        const query = wx.createSelectorQuery();
        query.select('#circle')
          .fields({
            node: true,
            size: true
          })
          .exec(res => {
            const canvas = res[0].node; // Canvas 对象
            this.data.ctx = canvas.getContext('2d');
    
            // 初始化画布大小
            const dpr = wx.getSystemInfoSync().pixelRatio;
            canvas.width = width * dpr; // 初始化画布大小--宽
            canvas.height = height * dpr; // 初始化画布大小--高
            this.data.ctx.scale(dpr, dpr);
            this.data.ctx.translate(this.data.centerPoint.x, this.data.centerPoint.y);
            this.canvasCircle();
          });
    
        const query2 = wx.createSelectorQuery();
        query2.select('#circle2')
          .fields({
            node: true,
            size: true
          })
          .exec(res => {
            this.data.canvas = res[0].node;
            this.data.ctx2 = this.data.canvas.getContext('2d');
    
            const dpr = wx.getSystemInfoSync().pixelRatio;
            this.data.canvas.width = width * dpr;
            this.data.canvas.height = height * dpr;
            this.data.ctx2.scale(dpr, dpr);
            this.data.ctx2.translate(this.data.centerPoint.x, this.data.centerPoint.y);
            this.proCanvasCircle();
          });
      },
    
      btnHandler(e) {
        const type = e.currentTarget.dataset.type;
        let value = this.data.value;
        if (type == 1) {
          value++;
          if (value > 150) return;
        } else {
          value--;
          if (value < 0) return;
        }
        this.data.value = value;
        this.proCanvasCircle();
      },
      // 拖动过程中触发的事件
      sliderchanging(e) {
        var value = e.detail.value;
        this.setData({
          value: value
        })
      },
      clickHandler(e) {
        const type = e.currentTarget.dataset.type;
        if (type == 1) {
          clearInterval(this.data.startId);
          clearInterval(this.data.reduceId);
          this.addNum();
        } else {
          clearInterval(this.data.addId);
          clearInterval(this.data.reduceId);
        }
      },
      addNum() {
        this.data.addId = setInterval(() => {
          let value = this.data.value;
          value++;
          if (value > 150) {
            clearInterval(this.data.addId);
            this.recuceNum();
          } else {
            this.data.value = value;
            this.proCanvasCircle();
          }
        }, 100);
      },
      recuceNum() {
        this.data.reduceId = setInterval(() => {
          let value = this.data.value;
          value--;
          if (value < 0) {
            clearInterval(this.data.reduceId);
            this.addNum();
          } else {
            this.data.value = value;
            this.proCanvasCircle();
          }
        }, 100);
      },
      test() {
        for (let index = 0; index < 20; index++) {
          this.data.zu.push(index);
        }
      },
      // 完成一次拖动后触发的事件
      sliderchange(e) {
        var value = e.detail.value;
        this.setData({
          value: value
        });
      },
      proCanvasCircle() {
        const value = this.data.value;
    
        // 绘制前清空之前的画布
        this.data.ctx2.clearRect(-this.data.centerPoint.x, -this.data.centerPoint.y,
          this.data.centerPoint.x * 2, this.data.centerPoint.y * 2);
    
    
        //当前值
        this.data.ctx2.font = '22px sans-serif';
        const valueStr = '' + value;
        const valueWidth = this.data.ctx2.measureText(valueStr).width;
        this.data.ctx2.beginPath();
        this.data.ctx2.fillStyle = 'black';
        this.data.ctx2.fillText(valueStr, -valueWidth, -this.data.radius * 0.02);
        this.data.ctx2.fill();
        this.data.ctx2.stroke();
    
        this.data.ctx2.rotate(180 * Math.PI / 180); //旋转180,起点从9点钟开始
        //进度色圆环
        this.data.ctx2.lineWidth = this.data.subCircleth;
        this.data.ctx2.lineCap = 'butt';
        this.data.ctx2.beginPath();
        this.data.ctx2.strokeStyle = '#fbc850';
        this.data.ctx2.arc(0, 0, this.data.whiteRadius + this.data.subCircleth / 2, 0 * Math.PI, value / 150 * 1.25 * Math.PI);
        this.data.ctx2.stroke();
    
        //进度圆点
        const pointRadius = this.data.radius * 0.86;
        const ponitPosition = {};
        const bili = 30 / 45; // 每一值代表多度
        const circleWidth = this.data.radius * 0.13;
        this.data.ctx2.beginPath();
        if (value >= 0 && value <= 90) { //从0mmHg~90mmHg之间的夹角  0°~135°
          ponitPosition.x = -Math.cos(value / bili * Math.PI / 180) * pointRadius;
          ponitPosition.y = -Math.sin(value / bili * Math.PI / 180) * pointRadius;
        } else if (value > 90 && value <= 120) { //从90mmHg~120mmHg之间的夹角 0°~45°
          ponitPosition.x = Math.cos((45 - (value - 90) / bili) * Math.PI / 180) * pointRadius;
          ponitPosition.y = -Math.sin((45 - (value - 90) / bili) * Math.PI / 180) * pointRadius;
        } else if (value >= 120 && value <= 150) { //从120mmHg~150mmHg之间的夹角 0°~45°
          ponitPosition.x = Math.cos((value - 120) / bili * Math.PI / 180) * pointRadius;
          ponitPosition.y = Math.sin((value - 120) / bili * Math.PI / 180) * pointRadius;
        }
        const image = this.data.canvas.createImage();
        image.onload = () => {
          this.data.ctx2.drawImage(
            image,
            ponitPosition.x - circleWidth / 2, ponitPosition.y - circleWidth / 2,
            circleWidth, circleWidth
          )
        }
        image.src = '../../image/circle.png'
    
        //最外侧有色圆环
        this.data.ctx2.beginPath();
        this.data.ctx2.lineWidth = this.data.sexth;
        this.data.ctx2.lineCap = 'round';
        this.data.ctx2.strokeStyle = '#fbc850';
        this.data.ctx2.fill();
        this.data.ctx2.arc(0, 0, this.data.whiteRadius + this.data.subCircleth + this.data.sexth, 0 * Math.PI, value / 150 * 1.25 * Math.PI);
        this.data.ctx2.stroke();
    
        this.data.ctx2.rotate(-180 * Math.PI / 180); //旋转180,起点从9点钟开始
    
      },
      canvasCircle() {
        //中间白色圆
        this.data.ctx.beginPath();
        this.data.ctx.strokeStyle = 'white';
        this.data.ctx.arc(0, 0, this.data.whiteRadius, 0, 2 * Math.PI);
        this.data.ctx.fillStyle = 'white'
        this.data.ctx.fill();
        this.data.ctx.stroke();
    
        //半透明圆环
        this.data.ctx.lineWidth = this.data.subCircleth;
        this.data.ctx.beginPath();
        this.data.ctx.strokeStyle = 'white';
        this.data.ctx.globalAlpha = 0.5; //设置为半透明
        this.data.ctx.arc(0, 0, this.data.whiteRadius + this.data.subCircleth / 2, 0, 2 * Math.PI);
        this.data.ctx.stroke();
        this.data.ctx.globalAlpha = 1; //设置为不透明
    
        this.data.ctx.rotate(90 * Math.PI / 180); //旋转-90,起点从9点钟开始
        const singeAngle = 15;
        const lineLength = 10;
        const lineCount = 225 / 15 + 1;
        for (let index = 0; index < lineCount; index++) {
          const ponit = {
            x: 0,
            y: this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength * 2
          };
          const arrowPoint = {
            x: 0,
            y: this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength
          }
          if (index == 1 || index == 2 || index == 4 || index == 5 || index == 7 || index == 8 ||
            index == 10 || index == 11 || index == 13 || index == 14) {
            ponit.y = this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength;
            arrowPoint.y = this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength;
          }
          this.data.ctx.strokeStyle = 'white';
          this.data.ctx.lineWidth = 2;
          this.data.ctx.beginPath();
          this.data.ctx.moveTo(ponit.x, ponit.y);
          this.data.ctx.lineTo(arrowPoint.x, arrowPoint.y);
          this.data.ctx.stroke();
    
          this.data.ctx.rotate(singeAngle * Math.PI / 180);
        }
    
        this.data.ctx.rotate(-(singeAngle * lineCount + 90) * Math.PI / 180); //旋转-singeAngle * lineCount,起点从9点钟开始
    
        //画0 mmHg
        const unitStr = 'mmHg';
        const onetStr = '0';
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '14px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(onetStr, -(this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength * 4), 0);
        this.data.ctx.stroke();
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '10px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(unitStr, -(this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength * 4) * 1.18, this.data.sexth * 2.5);
        this.data.ctx.stroke();
    
        //画30 mmHg
        const twotStr = '30';
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '14px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(twotStr, -(this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength * 4) * 0.8, -Math.sin(45) * this.data.radius * 1.1);
        this.data.ctx.stroke();
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '10px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(unitStr, -(this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength * 4) * 0.91, -Math.sin(45) * this.data.radius * 0.95);
        this.data.ctx.stroke();
    
        //画60 mmHg
        const threetStr = '60';
        const threeStrWidth = this.data.ctx.measureText(threetStr).width;
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '14px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(threetStr, -threeStrWidth, -(this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength) * 1.2);
        this.data.ctx.stroke();
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '10px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(unitStr, threeStrWidth / 2, -(this.data.whiteRadius + this.data.subCircleth + this.data.sexth + lineLength) * 1.2);
        this.data.ctx.stroke();
    
        //画90 mmHg
        const fourStr = '90';
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '14px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(fourStr, this.data.radius, -this.data.radius * 0.9);
        this.data.ctx.stroke();
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '10px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(unitStr, this.data.radius, -this.data.radius * 0.8);
        this.data.ctx.stroke();
    
        //画120 mmHg
        const fiveStr = '120';
        const fiveStrWidth = this.data.ctx.measureText(fiveStr).width;
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '14px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(fiveStr, this.data.radius * 1.35, 0);
        this.data.ctx.stroke();
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '10px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(unitStr, this.data.radius * 1.35, fiveStrWidth * 0.65);
        this.data.ctx.stroke();
    
        //画150 mmHg
        const sixStr = '150';
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '14px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(sixStr, this.data.radius * 0.95, this.data.radius * 1.1);
        this.data.ctx.stroke();
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'white';
        this.data.ctx.font = '10px sans-serif';
        this.data.ctx.lineWidth = 0.5;
        this.data.ctx.fill();
        this.data.ctx.fillText(unitStr, this.data.radius * 0.95, this.data.radius * 1.23);
        this.data.ctx.stroke();
    
        //中间mmHg
        this.data.ctx.font = '10px sans-serif';
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'black';
        this.data.ctx.fillText(unitStr, 0, 0);
        this.data.ctx.fill();
        this.data.ctx.stroke();
    
        //实时压力
        this.data.ctx.font = '15px sans-serif';
        const tipStr = '实时压力';
        const tipWidth = this.data.ctx.measureText(tipStr).width;
        this.data.ctx.beginPath();
        this.data.ctx.fillStyle = 'black';
        this.data.ctx.fillText(tipStr, -tipWidth / 2, this.data.radius * 0.2);
        this.data.ctx.fill();
        this.data.ctx.stroke();
    
        //圆心
        // this.data.ctx.lineWidth = 5;
        // this.data.ctx.beginPath();
        // this.data.ctx.strokeStyle = 'green';
        // this.data.ctx.arc(0, 0, 2, 0, 2 * Math.PI);
        // this.data.ctx.stroke();
    
      }
    })
    

    相关文章

      网友评论

          本文标题:小程序canvas自定义圆弧进度条(不是显示在最上层)---进化

          本文链接:https://www.haomeiwen.com/subject/rfljjdtx.html