Create polygon and move pointes

Viewed 42

I try to add polygon on img in canvas in angular 9 app. Found solution with javascript but can't get it to work in angular application. My mouse object is always undefined with this code

import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { OnChanges } from '@angular/core/src/metadata';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  @ViewChild('canvasEl') canvas: ElementRef;

  private context: CanvasRenderingContext2D;

  mouse = { x: 0, y: 0, button: 0, lx: 0, ly: 0, update: true };
  cursor: string;
  dragging: boolean;
  activePoint;
  poygon;
  polygon: {
    points: any[];
    closed: boolean;
    addPoint(p: any): void;
    draw(): void;
    drawLengthText(): void;
    drawAngleText(): void;
    closest(pos: any, dist?: number): any;
  };

  constructor() {}

  ngOnInit() {
    this.context = (this.canvas.nativeElement as HTMLCanvasElement).getContext(
      '2d'
    );
    requestAnimationFrame(this.update);

    ['mousedown', 'mouseup', 'mousemove'].forEach((name) =>
      document.addEventListener(name, (e: MouseEvent) => {
        const bounds = (
          this.canvas.nativeElement as HTMLCanvasElement
        ).getBoundingClientRect();
        this.mouse.x = e.pageX - bounds.left - scrollX;
        this.mouse.y = e.pageY - bounds.top - scrollY;
        this.mouse.button =
          e.type === 'mousedown'
            ? 1
            : e.type === 'mouseup'
            ? 0
            : this.mouse.button;
        this.mouse.update = true;
      })
    );

    this.context.lineWidth = 2;
    this.context.strokeStyle = 'red';
    const point = (x, y) => ({ x, y });
    const poly = () => ({
      points: [],
      closed: false,
      addPoint(p) {
        this.points.push(point(p.x, p.y));
      },
      draw() {
        console.log('aa' + this.mouse);
        this.context.lineWidth = 2;
        this.context.strokeStyle = 'red';
        this.context.fillStyle = 'rgba(255, 0, 0, 0.3)';
        this.context.beginPath();
        for (const p of this.points) {
          this.context.lineTo(p.x, p.y);
        }
        this.closed && this.context.closePath();
        this.context.stroke();
        this.closed && this.context.fill();

        this.context.fillStyle = 'rgba(0, 0, 0, 0.3)';
        this.context.strokeStyle = 'rgba(0, 0, 0, 0.8)';
        for (const p of this.points) {
          this.context.beginPath();
          this.context.moveTo(p.x + 10, p.y);
          this.context.arc(p.x, p.y, 10, 0, Math.PI * 2);
          this.context.fill();
          this.context.stroke();
        }
        this.points.length > 1 && this.drawLengthText();
        this.points.length > 2 && this.drawAngleText();
      },

      drawLengthText() {
        const len = this.points.length;
        var p1,
          i = 0;
        p1 = this.points[i];
        while (i < len - (this.closed ? 0 : 1)) {
          const p2 = this.points[(i++ + 1) % len];
          const lineLength = ((p1.x - p2.x) ** 2 + (p1.y - p2.y) ** 2) ** 0.5;
          this.drawLineText(p1, p2, lineLength.toFixed(0) + 'px');
          if (len < 3) {
            break;
          }
          p1 = p2;
        }
        this.context.setTransform(1, 0, 0, 1, 0, 0);
      },

      drawAngleText() {
        const len = this.points.length;
        var p1,
          p2,
          i = this.closed ? 0 : 1;
        p1 = this.points[(i + len - 1) % len];
        p2 = this.points[i];
        while (i < len - (this.closed ? 0 : 1)) {
          const p3 = this.points[(i++ + 1) % len];
          this.drawAngleText(p1, p2, p3);
          p1 = p2;
          p2 = p3;
        }
        this.context.setTransform(1, 0, 0, 1, 0, 0);
      },

      closest(pos, dist = 8) {
        var i = 0,
          index = -1;
        dist *= dist;
        for (const p of this.points) {
          var x = pos.x - p.x;
          var y = pos.y - p.y;
          var d2 = x * x + y * y;
          if (d2 < dist) {
            dist = d2;
            index = i;
          }
          i++;
        }
        if (index > -1) {
          return this.points[index];
        }
      },
    });
    this.polygon = poly();
  }

  drawCircle(pos, color = 'black', size = 8) {
    this.context.strokeStyle = color;
    this.context.beginPath();
    this.context.arc(pos.x, pos.y, size, 0, Math.PI * 2);
    this.context.stroke();
  }

  update() {
    console.log('aaaa' + this.mouse);
    if (this.mouse.update) {
      this.cursor = 'crosshair';
      this.context.clearRect(
        0,
        0,
        (this.canvas.nativeElement as HTMLCanvasElement).width,
        (this.canvas.nativeElement as HTMLCanvasElement).height
      );
      if (!this.dragging) {
        this.activePoint = this.polygon.closest(this.mouse);
      }
      if (this.activePoint === undefined && this.mouse.button) {
        this.polygon.addPoint(this.mouse);
        this.mouse.button = 0;
      } else if (this.activePoint) {
        if (this.mouse.button) {
          if (this.dragging) {
            this.activePoint.x += this.mouse.x - this.mouse.lx;
            this.activePoint.y += this.mouse.y - this.mouse.ly;
          } else {
            if (
              !this.polygon.closed &&
              this.polygon.points.length > 2 &&
              this.activePoint === this.polygon.points[0]
            ) {
              this.polygon.closed = true;
            }
            this.dragging = true;
          }
        } else {
          this.dragging = false;
        }
      }
      this.polygon.draw();
      if (this.activePoint) {
        this.drawCircle(this.activePoint);
        this.cursor = 'move';
      }
      this.mouse.lx = this.mouse.x;
      this.mouse.ly = this.mouse.y;
      (this.canvas.nativeElement as HTMLCanvasElement).style.cursor =
        this.cursor;
      this.mouse.update = false;
    }
    requestAnimationFrame(this.update);
  }
}

Here is where I found a solution in JS

And here is my stackblitz with whole code

0 Answers
Related