Canvas 小结

Canvas 小结

1. 第三方手势库 AlloyFinger.js 在 Vue 中的使用

参考简书文章 如何在移动端实现手势缩放(缩放图片,div等)

1.1 安装三个库
npm i -D alloyfinger
npm i -D css3transform

还有一个 To.js 可以点击链接下载后放到 assets 目录下,然后打开文件,在最后一行加入 module.exports = To;即可使用。

1.2 在 Vue 中引入它们
1.2.1 在 main.js 中引入 AlloyFinger
import AlloyFinger from 'alloyfinger'
import AlloyFingerPlugin from 'alloyfinger/vue/alloy_finger_vue'

Vue.use(AlloyFingerPlugin, {
    
    
  AlloyFinger
})
1.2.2 在自定义的组件中引入 css3transform 和 To
<script>
import To from "@/assets/to.js";	//我将下载好的 to.js 放置到了 assets 目录下
import Transform from "css3transform/dist/css3transform.js";
</script>
1.3 在组件中使用 AlloyFinger
//下列手势事件可以按需选用
<div id="canvasBox"
     v-finger:tap="tap"
     v-finger:multipoint-start="multipointStart"
     v-finger:long-tap="longTap"
     v-finger:swipe="swipe"
     v-finger:pinch="pinch"
     v-finger:rotate="rotate"
     v-finger:press-move="pressMove"
     v-finger:multipoint-end="multipointEnd"
     v-finger:double-tap="doubleTap"
     v-finger:single-tap="singleTap"

     v-finger:touch-start="touchStart"
     v-finger:touch-move="touchMove"
     v-finger:touch-end="touchEnd"
     v-finger:touch-cancel="touchCancel"
     >
    //the element that you want to bind event
    <canvas
          ref="mapCanvas"
          :width="canvasWidth"
          :height="canvasHeight"
    ></canvas>
</div>

<script>
import To from "@/assets/to.js";
import Transform from "css3transform/dist/css3transform.js";

export default {
    
    
	data() {
    
    
        return {
    
    
            canvas: null,
            context: null,
            canvasWidth: 100,
            canvasHeight: 100,
        };
  },
  methods: {
    
    
    ease(x) {
    
    
      return Math.sqrt(1 - Math.pow(x - 1, 2));
    },
    multipointStart: function () {
    
    
      To.stopAll();
      this.imgScale = this.canvas.scaleX;
    },
    pinch: function (evt) {
    
    
      this.canvas.scaleX = this.canvas.scaleY = this.imgScale * evt.zoom;
    },
    rotate: function (evt) {
    
    
      this.canvas.rotateZ += evt.angle;
    },
    pressMove: function (evt) {
    
    
      this.canvas.translateX += evt.deltaX;
      this.canvas.translateY += evt.deltaY;
      evt.preventDefault();
    },
    multipointEnd: function () {
    
    
      // 使用To.js来管理js开启的动画
      To.stopAll();

      // 最小缩放到0.8倍
      if (this.canvas.scaleX < 0.8) {
    
    
        new To(this.canvas, "scaleX", 0.8, 500, this.ease);
        new To(this.canvas, "scaleY", 0.8, 500, this.ease);
      }
      // 最大2倍
      if (this.canvas.scaleX > 2) {
    
    
        new To(this.canvas, "scaleX", 2, 500, this.ease);
        new To(this.canvas, "scaleY", 2, 500, this.ease);
      }

      // 取旋转角度
      var rotation = this.canvas.rotateZ % 360;

      if (rotation < 0) rotation = 360 + rotation;
      this.canvas.rotateZ = rotation;

      // 角度回弹
      if (rotation > 0 && rotation < 45) {
    
    
        new To(this.canvas, "rotateZ", 0, 500, this.ease);
      } else if (rotation >= 315) {
    
    
        new To(this.canvas, "rotateZ", 360, 500, this.ease);
      } else if (rotation >= 45 && rotation < 135) {
    
    
        new To(this.canvas, "rotateZ", 90, 500, this.ease);
      } else if (rotation >= 135 && rotation < 225) {
    
    
        new To(this.canvas, "rotateZ", 180, 500, this.ease);
      } else if (rotation >= 225 && rotation < 315) {
    
    
        new To(this.canvas, "rotateZ", 270, 500, this.ease);
      }
    },
     
    tap: function() {
    
     console.log('onTap'); },
    longTap: function() {
    
     console.log('onLongTap'); },
    swipe: function(evt) {
    
    
        console.log("swipe" + evt.direction);
        console.log('onSwipe');
    },
    doubleTap: function() {
    
     console.log('onDoubleTap'); },
    singleTap: function () {
    
     console.log('onSingleTap'); },

    touchStart: function() {
    
     console.log('onTouchStart'); },
    touchMove: function() {
    
     console.log('onTouchMove'); },
    touchEnd: function() {
    
     console.log('onTouchEnd'); },
    touchCancel: function() {
    
     console.log('onTouchCancel'); } 
  },
}
</script>

