Resumen del lienzo

Resumen del lienzo

1. Uso de la biblioteca de gestos de terceros AlloyFinger.js en Vue

Consulte el artículo de Jianshu sobre cómo implementar la escala de gestos en el terminal móvil (ampliación de imágenes, divs, etc.)

1.1 Instalar tres bibliotecas
npm i -D alloyfinger
npm i -D css3transform

También existe To.js en el que puede hacer clic en el enlace para descargarlo y colocarlo en el directorio de activos, luego abrir el archivo y agregarlo a la última línea module.exports = To;para usarlo.

1.2 Preséntelos en Vue
1.2.1 Introducir AlloyFinger en main.js
import AlloyFinger from 'alloyfinger'
import AlloyFingerPlugin from 'alloyfinger/vue/alloy_finger_vue'

Vue.use(AlloyFingerPlugin, {
    
    
  AlloyFinger
})
1.2.2 Introducir css3transform y To en componentes personalizados
<script>
import To from "@/assets/to.js";	//我将下载好的 to.js 放置到了 assets 目录下
import Transform from "css3transform/dist/css3transform.js";
</script>
1.3 Uso de AlloyFinger en componentes
//下列手势事件可以按需选用
<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. El terminal móvil implementa el método de seleccionar puntos en la pantalla y dibujar en el lienzo.

Puede fijar un punto en el centro de la pantalla y luego dibujar un punto en una posición específica en el lienzo moviendo el lienzo.

Los puntos se pueden obtener mediante <div>标签y绝对定位

<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. Respecto al cálculo de las coordenadas de los puntos en la ventana gráfica del lienzo en relación con la imagen original cuando se hace zoom en el lienzo.

Alloy Finger.jsEstá escalado para la ventana gráfica del lienzo. Cuando se hace zoom en la ventana gráfica del lienzo, es decir, <canvas>el tamaño del elemento de etiqueta cambia, pero el tamaño del lienzo (área dibujable) permanece sin cambios.

Suponiendo que la altura y el ancho del lienzo no se configuran inicialmente a través de CSS (no se recomienda hacer esto, se recomienda usar los atributos y <canvas>de la etiqueta para establecer el ancho y la altura), entonces el tamaño de la ventana gráfica del lienzo Es consistente con el tamaño del lienzo.widthheight

Cuando la ventana gráfica del lienzo no es igual al tamaño del lienzo, el navegador asignará el contenido dibujado en el lienzo a la ventana gráfica para llenar la ventana gráfica.

Insertar descripción de la imagen aquí

La escala de la ventana gráfica del lienzo no afecta las coordenadas del lienzo, solo muestra el mapeo del contenido del lienzo en la pantalla, lo que genera un efecto de escala visual.

[ Operación de dibujo de puntos y cálculo de coordenadas de puntos cuando se hace zoom en el lienzo ] Después de la operación de zoom, seleccione manualmente un punto en la ventana gráfica del lienzo ampliada y luego calcule las coordenadas del punto en relación con la ventana gráfica del lienzo según la pantalla, y luego calcule el coordenadas del punto en relación con la ventana gráfica del lienzo de acuerdo con la relación de zoom, calcule las coordenadas del punto en relación con el lienzo, luego llame a la API del lienzo para dibujarlo en el lienzo y luego actualice la instantánea para mostrarla en el ventana gráfica de lienzo ampliada.

[Resumen]: Primero obtenga la relación de escala después de completar la escala del lienzo, luego calcule las coordenadas relativas y divida por la relación de escala.

[Pase al pozo]: el código para monitorear el evento de pellizco del escalado del lienzo y el evento multipointStart para monitorear el inicio de la operación con varios dedos es el siguiente, que es la relación de escala después de que se completa el escalado del lienzo y su valor this.canvasScaleestá evt.zoomrelacionado a. Sin embargo, evt.zoomes la relación de escala entre esta operación de escala y la última operación de escala. Por lo tanto, después de realizar múltiples operaciones de escala (por ejemplo: primero acercar y luego alejar), solo prevalecerá la última operación y el cálculo de coordenadas se basa evt.zoomen El cálculo se realiza después de completar todas las operaciones de escala, por lo que el uso directo this.canvasScaleprovocará errores después de múltiples operaciones de escala.

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

