canvas实现图片矩形截图,矩形旋转后的截图,旋转后的截图摆正显示

一、效果图

在这里插入图片描述

二、主要代码

获取矩形框中地方的截图数据
1、先获取矩形四点在画布上的实际坐标值;
2、计算矩形此时实际的宽和高,便于设置后期临时矩形的宽和高;
3、可能矩形旋转了一定的角度,我们新建一个临时的画布tempCanvas,然后向反方向摆正,使矩形能正常的显示在临时画布中;
4、因为摆正了矩形,此时需要计算矩形的left和top,方便画图;
5、在创建一个用于画截图的canvas,canvas的宽高就是前面我们画出来的宽高‘
6、然后利用
rotatedCtx.drawImage(
tempCanvas,
left,
top,
width,
height,
0,
0,
width,
height
);
在临时画布中截取矩形框中的部分
7、ctx.drawImage的参数代表的意思请详见:

https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Using_images

    getCanvasImageData(id) {
      const viewportTransform = this.fabricCanvas.viewportTransform;
      const zoom = this.fabricCanvas.getZoom();
      let selectedCoords = null;
      let rotationAngle = 0;
      let left = 0;
      let top = 0;
       //根据画布矩阵和缩放信息,获取到矩形实际在画布上的坐标点
      this.fabricCanvas.getObjects().forEach(rect => {
        if (rect.id == id) {
          console.log("rect", rect);
          const coords = [];
          const points = rect.get("aCoords");
          // 将内部坐标转换为实际画布坐标
          coords.push(this.getACoords(points["tl"], viewportTransform, zoom));
          coords.push(this.getACoords(points["tr"], viewportTransform, zoom));
          coords.push(this.getACoords(points["br"], viewportTransform, zoom));
          coords.push(this.getACoords(points["bl"], viewportTransform, zoom));
          selectedCoords = coords;
          rotationAngle = rect.angle;
          // left = rect.left;
          // top = rect.top;
        }
      });

      if (selectedCoords) {
        //2、根据rotationAngle和selectedCoords,计算rect此时的宽高,此时矩形有可能被旋转,有可能被拉伸,所以需要重新计算矩形的宽高
        const width = Math.sqrt(
          Math.pow(selectedCoords[1][0] - selectedCoords[0][0], 2) +
            Math.pow(selectedCoords[1][1] - selectedCoords[0][1], 2)
        );
        const height = Math.sqrt(
          Math.pow(selectedCoords[3][0] - selectedCoords[0][0], 2) +
            Math.pow(selectedCoords[3][1] - selectedCoords[0][1], 2)
        );

        // 计算矩形中心点
        const centerX = (selectedCoords[0][0] + selectedCoords[2][0]) / 2;
        const centerY = (selectedCoords[0][1] + selectedCoords[2][1]) / 2;

        // 新建一个 canvas 元素
        const tempCanvas = document.createElement("canvas");
        const tempCtx = tempCanvas.getContext("2d");
        tempCanvas.height = this.canvasProp.height;
        tempCanvas.width = this.canvasProp.width;
        // 将原点移动到矩形中心点
        tempCtx.translate(centerX, centerY);
        // 按中心点旋转画布
        tempCtx.rotate(-(rotationAngle * (Math.PI / 180)));
        // 将原点移回
        tempCtx.translate(-centerX, -centerY);
        // 将 fabricCanvas 的内容绘制到临时 canvas 上,并进行裁剪
        tempCtx.save();
        tempCtx.beginPath();
        tempCtx.moveTo(selectedCoords[0][0], selectedCoords[0][1]);
        tempCtx.lineTo(selectedCoords[1][0], selectedCoords[1][1]);
        tempCtx.lineTo(selectedCoords[2][0], selectedCoords[2][1]);
        tempCtx.lineTo(selectedCoords[3][0], selectedCoords[3][1]);
        tempCtx.closePath();
        tempCtx.clip();

        // 获取 fabricCanvas 的数据并绘制到临时 canvas 上
        tempCtx.drawImage(this.bgImg, 0, 0);
        // 恢复上下文状态
        tempCtx.restore();

        // return tempCtx.getImageData(
        //   0,
        //   0,
        //   tempCanvas.width,
        //   tempCanvas.height
        // );

        // 重新计算旋转后的矩形的 left 和 top
        const rotatedCoords = selectedCoords.map(coord => {
          const x = coord[0] - centerX;
          const y = coord[1] - centerY;
          const rotatedX =
            x * Math.cos((rotationAngle * Math.PI) / 180) +
            y * Math.sin((rotationAngle * Math.PI) / 180);
          const rotatedY =
            -x * Math.sin((rotationAngle * Math.PI) / 180) +
            y * Math.cos((rotationAngle * Math.PI) / 180);
          return [rotatedX + centerX, rotatedY + centerY];
        });

        const left = Math.min(
          rotatedCoords[0][0],
          rotatedCoords[1][0],
          rotatedCoords[2][0],
          rotatedCoords[3][0]
        );
        const top = Math.min(
          rotatedCoords[0][1],
          rotatedCoords[1][1],
          rotatedCoords[2][1],
          rotatedCoords[3][1]
        );

        const rotatedCanvas = document.createElement("canvas");
        rotatedCanvas.width = width;
        rotatedCanvas.height = height;
        const rotatedCtx = rotatedCanvas.getContext("2d");

        // 将临时canvas的图像绘制到旋转后的canvas上
        rotatedCtx.drawImage(
          tempCanvas,
          left,
          top,
          width,
          height,
          0,
          0,
          width,
          height
        );

        // 返回旋转后的图像数据
        return rotatedCtx.getImageData(
          0,
          0,
          rotatedCanvas.width,
          rotatedCanvas.height
        );
      } else {
        return null;
      }
    },