2. 移动端实现在屏幕上选点并在 canvas 画布上画出的方法

可以在屏幕中心固定一个点,然后通过移动画布的操作实现在 canvas 画布上的特定位置画点。

点可以通过 <div>标签绝对定位 来实现

<div class="center-point" ref="point"></div>

<style lang="css" scoped>
.center-point {
    
    
  width: 4px;
  height: 4px;
  border-radius: 2px;
  background-color: red;
  flex: none;
  z-index: 100;
  position: absolute;
  left: calc(50% - 2px);
  top: calc(50% - 2px);
}
</style>

<script>
export default {
    
    
    methods: {
    
    
        addPoint() {
    
    
            //这个方法返回一个矩形对象,包含四个属性:left、top、right 和 bottom。分别表示元素各边与页面上边和左边的距离
            let pointBox = this.point.getBoundingClientRect();
            let newPoint = this.windowToCanvas(pointBox.left + 2, pointBox.top + 2);	// 2 是中心点的半径,加上后才是中心点的圆点坐标
            this.context.fillStyle = "black";
            this.context.beginPath();
            this.context.arc(newPoint.x, newPoint.y, 1.5, 0, 2 * Math.PI);
            this.context.fill();
        },
        //获取屏幕上的点在 canvas 中的相对坐标
        windowToCanvas(x, y) {
    
    
            let box = this.canvas.getBoundingClientRect();
            return {
    
    
                x : x - box.left;
                y : y - box.top; 
            }
        },   
    }
}
</script>

3. 关于 canvas 放缩时 canvas 视口上的点相对于原始图片坐标的计算

Alloy Finger.js 是针对 canvas 的视口进行缩放的。 canvas 视口缩放时,即 <canvas> 标签元素的大小发生改变,而 canvas 的画布(可绘画区域)大小不变。

假设初始情况下未通过 css 给 canvas 设置高度和宽度(也不建议这么做,建议使用 <canvas> 标签的 widthheight 属性设置宽高),那么 canvas 的视口大小和画布大小一致。

当 canvas 的视口不等于 canvas 的画布大小时,浏览器会将画布上画好的内容映射到视口上,填满视口。

在这里插入图片描述

canvas 的视口缩放不影响 canvas 的画布坐标,只是将画布内容的映射在屏幕上显示了出来,造成了视觉上的放缩效果。

canvas 放缩时的画点操作以及点坐标的计算】在进行缩放操作后,在放缩后的 canvas 视口上手动选择点,然后根据屏幕计算出该点相对于 canvas 视口的坐标,然后根据放缩比,计算出该点相对于 canvas 画布的坐标,再调用 canvas 的 api 在画布上画出来,然后更新快照,从而在放缩后的 canvas 视口上显示出来。

【总结】:先获取 canvas 放缩完成后的放缩比,然后再计算相对坐标后除以放缩比即可。

