canvas画以中心点旋转的矩形

<template>
  <canvas
    id="cvs"
    width="600"
    height="600"
    style="background-color: rgba(0, 0, 0, 0.1); outline: none"
    tabindex="0"
  ></canvas>
</template>

<script lang="ts">
import { Options, Vue } from "vue-class-component";

@Options({
  components: {},
})
export default class Home extends Vue {
  private rectangle: Array<Array<number>> = [];

  mounted(): void {
    let cvs = document.getElementById("cvs") as HTMLCanvasElement;
    let ctx = cvs.getContext("2d") as CanvasRenderingContext2D;

    cvs.onmousedown = (ev) => {
      this.rectangle = [];
      let onkeyDownMousePosition: Array<number> = [];
      let onkeyDownRectPosition: Array<Array<number>> = [];
      let onkeyDownStatus = false;

      cvs.onmousemove = (event) => {
        if (onkeyDownStatus) {
          // 旋转
          let angle = this.point3_angle(
            [ev.offsetX, ev.offsetY],
            onkeyDownMousePosition,
            [event.offsetX, event.offsetY]
          );

          this.rectangle = [
            this.point2angle_point(
              [ev.offsetX, ev.offsetY],
              onkeyDownRectPosition[0],
              angle
            ),
            this.point2angle_point(
              [ev.offsetX, ev.offsetY],
              onkeyDownRectPosition[1],
              angle
            ),
            this.point2angle_point(
              [ev.offsetX, ev.offsetY],
              onkeyDownRectPosition[2],
              angle
            ),
            this.point2angle_point(
              [ev.offsetX, ev.offsetY],
              onkeyDownRectPosition[3],
              angle
            ),
          ];
        } else {
          // 缩放
          const x = event.offsetX - ev.offsetX;
          const y = event.offsetY - ev.offsetY;
          this.rectangle = [
            [ev.offsetX + x, ev.offsetY + y],
            [ev.offsetX - x, ev.offsetY + y],
            [ev.offsetX - x, ev.offsetY - y],
            [ev.offsetX + x, ev.offsetY - y],
          ];
          onkeyDownMousePosition = [event.offsetX, event.offsetY];
          onkeyDownRectPosition = [...this.rectangle];
        }
        this.drawerCanvas(ctx, [ev.offsetX, ev.offsetY]);
      };

      cvs.onkeydown = (event) => {
        onkeyDownStatus = event.shiftKey;
      };

      cvs.onkeyup = (event) => {
        onkeyDownStatus = event.shiftKey;
      };
    };

    cvs.onmouseup = () => {
      cvs.onkeydown = null;
      cvs.onkeyup = null;
      cvs.onmousemove = null;
    };
  }

  // 根据中心点、起点、终点算弧度
  private point3_angle(
    center: Array<number>,
    start: Array<number>,
    end: Array<number>
  ): number {
    let endAngle = Math.atan2(end[1] - center[1], end[0] - center[0]);
    let startAngle = Math.atan2(start[1] - center[1], start[0] - center[0]);
    return endAngle - startAngle;
  }

  // 根据中心点、起点、旋转弧度算终点
  private point2angle_point(
    center: Array<number>,
    start: Array<number>,
    angle: number
  ): Array<number> {
    const r = Math.sqrt(
      Math.pow(start[0] - center[0], 2) + Math.pow(start[1] - center[1], 2)
    );
    const endAngle =
      this.point3_angle(center, [center[0] + 1, center[1]], start) + angle;

    let cosVal = Math.cos(endAngle);
    let sinVal = Math.sin(endAngle);
    if (cosVal > 1 || cosVal < -1) {
      cosVal = 0;
    }
    if (sinVal > 1 || sinVal < -1) {
      sinVal = 0;
    }
    return [cosVal * r + center[0], sinVal * r + center[1]];
  }

  private drawerCanvas(ctx: CanvasRenderingContext2D, center: Array<number>) {
    const r = 3;
    ctx.clearRect(0, 0, 600, 600);
    ctx.lineWidth = 1;
    ctx.strokeStyle = "rgb(0,255,0)";

    ctx.setLineDash([3, 3]);
    ctx.beginPath();
    this.rectangle.forEach((li) => {
      ctx.lineTo(li[0], li[1]);
    });
    ctx.closePath();
    ctx.lineTo(center[0], center[1]);
    ctx.stroke();
    ctx.setLineDash([]);
    this.rectangle.forEach((li) => {
      ctx.clearRect(li[0] - r, li[1] - r, 2 * r, 2 * r);
      ctx.beginPath();
      ctx.arc(li[0], li[1], r, 0, 2 * Math.PI, true);
      ctx.stroke();
    });
  }
}
</script>
原文地址:https://www.cnblogs.com/linding/p/15405807.html