三、组件代码

<template>
  <div v-if="canvasProp.width != 0">
    <div
      class="canvas-wrap"
      :style="{
        width: canvasProp.width + 'px',
        height: canvasProp.height + 'px'
      }"
    >
      <canvas
        :width="canvasProp.width"
        :height="canvasProp.height"
        ref="canvas"
        :style="{
          width: canvasProp.width + 'px',
          height: canvasProp.height + 'px'
        }"
        id="canvasId"
      ></canvas>
    </div>
    <div
      class="muane"
      :style="{
        width: canvasProp.width - 2 + 'px'
      }"
    >
      <span @click="zoomBig">
        <i class="el-icon-zoom-in" style="color: #000;font-size: 16px;"></i>
      </span>
      <span @click="zoomSmall">
        <i class="el-icon-zoom-out" style="color: #000;font-size: 16px;"></i>
      </span>
      <span @click="panChange">
        <i
          v-if="!isPan"
          class="icon iconfont-saber icon-saber-shouzhang mIcon"
          style="color: #000;font-size: 15px !important;"
        ></i>
        <i
          v-else
          class="icon iconfont-saber icon-saber-24gl-pointer mIcon"
          style="color: #000;font-size: 16px !important;"
        ></i>
      </span>
    </div>

    <!-- 隐藏的 canvas -->
    <canvas
      ref="hiddenCanvas"
      :width="canvasProp.width"
      :height="canvasProp.height"
      style="display: none;"
    ></canvas>
  </div>