【踩坑】:监听 canvas 放缩的 pinch 事件和监听多指开始操作的 multipointStart 事件代码如下所示,this.canvasScale 即为 canvas 放缩完成后的放缩比,它的值与 evt.zoom 有关 。但是 evt.zoom 是本次放缩操作与上次放缩操作的放缩比,因此在进行多次放缩操作(比如:先放大再缩小)后,evt.zoom 只以最后一次操作为准,而坐标计算则是在所有放缩操作完成后进行计算,所以直接使用 this.canvasScale 会在进行多次放缩操作后造成误差。

pinch: function (evt) {
    
    
    this.canvas.scaleX = this.canvas.scaleY = this.canvasScale * evt.zoom;
},
multipointStart: function () {
    
    
    To.stopAll();
    this.canvasScale = this.canvas.scaleX;
}

【解决】:通过放缩后 canvas 容器的宽度与 canvas 初始宽度的比值获取最终的放缩比。

//这个方法返回一个矩形对象,包含四个属性:left、top、right 和 bottom。分别表示元素各边与页面上边和左边的距离
let box = this.canvas.getBoundingClientRect();
let finalScale = box.width / this.canvas.width;

canvas 无论经历多少次放缩操作,其最终的容器的宽度是一定的,该值与 canvas 原始宽度的比值恰好是最终的放缩比。

因此计算相对原始 canvas 画布坐标的函数可以这样写,分析见下图

windowToCanvas(x, y) {
    
    
      let box = this.canvas.getBoundingClientRect();
      let finalScale = box.width / this.canvas.width;
      return {
    
    
          x : (x - box.left) / finalScale;
          y : (y - box.top) / finalScale;
      }
}    

【注】:下图中 canvasWidth 为 canvas 的原始宽度。

在这里插入图片描述

对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点,因此计算相对于原始图片坐标的函数应为

// canvas 处于初始状态下下列各值的计算情况
let imageScale = this.canvas.height / this.img.height;
//imgX 和 imgY 是图片在 canvas 上放置的位置(图像相对于 canvas 的左边距和上边距)
this.imgX = this.canvas.width / 2 - (this.img.width * this.imgScale) / 2;
this.imgY = this.canvas.height / 2 - (this.img.height * this.imgScale) / 2;

// canvas 经过放缩、旋转后屏幕中心点的计算情况
let pointBox = this.centerPoint.getBoundingClientRect();
// 2 为屏幕中心点的半径
let newPoint = this.windowToCanvas(pointBox.left + 2, pointBox.top + 2);

//对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点
//相对于原始图片的x:
let originImageX = (newPoint.x - this.imgX) / this.imgScale 
//相对于原始图片的Y:
let originImageY = (this.img.height * this.imgScale - (newPoint.y - this.imgY)) / this.imgScale

计算示意图如下所示

在这里插入图片描述

4. 关于 canvas 旋转时 canvas 视口上的点相对于原始图片坐标的计算

【总结】:无论 canvas 如何旋转,其内部坐标系的原点都是初始位置时位于左上角的点。对于 canvas 中的图片而言,其坐标系的原点是初始位置时位于左下角的点。

在这里插入图片描述

4.1 旋转角为 0° 和 360° 时的情况

旋转角为 0° 和 360° 时,相当于没有发生旋转,canvas 视口上的点相对于原始图片坐标的计算和上述 canvas 放缩时 canvas 视口上的点相对于原始图片坐标的计算 方式一致。

4.2 旋转角为 90° 时的情况

【注】:canvasWidth 为 canvas 的原始宽度,缩放比和相对坐标的计算有所不同。

在这里插入图片描述

对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点,因此计算相对于原始图片坐标的函数应为

// canvas 处于初始状态下下列各值的计算情况
let imageScale = this.canvas.height / this.img.height;
this.imgX = this.canvas.width / 2 - (this.img.width * this.imgScale) / 2;
this.imgY = this.canvas.height / 2 - (this.img.height * this.imgScale) / 2;