[Solución]: Obtenga la relación de escala final a través de la relación entre el ancho del contenedor del lienzo después del escalado y el ancho inicial del lienzo.

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

No importa cuántas veces el lienzo se someta a operaciones de escala, el ancho final del contenedor es seguro y la relación entre este valor y el ancho original del lienzo es exactamente la relación de escala final.

Por lo tanto, la función para calcular las coordenadas del lienzo en relación con el lienzo original se puede escribir así: el análisis se muestra en la siguiente figura.

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

[Nota]: canvasWidth en la figura siguiente es el ancho original del lienzo.

Insertar descripción de la imagen aquí

Para cuadros en lienzo, el origen de su sistema de coordenadas es siempre el punto en la esquina inferior izquierda de la posición inicial, por lo que la función para calcular las coordenadas relativas al cuadro original debe ser

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

El diagrama de cálculo es el siguiente.

Insertar descripción de la imagen aquí

4. Con respecto al cálculo de las coordenadas de los puntos en la ventana gráfica del lienzo en relación con la imagen original cuando se gira el lienzo

[Resumen]: No importa cómo se gire el lienzo, el origen de su sistema de coordenadas interno es el punto en la esquina superior izquierda de la posición inicial. Para cuadros en lienzo, el origen de su sistema de coordenadas es el punto en la esquina inferior izquierda de la posición inicial.

Insertar descripción de la imagen aquí

4.1 Situación cuando el ángulo de rotación es 0° y 360°

Cuando el ángulo de rotación es 0° y 360°, equivale a no girar. El cálculo de las coordenadas de los puntos en la ventana gráfica del lienzo en relación con la imagen original es el mismo que el cálculo de las coordenadas de los puntos en el lienzo. ventana gráfica relativa a la imagen original cuando se hace zoom en el lienzo.

4.2 Situación cuando el ángulo de rotación es de 90°

[Nota]: canvasWidth es el ancho original del lienzo, y la relación de escala y el cálculo de las coordenadas relativas son diferentes.

Insertar descripción de la imagen aquí

Para cuadros en lienzo, el origen de su sistema de coordenadas es siempre el punto en la esquina inferior izquierda de la posición inicial, por lo que la función para calcular las coordenadas relativas al cuadro original debe ser

// 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 Situación cuando el ángulo de rotación es de 180°

[Nota]: canvasWidth es el ancho original del lienzo.

缩放比 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)

Para cuadros en lienzo, el origen de su sistema de coordenadas es siempre el punto en la esquina inferior izquierda de la posición inicial, por lo que la función para calcular las coordenadas relativas al cuadro original debe ser

// 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 Situación cuando el ángulo de rotación es de 270°

[Nota]: canvasWidth es el ancho original del lienzo.

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

Para cuadros en lienzo, el origen de su sistema de coordenadas es siempre el punto en la esquina inferior izquierda de la posición inicial, por lo que la función para calcular las coordenadas relativas al cuadro original debe ser

// 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 Código central
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. Deshacer la implementación de gráficos dibujados (puntos, líneas rectas, etc.) en el lienzo.

getImageData()Puede usar los métodos y en el contexto del lienzo putImageData()para obtener o guardar una instantánea del lienzo después de cada operación. Por lo tanto, puede definir una lista llamada canvasDatas en la función data() para simular una pila , que almacena el lienzo después de cada pintura. ... instantánea. Al realizar una operación de deshacer, primero puede colocar el elemento en la parte superior de la pila en canvasDatas, luego obtener el nuevo elemento superior de la pila y colocarlo en el lienzo.

//向栈中添加当前绘制完成的 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. Código completo

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

Supongo que te gusta

Origin blog.csdn.net/Alan_Walker688/article/details/127792652
Recomendado
Clasificación