</template>
<script>
let backgroundImage = null;
export default {
  name: "images-tags",
  props: {
    // 矩形标注的数据
    tagsData: {
      type: Array,
      default: () => {
        return [
          {
            label: "基表数据",
            color: "#0000ff",
            type: "rectangle",
            width: 150,
            height: 50,
            rotate: 0,
            isInit: true,
            startX: 185,
            startY: 235
          },
          {
            label: "数据点2",
            color: "#0000ff",
            type: "rectangle",
            width: 150,
            height: 50,
            rotate: 0,
            isInit: false,
            startX: 100,
            startY: 100
          }
        ];
      }
    },
    // 图片路径
    images: {
      type: String,
      default: ""
    }
  },
  data() {
    return {
      bgImg: null,
      ctx: null,
      fabricCanvas: null,
      isPan: false,
      isDragging: false,
      canvasSizeScale: 1,
      lastPosX: 0,
      lastPosY: 0,
      canvasProp: {
        width: 0, // canvas的宽度
        height: 0, // canvas的高度
        translateX: 0,
        translateY: 0
      }
    };
  },
  mounted() {
    this.loadImageAndSetCanvas();
    //window.addEventListener("keydown", this.handleKeyDown);
  },
  beforeDestroy() {
    //window.removeEventListener("keydown", this.handleKeyDown);
    this.fabricCanvas.off("object:modified", this.modifyRect);
  },
  methods: {
    // 添加新的方法
    getCanvasImageData(id) {
      console.log("getCanvasImageData");
      const viewportTransform = this.fabricCanvas.viewportTransform;
      const zoom = this.fabricCanvas.getZoom();
      let selectedCoords = null;
      let rotationAngle = 0;
      

      this.fabricCanvas.getObjects().forEach(rect => {
        if (rect.id == id) {
          console.log("rect", rect);
          const coords = [];
          const points = rect.get("aCoords");
          // 将内部坐标转换为实际画布坐标
          coords.push(this.getACoords(points["tl"], viewportTransform, zoom));
          coords.push(this.getACoords(points["tr"], viewportTransform, zoom));
          coords.push(this.getACoords(points["br"], viewportTransform, zoom));
          coords.push(this.getACoords(points["bl"], viewportTransform, zoom));
          selectedCoords = coords;
          rotationAngle = rect.angle;
        }
      });

      if (selectedCoords) {
        //2、根据rotationAngle和selectedCoords,计算rect此时的宽高
        const width = Math.sqrt(
          Math.pow(selectedCoords[1][0] - selectedCoords[0][0], 2) +
            Math.pow(selectedCoords[1][1] - selectedCoords[0][1], 2)
        );
        const height = Math.sqrt(
          Math.pow(selectedCoords[3][0] - selectedCoords[0][0], 2) +
            Math.pow(selectedCoords[3][1] - selectedCoords[0][1], 2)
        );

        // 计算矩形中心点
        const centerX = (selectedCoords[0][0] + selectedCoords[2][0]) / 2;
        const centerY = (selectedCoords[0][1] + selectedCoords[2][1]) / 2;

        // 新建一个 canvas 元素
        const tempCanvas = document.createElement("canvas");
        const tempCtx = tempCanvas.getContext("2d");
        tempCanvas.height = this.canvasProp.height;
        tempCanvas.width = this.canvasProp.width;
        // 将原点移动到矩形中心点
        tempCtx.translate(centerX, centerY);
        // 按中心点旋转画布
        tempCtx.rotate(-(rotationAngle * (Math.PI / 180)));
        // 将原点移回
        tempCtx.translate(-centerX, -centerY);
        // 将 fabricCanvas 的内容绘制到临时 canvas 上,并进行裁剪
        tempCtx.save();
        tempCtx.beginPath();
        tempCtx.moveTo(selectedCoords[0][0], selectedCoords[0][1]);
        tempCtx.lineTo(selectedCoords[1][0], selectedCoords[1][1]);
        tempCtx.lineTo(selectedCoords[2][0], selectedCoords[2][1]);
        tempCtx.lineTo(selectedCoords[3][0], selectedCoords[3][1]);
        tempCtx.closePath();
        tempCtx.clip();

        // 获取 fabricCanvas 的数据并绘制到临时 canvas 上
        tempCtx.drawImage(this.bgImg, 0, 0);
        // 恢复上下文状态
        tempCtx.restore();

        // return tempCtx.getImageData(
        //   0,
        //   0,
        //   tempCanvas.width,
        //   tempCanvas.height
        // );

        // 重新计算旋转后的矩形的 left 和 top
        const rotatedCoords = selectedCoords.map(coord => {
          const x = coord[0] - centerX;
          const y = coord[1] - centerY;
          const rotatedX =
            x * Math.cos((rotationAngle * Math.PI) / 180) +
            y * Math.sin((rotationAngle * Math.PI) / 180);
          const rotatedY =
            -x * Math.sin((rotationAngle * Math.PI) / 180) +
            y * Math.cos((rotationAngle * Math.PI) / 180);
          return [rotatedX + centerX, rotatedY + centerY];
        });

        const left = Math.min(
          rotatedCoords[0][0],
          rotatedCoords[1][0],
          rotatedCoords[2][0],
          rotatedCoords[3][0]
        );
        const top = Math.min(
          rotatedCoords[0][1],
          rotatedCoords[1][1],
          rotatedCoords[2][1],
          rotatedCoords[3][1]
        );

          // 检查并调整宽度和高度,确保不超出画布边界,否则ios无法正常显示
        let adjustedWidth = width;
        let adjustedHeight = height;

        //超过右边界
        if (left + width > tempCanvas.width) {
          adjustedWidth = tempCanvas.width - left;
        }
        //超过左边界
        if (left<0) {
          adjustedWidth = width+left;
          if(adjustedWidth>tempCanvas.width){
            adjustedWidth = tempCanvas.width;
          }
        }
        //如果横框宽度
       
        //超过下边界
        if (top + height > tempCanvas.height) {
          adjustedHeight = tempCanvas.height - top;
        }
        //超过上边界
        if(top<0){
          adjustedHeight = height+top;
          if(adjustedHeight>tempCanvas.height){
            adjustedHeight = tempCanvas.height;
          }
        }



        const rotatedCanvas = document.createElement("canvas");
        rotatedCanvas.width = adjustedWidth;
        rotatedCanvas.height = adjustedHeight;
        const rotatedCtx = rotatedCanvas.getContext("2d");
        

        // 将临时canvas的图像绘制到旋转后的canvas上
        rotatedCtx.drawImage(
          tempCanvas,
          left<0 ? 0 : left,
          top<0? 0 : top,
          adjustedWidth,
          adjustedHeight,
          0,
          0,
          adjustedWidth,
          adjustedHeight
        );
    

        // 返回旋转后的图像数据
        return rotatedCtx.getImageData(
          0,
          0,
          rotatedCanvas.width,
          rotatedCanvas.height
        );
      } else {
        return null;
      }
    },

    convertToGrayScale(imageData) {
      const data = imageData.data;
      for (let i = 0; i < data.length; i += 4) {
        const avg = 0.3 * data[i] + 0.59 * data[i + 1] + 0.11 * data[i + 2];
        data[i] = avg;
        data[i + 1] = avg;
        data[i + 2] = avg;
      }
      return imageData;
    },
    modifyRect(rect) {
      console.log(rect, this);
      let selectedDataPoint = this.$parent.selectedDataPoint;
      let id = rect.target.id;
      for (let i = 0; i < selectedDataPoint.length; i++) {
        let item = selectedDataPoint[i];
        if (item.id == id) {
          this.applyGrayScale(id, item.ledThreshold);
          break;
        }
      }
    },
    //绘制灰色图片
    applyGrayScale(id, threshold) {
      // 获取选中区域的图像数据
      const imageData = this.getCanvasImageData(id);
      //对图像数据进行灰度处理
      const grayImageData = this.convertToGrayScale(imageData);
      this.$emit("getGrayCtxSize", {
        id: id,
        width: grayImageData.width,
        height: grayImageData.height
      });
      // 找到灰度canvas并放入灰度图片数据

      const grayCtx = this.$parent.$refs["grayCanvas-" + id][0].getContext(
        "2d"
      );

      this.$nextTick(() => {
        grayCtx.putImageData(grayImageData, 0, 0);
        this.applyThreshold(
          id,
          threshold,
          grayImageData.width,
          grayImageData.height
        );
      });
    },
    applyThreshold(id, threshold, width, height) {
      console.log("width", width);
      if (!width) return;

      if (!threshold) {
        threshold = 128;
      }
      const grayCtx = this.$parent.$refs["grayCanvas-" + id][0].getContext(
        "2d"
      );
      const grayImageData = grayCtx.getImageData(0, 0, width, height);
      const data = grayImageData.data;
      for (let i = 0; i < data.length; i += 4) {
        const avg = data[i];
        const value = avg > threshold ? 255 : 0;
        data[i] = value;
        data[i + 1] = value;
        data[i + 2] = value;
      }
      const binaryCtx = this.$parent.$refs["binaryCanvas-" + id][0].getContext(
        "2d"
      );
      grayCtx.width = binaryCtx.width;
      grayCtx.height = binaryCtx.height;

      binaryCtx.putImageData(grayImageData, 0, 0);
    },
    //切换操作切换
    panChange() {
      this.isPan = !this.isPan;
      if (this.isPan) {
        this.enablePan();
      } else {
        this.disablePan();
      }
    },
    enablePan() {
      this.fabricCanvas.discardActiveObject(); //取消当前的选中状态
      //禁止页面的选择
      this.fabricCanvas.forEachObject(function(obj) {
        obj.selectable = false; // 禁用对象选择
        obj.evented = false; // 禁用对象事件
      });
      // 设置 canvas 的鼠标样式为 'move'
      this.fabricCanvas.defaultCursor = "grab";
      this.fabricCanvas.hoverCursor = "grab";
      // 添加事件监听
      this.fabricCanvas.on("mouse:down", this.onMouseDown);
      this.fabricCanvas.on("mouse:move", this.onMouseMove);
      this.fabricCanvas.on("mouse:up", this.onMouseUp);
      this.fabricCanvas.on("mouse:out", this.onMouseUp);

      this.fabricCanvas.renderAll(); // 重绘画布以显示更改
    },
    disablePan() {
      //禁止页面的选择
      this.fabricCanvas.forEachObject(function(obj) {
        obj.selectable = true; // 禁用对象选择
        obj.evented = true; // 禁用对象事件
      });
      // 恢复 canvas 的默认鼠标样式
      this.fabricCanvas.defaultCursor = "default";
      this.fabricCanvas.hoverCursor = "default";

      // 移除事件监听
      this.fabricCanvas.off("mouse:down", this.onMouseDown);
      this.fabricCanvas.off("mouse:move", this.onMouseMove);
      this.fabricCanvas.off("mouse:up", this.onMouseUp);
      this.fabricCanvas.off("mouse:out", this.onMouseUp);

      this.fabricCanvas.renderAll(); // 重绘画布以显示更改
    },
    onMouseDown(event) {
      this.isDragging = true;
      this.lastPosX = event.e.clientX;
      this.lastPosY = event.e.clientY;
      this.fabricCanvas.defaultCursor = "grabbing";
    },
    // onMouseMove(event) {
    //   if (this.isDragging) {
    //     const e = event.e;
    //     const vpt = this.fabricCanvas.viewportTransform;
    //     vpt[4] += e.clientX - this.lastPosX;
    //     vpt[5] += e.clientY - this.lastPosY;
    //     this.fabricCanvas.requestRenderAll();
    //     this.lastPosX = e.clientX;
    //     this.lastPosY = e.clientY;
    //   }
    // },
    onMouseMove(event) {
      if (this.isDragging) {
        const e = event.e;
        const vpt = this.fabricCanvas.viewportTransform.slice(); // 创建副本,避免直接修改
        const zoom = this.fabricCanvas.getZoom();

        // 计算平移的距离
        const moveX = e.clientX - this.lastPosX;
        const moveY = e.clientY - this.lastPosY;

        // 获取画布和容器的宽高
        const canvasWidth = this.fabricCanvas.getWidth();
        const canvasHeight = this.fabricCanvas.getHeight();
        const containerWidth = this.canvasProp.width;
        const containerHeight = this.canvasProp.height;

        // 计算缩放后的宽高
        const scaledWidth = canvasWidth * zoom;
        const scaledHeight = canvasHeight * zoom;

        // 计算边界
        const leftBoundary = Math.min(0, containerWidth - scaledWidth);
        const topBoundary = Math.min(0, containerHeight - scaledHeight);

        // 应用平移限制
        vpt[4] = Math.max(leftBoundary, Math.min(0, vpt[4] + moveX));
        vpt[5] = Math.max(topBoundary, Math.min(0, vpt[5] + moveY));

        // 更新画布视口变换
        this.fabricCanvas.setViewportTransform(vpt);
        this.lastPosX = e.clientX;
        this.lastPosY = e.clientY;
      }
    },
    onMouseUp() {
      this.isDragging = false;
      this.fabricCanvas.defaultCursor = "grab";
    },
    zoomBig() {
      const currentZoom = this.fabricCanvas.getZoom();
      if (currentZoom < 3) {
        this.scaleCanvas(currentZoom + 0.1);
      }
    },
    zoomSmall() {
      const currentZoom = this.fabricCanvas.getZoom();
      if (currentZoom > 1) {
        this.scaleCanvas(currentZoom - 0.1);
      }
    },
    scaleCanvas(scale) {
      const center = this.getCanvasCenter();
      this.fabricCanvas.zoomToPoint({ x: center.x, y: center.y }, scale);
    },
    //获取画布的中心点
    getCanvasCenter() {
      const canvasCenter = {
        x: this.fabricCanvas.width / 2,
        y: this.fabricCanvas.height / 2
      };
      return canvasCenter;
    },

    handleKeyDown(event) {
      console.log("event.key", event.key);
      const step = 5; // 每次移动的步长
      switch (event.key) {
        case "ArrowUp":
          this.canvasProp.translateY -= step;
          break;
        case "ArrowDown":
          this.canvasProp.translateY += step;
          break;
        case "ArrowLeft":
          this.canvasProp.translateX -= step;
          break;
        case "ArrowRight":
          this.canvasProp.translateX += step;
          break;
      }
      this.panCanvas(this.canvasProp.translateX, this.canvasProp.translateY);
    },
    loadFromJSON(json) {
      //  this.fabricCanvas.clear();
      //背景图替换为当前的背景图
      let newjson = JSON.parse(json);

      console.log("加载的json", newjson);
      newjson.backgroundImage = backgroundImage;
      //this.fabricCanvas.loadFromJSON(newjson);
      // 反序列化对象
      this.fabricCanvas.loadFromJSON(newjson);
    },
    getCanvasJson() {
      console.log("在线获取json", this.fabricCanvas.toJSON(["id"]));
      return JSON.stringify(this.fabricCanvas.toJSON(["id"]));
    },

    hexToRgba(hex, alpha) {
      const bigint = parseInt(hex.replace("#", ""), 16);
      const r = (bigint >> 16) & 255;
      const g = (bigint >> 8) & 255;
      const b = bigint & 255;
      return `rgba(${r},${g},${b},${alpha})`;
    },
    // ...其他方法
    panCanvas(translateX, translateY) {
      // 获取当前的 viewportTransform
      const viewportTransform = this.fabricCanvas.viewportTransform.slice(); // 创建一个副本,以免直接修改原始数组

      // 更新平移值
      viewportTransform[4] = translateX;
      viewportTransform[5] = translateY;

      // 设置新的 viewportTransform
      this.fabricCanvas.setViewportTransform(viewportTransform);
    },
    loadImageAndSetCanvas() {
      if (!this.images) return;
      const img = new Image();
      img.src = this.images;
      img.onload = () => {
        console.log("图片加载完毕", img);
        this.canvasProp.width = img.width * this.canvasSizeScale;
        this.canvasProp.height = img.height * this.canvasSizeScale;
        this.bgImg = img;

        this.$nextTick(() => {
          this.fabricCanvas = new fabric.Canvas("canvasId");

          // 设置canvas大小
          this.fabricCanvas.setWidth(this.canvasProp.width);
          this.fabricCanvas.setHeight(this.canvasProp.height);

          this.$refs.hiddenCanvas.width = img.width;
          this.$refs.hiddenCanvas.height = img.height;

          this.ctx = this.$refs.hiddenCanvas.getContext("2d");
          this.ctx.drawImage(img, 0, 0, img.width, img.height);

          // 创建 Fabric 图片对象
          const fabricImage = new fabric.Image(img, {
            left: 0,
            top: 0,
            width: img.width * this.canvasSizeScale, // 你可以根据需要调整宽度
            height: img.height * this.canvasSizeScale, // 高度调整为原来的1.5倍
            selectable: false // 防止背景图片被选择
          });

          // 设置背景图片
          let backgroundImageObj = this.fabricCanvas.setBackgroundImage(
            fabricImage
          );

          backgroundImage = backgroundImageObj.backgroundImage;

          this.fabricCanvas.on("object:modified", this.modifyRect);

          this.$emit("fabricEnd");
          //this.drawTags(this.tagsData[0]);
        });
      };
    },
    clear() {
      this.fabricCanvas.getObjects().forEach(obj => {
        if (obj !== this.fabricCanvas.backgroundImage) {
          this.fabricCanvas.remove(obj);
        }
      });
    },
    getGroupById(id) {
      let result = null;
      this.fabricCanvas.getObjects().forEach(obj => {
        console.log(obj);
        if (obj.id === id) {
          result = obj;
        }
      });
      return result;
    },
    remove(item) {
      console.log("id", item.id);

      let result = this.getGroupById(item.id);

      console.log("result", result);

      if (result) {
        this.fabricCanvas.remove(result);
      }
    },
    drawTags(item, callback = () => {}) {
      // 创建一个矩形
      const rect = new fabric.Rect({
        fill: this.hexToRgba(item.color, 0.2), // 填充颜色,透明度为 0.2
        width: item.width, // 矩形的宽度
        height: item.height, // 矩形的高度
        angle: 0, // 旋转角度
        stroke: item.color,
        strokeWidth: 2 // 边框宽度
      });

      // 创建第一个文字对象
      const text1 = new fabric.Text(item.label, {
        fontFamily: "Arial",
        fontSize: 20,
        fill: item.color // 文字颜色
        // stroke: "#ffffff", // 文字边框颜色
        // strokeWidth: 0.5 // 文字边框宽度
      });

      // 计算文字位置以确保其在矩形的正中央
      text1.set({
        left: rect.left + rect.width / 2,
        top: rect.top + rect.height / 2,
        originX: "center",
        originY: "center"
      });

      // 使用fabric.Group将矩形和文字组合在一起
      const group = new fabric.Group([rect, text1], {
        left: item.isInit
          ? this.canvasProp.width / 2 - item.width / 2
          : item.startX, // 矩形的左上角 x 坐标
        top: item.isInit
          ? this.canvasProp.height / 2 - item.height / 2
          : item.startY, // 矩形的左上角 y 坐标
        cornerColor: item.color, // 控制点的颜色
        cornerSize: 10, // 控制点的大小
        borderWidth: 0, // 选中时的边框宽度
        transparentCorners: true,
        angle: item.rotate, // 组合对象的旋转角度
        id: item.id
      });
      // 将组合添加到画布上
      console.log("添加到画布上", group);
      this.fabricCanvas.add(group);
      callback();
    },
    saveData() {
      this.getPointData();
    },
    getACoords(point, viewportTransform, zoom) {
      return [Math.round(point.x), Math.round(point.y)];
    },
    getPointData() {
      let result = {};
      this.fabricCanvas.getObjects().forEach(rect => {
        console.log("rect==", rect);
        const coords = [];
        const points = rect.get("aCoords"); // 获取矩形的绝对坐标

        console.log("points", points);

        const viewportTransform = this.fabricCanvas.viewportTransform;
        const zoom = this.fabricCanvas.getZoom();
    

        // 将内部坐标转换为实际画布坐标
        coords.push(this.getACoords(points["tl"], viewportTransform, zoom));
        coords.push(this.getACoords(points["tr"], viewportTransform, zoom));
        coords.push(this.getACoords(points["br"], viewportTransform, zoom));
        coords.push(this.getACoords(points["bl"], viewportTransform, zoom));
        console.log("coords", coords);

        result[rect.id] = coords;
      });
      console.log("result", result);
      return result;
    }
  }
};
</script>
<style lang="scss" scoped>
.muane {
  height: 36px;
  background: #fafafa;
  display: flex;
  align-items: center;
  padding: 0px 1px;
  border-left: 1px solid rgb(229, 229, 229);
  border-right: 1px solid rgb(229, 229, 229);
  border-bottom: 1px solid rgb(229, 229, 229);
  span {
    width: 50%;
    text-align: center;
  }
}
.canvas-wrap {
  border-left: 1px solid rgb(229, 229, 229);
  border-right: 1px solid rgb(229, 229, 229);
  border-top: 1px solid rgb(229, 229, 229);
}
</style>

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现图片的360度旋转,可以使用canvas的transform方法和事件监听器来实现。具体步骤如下: 1. 创建一个canvas元素和一个图片元素,并将图片元素加载到canvas中。 2. 在canvas上绘制图片,并设置图片的初始位置和旋转角度。 3. 监听鼠标点击事件,并根据鼠标点击位置和图片中心点的距离计算出图片需要旋转的角度。 4. 使用canvas的transform方法来旋转图片,并在canvas上重新绘制旋转后的图片。 下面是一个示例代码,可以实现图片在舞台上点击后旋转360度: ```html <!DOCTYPE html> <html> <head> <title>Canvas图片旋转</title> <style> canvas { border: 1px solid #ccc; margin: 20px auto; display: block; } </style> </head> <body> <canvas id="canvas" width="400" height="400"></canvas> <script> // 获取canvas元素和图片元素 var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var img = new Image(); img.src = 'image.jpg'; // 图片加载完成后进行绘制 img.onload = function() { // 设置图片初始位置和旋转角度 var x = canvas.width / 2; var y = canvas.height / 2; var angle = 0; // 绘制图片 ctx.save(); ctx.translate(x, y); ctx.rotate(angle * Math.PI / 180); ctx.drawImage(img, -img.width / 2, -img.height / 2); ctx.restore(); // 监听canvas的点击事件 canvas.addEventListener('click', function(event) { // 计算鼠标点击位置和图片中心点的距离 var mouseX = event.clientX - canvas.offsetLeft; var mouseY = event.clientY - canvas.offsetTop; var dx = mouseX - x; var dy = mouseY - y; // 计算图片需要旋转的角度 angle = Math.atan2(dy, dx) * 180 / Math.PI; angle += 90; // 绘制旋转后的图片 ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.save(); ctx.translate(x, y); ctx.rotate(angle * Math.PI / 180); ctx.drawImage(img, -img.width / 2, -img.height / 2); ctx.restore(); }); }; </script> </body> </html> ``` 在这段代码中,我们监听了canvas的点击事件,并在事件处理函数中计算了鼠标点击位置和图片中心点的距离,然后根据这个距离计算出图片需要旋转的角度。最后使用canvas的transform方法来旋转图片,并在canvas上重新绘制旋转后的图片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值