// canvas 经过放缩、旋转后中心点的计算情况
let pointBox = this.centerPoint.getBoundingClientRect();
let newPoint = this.windowToCanvas(pointBox.left + 2, pointBox.top + 2);

//对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点
//相对于原始图片的x:
let originImageX = (newPoint.x - this.imgX) / this.imgScale 
//相对于原始图片的Y:
let originImageY = (this.img.height * this.imgScale - (newPoint.y - this.imgY)) / this.imgScale
4.3 旋转角为 180° 时的情况

【注】:canvasWidth 为 canvas 的原始宽度。

缩放比 scale = box.width / canvasWidth
相对画布坐标 (box.width-(x-box.left), box.height-(y-.box.top))
相对原始图片坐标 
((box.width-(x-box.left))/scale, (box.height-(y-.box.top))/scale)

对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点,因此计算相对于原始图片坐标的函数应为

// canvas 处于初始状态下下列各值的计算情况
let imageScale = this.canvas.height / this.img.height;
this.imgX = this.canvas.width / 2 - (this.img.width * this.imgScale) / 2;
this.imgY = this.canvas.height / 2 - (this.img.height * this.imgScale) / 2;

// canvas 经过放缩、旋转后中心点的计算情况
let pointBox = this.centerPoint.getBoundingClientRect();
let newPoint = this.windowToCanvas(pointBox.left + 2, pointBox.top + 2);

//对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点
//相对于原始图片的x:
let originImageX = (newPoint.x - this.imgX) / this.imgScale 
//相对于原始图片的Y:
let originImageY = (this.img.height * this.imgScale - (newPoint.y - this.imgY)) / this.imgScale
4.4 旋转角为 270° 时的情况

【注】:canvasWidth 为 canvas 的原始宽度。

缩放比            scale = box.height / canvasWidth
相对画布坐标      (box.height-(y-.box.top), x-box.left)
相对原始图片坐标 ((box.height-(y-.box.top))/scale, (x-box.left)/scale)

对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点,因此计算相对于原始图片坐标的函数应为

// canvas 处于初始状态下下列各值的计算情况
let imageScale = this.canvas.height / this.img.height;
this.imgX = this.canvas.width / 2 - (this.img.width * this.imgScale) / 2;
this.imgY = this.canvas.height / 2 - (this.img.height * this.imgScale) / 2;

// canvas 经过放缩、旋转后中心点的计算情况
let pointBox = this.centerPoint.getBoundingClientRect();
let newPoint = this.windowToCanvas(pointBox.left + 2, pointBox.top + 2);

//对于 canvas 中的图片而言,其坐标系的原点一直都是初始位置时位于左下角的点
//相对于原始图片的x:
let originImageX = (newPoint.x - this.imgX) / this.imgScale 
//相对于原始图片的Y:
let originImageY = (this.img.height * this.imgScale - (newPoint.y - this.imgY)) / this.imgScale
4.5 核心代码
windowToCanvas(x, y) {
    
    
      //这个方法返回一个矩形对象,包含四个属性:left、top、right 和 bottom。分别表示元素各边与页面上边和左边的距离
      let box = this.canvas.getBoundingClientRect();

      let trueScale;
      if (this.canvasRotate === 90 || this.canvasRotate === 270) {
    
    
        trueScale = box.height / this.canvasWidth;
      } else {
    
    
        trueScale = box.width / this.canvasWidth;
      }
      //以 canvas 未旋转时左上角为基准的(x,y)坐标
      let left_top_x = x - box.left;
      let left_top_y = y - box.top;
      let result;
      switch (this.canvasRotate) {
    
    
        case 0:
          result = {
    
     x: left_top_x, y: left_top_y };
          break;
        case 90:
          result = {
    
     x: left_top_y, y: box.width - left_top_x };
          break;
        case 180:
          result = {
    
     x: box.width - left_top_x, y: box.height - left_top_y };
          break;
        case 270:
          result = {
    
     x: box.height - left_top_y, y: left_top_x };
          break;
      }
      result.x /= trueScale;
      result.y /= trueScale;
      return result;
    }

