微信小程序canvas画布实现文字自由缩放、移动、旋转

微信小程序canvas画布实现文字自由缩放、移动、旋转

本篇文章给大家带来的内容是关于小程序中canvas的拖拽功能详解,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

效果图

canvas拖拽移动详情介绍

创建canvas元素,获取画布信息

 <canvas class="canvas_img" type="2d" id="myCanvas" bindtouchstart="handleCanvasStart" bindtouchmove="handleCanvasMove" bindtouchend="handleCanvasEnd" />

设置变量

 data: {
    canvas: null,
    ctx: null,
    dpr: 0,   //像素比
    fontSize: 18,
    isDragging: null, // 1 移动 2 旋转 3 缩放
    dataIndex: 0,
    rectPadding: 15, //边距
    dataList: [
      {
        type: 'text',
        text: '可拖拽文字',
        fontSize: 18,
        fontWeight: 'normal',
        fontStyle: 'normal',
        startX: 1,
        startY: 1,
        x: 60,  //x轴偏移量
        y: 60,  //Y轴偏移量
        angle: 0, //旋转角度
      }
    ],
  },

获取画布

 initData() {
    //  wx.showLoading()
    const that = this
    const query = wx.createSelectorQuery().in(this)
    query.select('#myCanvas')
      .fields({ node: true, size: true })
      .exec(function (res) {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')
        const dpr = wx.getWindowInfo().pixelRatio
        canvas.width = res[0].width * dpr
        canvas.height = res[0].height * dpr
        ctx.scale(dpr, dpr)
        that.setData({
          canvas: canvas,
          ctx: ctx,
          dpr: dpr,
        })
        that.drawText()
        ctx.restore(); // 恢复canvas状态
      })
  },

绘制画布文本

 drawText() {
    let that = this
    const canvas = this.data.canvas
    const ctx = this.data.ctx
    let rectPadding = that.data.rectPadding;
    ctx.save();

    let bgImg = canvas.createImage();
    bgImg.src = "../../img/3.png"
    bgImg.onload = () => {
      ctx.save()

      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(bgImg, 0, 0, canvas.width, canvas.height);
      that.data.dataList.forEach((text) => {
        ctx.font = text.fontSize + "px Arial";
        let textWidth = ctx.measureText(text.text).width;
        let rectHeight = text.fontSize * 1.2;  //文本高度

        // 绘制文本框
        ctx.lineWidth = 1;
        ctx.strokeStyle = '#333';
        // 重新映射位置
        ctx.translate(textWidth / 2 + text.x, rectHeight / 2 + text.y);
        // 旋转角度
        ctx.rotate(text.angle);
        ctx.beginPath();
        ctx.rect(-textWidth / 2 - rectPadding, -rectHeight - rectPadding * 2, textWidth + rectPadding * 2, rectHeight + rectPadding * 2);

        ctx.stroke();
        // 填充文本框
        ctx.fillStyle = '#ffffff';
        // ctx.fill();
        ctx.restore();
        // 绘制文本
        ctx.fillStyle = '#000000';
        ctx.font = text.fontStyle + ' ' + text.fontWeight + ' ' + text.fontSize + "px Arial";
        // 重新映射位置
        ctx.translate(textWidth / 2 + text.x, rectHeight / 2 + text.y);
        // 旋转角度
        ctx.rotate(text.angle);
        // 文本填充
        ctx.fillText(text.text, -ctx.measureText(text.text).width / 2, -rectPadding);
        ctx.setTransform(that.data.dpr, 0, 0, that.data.dpr, 0, 0);
        ctx.save()
        // 重新映射位置
        ctx.translate(textWidth / 2 + text.x, rectHeight / 2 + text.y);
        // 旋转角度
        ctx.rotate(text.angle);
        // 文本填充
        ctx.fillText('旋转', -ctx.measureText('旋转').width / 2 , rectPadding+10);
        ctx.setTransform(that.data.dpr, 0, 0, that.data.dpr, 0, 0);
        ctx.save()
      })
    }
    ctx.restore(); // 恢复canvas状态
  },

监听手势开始事件

  handleCanvasStart(e) {
    let that = this
    const ctx = that.data.ctx
    var mouseX = e.touches[0].clientX - 0; //鼠标x轴坐标
    var mouseY = e.touches[0].clientY - 0; //鼠标y轴坐标
    let rectPadding = that.data.rectPadding;
    that.data.dataList.forEach((item, i) => {
      const textX = item.x;  // 文本x轴坐标
      const textY = item.y;  // 文本y轴坐标
      const width = ctx.measureText(item.text).width;
      let rectHeight = item.fontSize * 1.2;  //that.data.rectHeight;
      const rotateWidth = ctx.measureText('旋转').width;
      that.setData({
        dataIndex: i
      })
      // 文字区域
      if (mouseX > textX && mouseX < textX + width && mouseY > textY - 30 && mouseY < textY) {
        dragging = item;
        that.setData({
          isDragging: 1
        })
      }
      // 旋转区域
      if (mouseX > textX + width / 2 - rectPadding && mouseX < textX + width / 2 - rectPadding + rotateWidth && mouseY > textY + rectHeight && mouseY < textY + rectHeight + rectPadding) {
        dragging = item;
        that.setData({
          isDragging: 2
        })
      }
      // 缩放区域
      if (mouseX > textX + width - rectPadding && mouseX < textX +
        width + rectPadding + 20 && mouseY > textY + rectHeight - 20 && mouseY < textY + rectHeight + rectPadding * 2) {
        dragging = item;
        dragging.startX = mouseX
        dragging.startY = mouseY
        that.setData({
          isDragging: 3
        })
      }
    })
  },

监听手势移动

 // 手势拖动
  handleCanvasMove(e) {
    const { x, y } = this.getCoordinates(e);
    if (this.data.isDragging == 1) {
      dragging.x = x - 50;
      dragging.y = y;
      this.drawText()
    }
    if (this.data.isDragging == 2) {
      const { angle } = this.updateAngle(x, y);
      dragging.angle = angle
      this.drawText()
    }
    if (this.data.isDragging == 3) {
      const { fontSize } = this.updateScale(dragging.startX, dragging.startY, x, y)
      dragging.fontSize = fontSize
      console.log(dragging)
      this.drawText()
    }
  },

手势结束

handleCanvasEnd(e) {
    this.setData({
      isDragging: null
    })
  },

拖动坐标、放大缩小比例、旋转角度计算

  //  获取鼠标坐标
  getCoordinates(e) {
    const canvas = this.data.canvas
    return {
      x: e.touches[0].clientX - 0,
      y: e.touches[0].clientY - 0
    };
  },
  // 旋转角度
  updateAngle(x, y) {
    let that = this
    let angle = 0
    const canvas = this.data.canvas
    const dx = x - canvas.width / (2 * that.data.dpr);
    const dy = y - canvas.height / (2 * that.data.dpr);
    angle = Math.atan2(dy, dx);
    return { angle }
  },
  // 缩放
  updateScale(startX, startY, x, y) {
    var widthDelta = x - startX;
    const fontSize = this.data.fontSize + widthDelta / 10;
    return { fontSize }
  },

图片: 在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值