Canvas Summary

Canvas Summary

1. Use of third-party gesture library AlloyFinger.js in Vue

Refer to the Jianshu article on how to implement gesture scaling on the mobile terminal (zooming pictures, divs, etc.)

1.1 Install three libraries
npm i -D alloyfinger
npm i -D css3transform

There is also To.js that you can click on the link to download and put it in the assets directory, then open the file and add it to the last line module.exports = To;to use it.

1.2 Introduce them in Vue
1.2.1 Introduce AlloyFinger into main.js
import AlloyFinger from 'alloyfinger'
import AlloyFingerPlugin from 'alloyfinger/vue/alloy_finger_vue'

Vue.use(AlloyFingerPlugin, {
    
    
  AlloyFinger
})
1.2.2 Introduce css3transform and To into custom components
<script>
import To from "@/assets/to.js";	//我将下载好的 to.js 放置到了 assets 目录下
import Transform from "css3transform/dist/css3transform.js";
</script>
1.3 Using AlloyFinger in components
//下列手势事件可以按需选用
<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. The mobile terminal implements the method of selecting points on the screen and drawing on the canvas.

You can fix a point in the center of the screen, and then draw a point at a specific location on the canvas by moving the canvas.

Points can be realized by <div>标签and绝对定位

<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. Regarding the calculation of the coordinates of the points on the canvas viewport relative to the original image when the canvas is zoomed.

Alloy Finger.jsIt is scaled for the canvas viewport. When the canvas viewport is zoomed, that is, <canvas>the size of the label element changes, but the size of the canvas (drawable area) remains unchanged.

Assuming that the height and width of the canvas are not set through CSS initially (it is not recommended to do this, it is recommended to use the and attributes <canvas>of the label to set the width and height), then the viewport size of the canvas is consistent with the canvas size.widthheight

When the canvas's viewport is not equal to the canvas's canvas size, the browser will map the drawn content on the canvas to the viewport to fill the viewport.

Insert image description here

The viewport scaling of canvas does not affect the canvas coordinates, but only displays the mapping of the canvas content on the screen, resulting in a visual scaling effect.

[ Point drawing operation and point coordinate calculation when canvas is zoomed ] After the zoom operation, manually select a point on the zoomed canvas viewport, and then calculate the coordinates of the point relative to the canvas viewport based on the screen, and then calculate the coordinates of the point relative to the canvas viewport according to the screen. Zoom ratio, calculate the coordinates of the point relative to the canvas, then call the canvas api to draw it on the canvas, and then update the snapshot to display it on the zoomed canvas viewport.

[Summary]: First obtain the scaling ratio after the canvas scaling is completed, then calculate the relative coordinates and divide by the scaling ratio.

[Step on the pit]: The code for monitoring the pinch event of canvas scaling and the multipointStart event of monitoring the start of multi-finger operation is as follows, which is the this.canvasScalescaling ratio after canvas scaling is completed, and its value is evt.zoomrelated to. However, evt.zoomis the scaling ratio between this scaling operation and the last scaling operation. Therefore, after performing multiple scaling operations (for example: first zoom in and then zoom out), only the last operation shall evt.zoomprevail, and the coordinate calculation is based on Calculation is performed after all scaling operations are completed, so using directly this.canvasScalewill cause errors after multiple scaling operations.

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

[Solution]: Obtain the final scaling ratio through the ratio of the width of the canvas container after scaling and the initial width of the canvas.

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

No matter how many times the canvas undergoes scaling operations, its final container width is certain, and the ratio of this value to the original width of the canvas is exactly the final scaling ratio.

Therefore, the function to calculate the canvas coordinates relative to the original canvas can be written like this. The analysis is shown in the figure below.

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;
      }
}    

[Note]: canvasWidth in the figure below is the original width of canvas.

Insert image description here

For pictures in canvas, the origin of its coordinate system is always the point in the lower left corner of the initial position, so the function to calculate the coordinates relative to the original picture should be

// 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

The calculation diagram is as follows

Insert image description here

4. Regarding the calculation of the coordinates of the points on the canvas viewport relative to the original image when the canvas is rotated

[Summary]: No matter how the canvas is rotated, the origin of its internal coordinate system is the point in the upper left corner of the initial position. For pictures in canvas, the origin of its coordinate system is the point in the lower left corner of the initial position.

Insert image description here

4.1 Situation when the rotation angle is 0° and 360°

When the rotation angle is 0° and 360°, it is equivalent to no rotation. The calculation of the coordinates of the points on the canvas viewport relative to the original image is the same as the calculation of the coordinates of the points on the canvas viewport relative to the original image when the canvas is zoomed.

4.2 Situation when the rotation angle is 90°

[Note]: canvasWidth is the original width of canvas, and the scaling ratio and calculation of relative coordinates are different.

Insert image description here

For pictures in canvas, the origin of its coordinate system is always the point in the lower left corner of the initial position, so the function to calculate the coordinates relative to the original picture should be

// 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 Situation when the rotation angle is 180°

[Note]: canvasWidth is the original width of 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)

For pictures in canvas, the origin of its coordinate system is always the point in the lower left corner of the initial position, so the function to calculate the coordinates relative to the original picture should be

// 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 Situation when the rotation angle is 270°

[Note]: canvasWidth is the original width of canvas.

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

For pictures in canvas, the origin of its coordinate system is always the point in the lower left corner of the initial position, so the function to calculate the coordinates relative to the original picture should be

// 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 Core code
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. Undo the implementation of drawn graphics (points, straight lines, etc.) in canvas

getImageData()You can use the and methods in the canvas context putImageData()to obtain or save a snapshot of the canvas after each operation. Therefore, you can define a list named canvasDatas in the data() function to simulate a stack , which stores the canvas after each painting. snapshot. When performing an undo operation, you can first pop the element at the top of the stack in canvasDatas, then obtain the new top element of the stack and put it on the canvas.

//向栈中添加当前绘制完成的 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. Complete code

<!--
 * @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>

Guess you like

Origin blog.csdn.net/Alan_Walker688/article/details/127792652