5. 撤销 canvas 中已画图形 (点、直线等) 的实现

使用 canvas 的 context 中的 getImageData()putImageData() 方法可以分别获取或保存每次操作后 canvas 的快照,因此可以在 data() 函数中定义一个名称为 canvasDatas 的列表来模拟一个,里面存放的是每次绘画后 canvas 的快照。在进行撤销操作时,可以先将 canvasDatas 中位于栈顶的元素弹出,然后获取新的栈顶元素,将其 put 到画布上。

//向栈中添加当前绘制完成的 canvas 快照
this.canvasDatas.push(this.context.getImageData(0, 0,this.canvasWidth,this.canvasHeight));

//撤销操作,canvas 上展示的是上一次的操作快照
this.canvasDatas.pop();
let nowImageData = this.canvasDatas[this.canvasDatas.length - 1];
this.context.putImageData(nowImageData, 0, 0);

6. 完整代码

<!--
 * @Author: Shimmer
 * @Description: 侧边菜单和画布组件
-->
<template>
  <el-container>
    <transition name="slide">
      <el-aside v-if="!isFold" width="210px">
        <slot name="aside"></slot>
      </el-aside>
    </transition>

    <el-main>
      <el-button
        style="z-index: 100"
        :icon="iconFold"
        class="btn-fold"
        @click="isFold = !isFold"
      ></el-button>

      <div class="btns">
        <el-button type="primary" @click="addPoint" icon="el-icon-plus"
          >添加点</el-button
        >
        <el-button type="primary" @click="removePoint" icon="el-icon-minus"
          >删除点</el-button
        >
        <el-button-group>
          <el-button @click="exit" style="width: 50%; padding: 12px 0"
            >退出</el-button
          >
          <el-button
            type="primary"
            @click="savePath"
            icon="el-icon-save"
            style="width: 50%; padding: 12px 0"
            >保存</el-button
          >
        </el-button-group>
      </div>
      <div
        id="canvasBox"
        style="flex: 1; z-index: 0"
        v-finger:multipoint-start="multipointStart"
        v-finger:pinch="pinch"
        v-finger:rotate="rotate"
        v-finger:press-move="pressMove"
        v-finger:multipoint-end="multipointEnd"
      >
        <div class="center-point" ref="point"></div>
        <canvas
          ref="mapCanvas"
          :width="canvasWidth"
          :height="canvasHeight"
          tabindex="0"
          style="display: inline-block"
        ></canvas>
      </div>
    </el-main>
  </el-container>
</template>

<script>
import To from "@/assets/to.js";
import Transform from "css3transform/dist/css3transform.js";

export default {
    
    
  name: "SideMenuAndCanvas",
  data() {
    
    
    return {
    
    
      isFold: false,
      centerPoint: null,
      canvas: null,
      context: null,
      img: null,
      imgX: 0,
      imgY: 0,
      imgScale: 1,
      canvasWidth: 100,
      canvasHeight: 100,
      unSavedPoints: [],
      canvasDatas: [],
      paths: {
    
    },
    };
  },
  computed: {
    
    
    iconFold() {
    
    
      return this.isFold ? "el-icon-s-unfold" : "el-icon-s-fold";
    },
  },
  methods: {
    
    
    exit() {
    
    
      this.unSavedPoints.length = 0;
      this.canvasDatas.length = 1;
      let nowImageData = this.canvasDatas[this.canvasDatas.length - 1];
        this.context.putImageData(nowImageData, 0, 0);
    },
    savePath() {
    
    },
    addPoint() {
    
    
      let pointBox = this.point.getBoundingClientRect();
      let newPoint = this.windowToCanvas(pointBox.left + 2, pointBox.top + 2);
      this.unSavedPoints.push(newPoint);
      this.context.fillStyle = "black";
      this.context.beginPath();
      this.context.arc(newPoint.x, newPoint.y, 1.5, 0, 2 * Math.PI);
      this.context.fill();
      let len = this.unSavedPoints.length;
      if (len >= 2) {
    
    
        this.drawLine(this.unSavedPoints[len - 2], this.unSavedPoints[len - 1]);
      }
      this.canvasDatas.push(
        this.context.getImageData(0, 0, this.canvasWidth, this.canvasHeight)
      );
    },
    removePoint() {
    
    
      if (this.unSavedPoints.length > 0) {
    
    
        this.unSavedPoints.pop();
        this.canvasDatas.pop();
        let nowImageData = this.canvasDatas[this.canvasDatas.length - 1];
        this.context.putImageData(nowImageData, 0, 0);
      } else {
    
    
        this.$message.warning("您还没有添加任何点,请先添加点!");
      }
    },
    drawLine(startPoint, endPoint) {
    
    
      this.context.moveTo(startPoint.x, startPoint.y);
      this.context.lineTo(endPoint.x, endPoint.y);
      this.context.stroke();
    },
    windowToCanvas(x, y) {
    
    
      //这个方法返回一个矩形对象,包含四个属性:left、top、right 和 bottom。分别表示元素各边与页面上边和左边的距离
      let box = this.canvas.getBoundingClientRect();
      let relativeX = x - box.left;
      let relativeY = y - box.top;
      if (this.canvas.rotateZ >= 0 && this.canvas.rotateZ < 45) {
    
    
        let trueScale = box.width / this.canvas.width;
        return {
    
    
          x: relativeX / trueScale,
          y: relativeY / trueScale,
        };
      } else if (this.canvas.rotateZ >= 315) {
    
    
        let trueScale = box.width / this.canvas.width;
        return {
    
    
          x: relativeX / trueScale,
          y: relativeY / trueScale,
        };
      } else if (this.canvas.rotateZ >= 45 && this.canvas.rotateZ < 135) {
    
    
        let trueScale = box.height / this.canvas.width;
        return {
    
    
          x: relativeY / trueScale,
          y: (box.width - relativeX) / trueScale,
        };
      } else if (this.canvas.rotateZ >= 135 && this.canvas.rotateZ < 225) {
    
    
        let trueScale = box.width / this.canvas.width;
        return {
    
    
          x: (box.width - relativeX) / trueScale,
          y: (box.height - relativeY) / trueScale,
        };
      } else if (this.canvas.rotateZ >= 225 && this.canvas.rotateZ < 315) {
    
    
        let trueScale = box.height / this.canvas.width;
        return {
    
    
          x: (box.height - relativeY) / trueScale,
          y: relativeX / trueScale,
        };
      }
    },
    init() {
    
    
      let box = document.getElementById("canvasBox");
      let that = this;
      this.canvasWidth = box.clientWidth;
      this.canvasHeight = box.clientHeight;

      window.addEventListener("resize", () => {
    
    
        that.canvasWidth = box.clientWidth;
        that.canvasHeight = box.clientHeight;
        setTimeout(() => {
    
    
          that.context.putImageData(
            that.canvasDatas[this.canvasDatas.length - 1],
            0,
            0
          );
        }, 1000);
      });

      this.point = this.$refs.point;
      this.canvas = this.$refs.mapCanvas; //画布对象
      this.context = this.canvas.getContext("2d"); //画布显示二维图片
      this.loadImg();
    },
    imgIsLoad() {
    
    
      this.drawImage();
      this.canvasDatas.push(
        this.context.getImageData(0, 0, this.canvasWidth, this.canvasHeight)
      );
    },
    loadImg() {
    
    
      this.img = new Image();
      this.img.src = require("../assets/zex1.png");
      this.img.onload = this.imgIsLoad;
    },
    drawImage() {
    
    
      this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
      this.imgScale = this.canvas.height / this.img.height;
      this.imgX = this.canvas.width / 2 - (this.img.width * this.imgScale) / 2;
      this.imgY =
        this.canvas.height / 2 - (this.img.height * this.imgScale) / 2;
      this.context.drawImage(
        this.img, //规定要使用的图像、画布或视频
        this.imgX, //在画布上放置图像的 x y 坐标位置
        this.imgY,
        this.img.width * this.imgScale, //要使用的图像的宽度、高度
        this.img.height * this.imgScale
      );
    },
    ease(x) {
    
    
      return Math.sqrt(1 - Math.pow(x - 1, 2));
    },
    multipointStart: function () {
    
    
      To.stopAll();
      this.imgScale = this.canvas.scaleX;
    },
    pinch: function (evt) {
    
    
      this.canvas.scaleX = this.canvas.scaleY = this.imgScale * evt.zoom;
    },
    rotate: function (evt) {
    
    
      this.canvas.rotateZ += evt.angle;
    },
    pressMove: function (evt) {
    
    
      this.canvas.translateX += evt.deltaX;
      this.canvas.translateY += evt.deltaY;
      evt.preventDefault();
    },
    multipointEnd: function () {
    
    
      // 使用To.js来管理js开启的动画
      To.stopAll();

      // 最小缩放到0.8倍
      if (this.canvas.scaleX < 0.8) {
    
    
        new To(this.canvas, "scaleX", 0.8, 500, this.ease);
        new To(this.canvas, "scaleY", 0.8, 500, this.ease);
      }
      // 最大2倍
      if (this.canvas.scaleX > 2) {
    
    
        new To(this.canvas, "scaleX", 2, 500, this.ease);
        new To(this.canvas, "scaleY", 2, 500, this.ease);
      }

      // 取旋转角度
      var rotation = this.canvas.rotateZ % 360;

      if (rotation < 0) rotation = 360 + rotation;
      this.canvas.rotateZ = rotation;

      // 角度回弹
      if (rotation > 0 && rotation < 45) {
    
    
        new To(this.canvas, "rotateZ", 0, 500, this.ease);
      } else if (rotation >= 315) {
    
    
        new To(this.canvas, "rotateZ", 360, 500, this.ease);
      } else if (rotation >= 45 && rotation < 135) {
    
    
        new To(this.canvas, "rotateZ", 90, 500, this.ease);
      } else if (rotation >= 135 && rotation < 225) {
    
    
        new To(this.canvas, "rotateZ", 180, 500, this.ease);
      } else if (rotation >= 225 && rotation < 315) {
    
    
        new To(this.canvas, "rotateZ", 270, 500, this.ease);
      }
    },
  },
  mounted() {
    
    
    this.init();
    Transform(this.canvas);
  },
};
</script>

<style lang="css" scoped>
#canvasBox {
    
    
  display: flex;
  height: 100%;
}

.el-container {
    
    
  height: 100%;
}
.el-aside {
    
    
  background-color: #545c64;
  color: #333;
  text-align: center;
}
.el-main {
    
    
  background-color: #e9eef3;
  color: #333;
  padding: 0;
  display: flex;
  position: relative;
}
.slide-enter-active,
.slide-leave-active {
    
    
  transition: all 0.3s ease;
}
.slide-enter,
.slide-leave-to {
    
    
  width: 0 !important;
}
.btn-fold {
    
    
  width: 60px;
  height: 50px;
  float: left;
}
.center-point {
    
    
  width: 4px;
  height: 4px;
  border-radius: 2px;
  background-color: red;
  flex: none;
  z-index: 100;
  position: absolute;
  left: calc(50% - 2px);
  top: calc(50% - 2px);
}
.btns {
    
    
  position: absolute;
  left: 5%;
  bottom: 5%;
  display: flex;
  flex-direction: column;
  z-index: 100;
  width: 100px;
}
.el-button {
    
    
  margin-top: 5px !important;
  margin-left: 0 !important;
}
</style>

猜你喜欢

转载自blog.csdn.net/Alan_Walker688/article/details/127792652