0

如何在画布中拖动线条?

我可以使用这个答案在画布中添加线条。

在这种情况下,答案线拖动是有效的,但是当我在离子应用程序中使用它时它不起作用。

这是我的代码:

import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
})
export class HomePage {
  @ViewChild('canvasDraw', { static: false }) canvas: ElementRef;

  canvasElement: any;
  lines: any[];
  isDown: boolean = false;
  startX: number;
  startY: number;
  nearest: any;
  offsetX: any;
  offsetY: any;

  constructor() {
    setTimeout(() => {
      let ctx = this.canvasElement.getContext('2d');
    }, 1000)
  }

  ngOnInit() {
  }

  ngAfterViewInit(): void {
    this.canvasElement = this.canvas.nativeElement;
    // canvas lets
    let canvas = document.getElementById("canvasDraw");

    // line lets
    // let this.nearest;
    this.lines = [];
    this.lines.push({ x0: 75, y0: 25, x1: 125, y1: 25 });
    this.lines.push({ x0: 75, y0: 100, x1: 125, y1: 100 });
    this.lines.push({ x0: 50, y0: 35, x1: 50, y1: 85 });
    this.lines.push({ x0: 150, y0: 35, x1: 150, y1: 85 });

    this.draw();
  }

  reOffset() {
    let canvas = document.getElementById("canvasDraw");
    let BB = canvas.getBoundingClientRect();
    this.offsetX = BB.left;
    this.offsetY = BB.top;
  }

  ionViewWillLeave() {
  }

  // select the this.nearest line to the mouse
  closestLine(mx, my) {
    let dist = 100000000;
    let index, pt;
    for (let i = 0; i < this.lines.length; i++) {
      //
      let xy = this.closestXY(this.lines[i], mx, my);
      //
      let dx = mx - xy.x;
      let dy = my - xy.y;
      let thisDist = dx * dx + dy * dy;
      if (thisDist < dist) {
        dist = thisDist;
        pt = xy;
        index = i;
      }
    }
    let line = this.lines[index];
    return ({ pt: pt, line: line, originalLine: { x0: line.x0, y0: line.y0, x1: line.x1, y1: line.y1 } });
  }

  // linear interpolation -- needed in setClosestLine()
  lerp(a, b, x) {
    return (a + x * (b - a));
  }

  // find closest XY on line to mouse XY
  closestXY(line, mx, my) {
    let x0 = line.x0;
    let y0 = line.y0;
    let x1 = line.x1;
    let y1 = line.y1;
    let dx = x1 - x0;
    let dy = y1 - y0;
    let t = ((mx - x0) * dx + (my - y0) * dy) / (dx * dx + dy * dy);
    t = Math.max(0, Math.min(1, t));
    let x = this.lerp(x0, x1, t);
    let y = this.lerp(y0, y1, t);
    return ({ x: x, y: y });
  }

  // draw the scene
  draw() {
    let ctx = this.canvasElement.getContext('2d');
    let cw = this.canvasElement.width;
    let ch = this.canvasElement.height;
    ctx.clearRect(0, 0, cw, ch);
    // draw all lines at their current positions
    for (let i = 0; i < this.lines.length; i++) {
      this.drawLine(this.lines[i], 'black');
    }
    // draw markers if a line is being dragged
    if (this.nearest) {
      // point on line this.nearest to mouse
      ctx.beginPath();
      ctx.arc(this.nearest.pt.x, this.nearest.pt.y, 5, 0, Math.PI * 2);
      ctx.strokeStyle = 'red';
      ctx.stroke();
      // marker for original line before dragging
      this.drawLine(this.nearest.originalLine, 'red');
      // hightlight the line as its dragged
      this.drawLine(this.nearest.line, 'red');
    }
  }

  drawLine(line, color) {
    let ctx = this.canvasElement.getContext('2d');
    ctx.beginPath();
    ctx.moveTo(line.x0, line.y0);
    ctx.lineTo(line.x1, line.y1);
    ctx.strokeStyle = color;
    ctx.stroke();
  }

  handleMouseDown(e: { preventDefault: () => void; stopPropagation: () => void; clientX: number; clientY: number; }) {
    // tell the browser we're handling this event
    e.preventDefault();
    e.stopPropagation();
    // mouse position
    this.startX = e.clientX - this.offsetX;
    this.startY = e.clientY - this.offsetY;
    // find this.nearest line to mouse
    this.nearest = this.closestLine(this.startX, this.startY);
    this.draw();
    // set dragging flag
    this.isDown = true;
  }

  handleMouseUpOut(e) {
    // tell the browser we're handling this event
    e.preventDefault();
    e.stopPropagation();
    // clear dragging flag
    this.isDown = false;
    this.nearest = null;
    this.draw();
  }

  handleMouseMove(e) {
    if (!this.isDown) { return; }
    // tell the browser we're handling this event
    e.preventDefault();
    e.stopPropagation();
    // mouse position
    const mouseX = e.clientX - this.offsetX;
    const mouseY = e.clientY - this.offsetY;
    // calc how far mouse has moved since last mousemove event
    let dx = mouseX - this.startX;
    let dy = mouseY - this.startY;
    this.startX = mouseX;
    this.startY = mouseY;
    // change this.nearest line vertices by distance moved
    let line = this.nearest.line;
    line.x0 += dx;
    line.y0 += dy;
    line.x1 += dx;
    line.y1 += dy;
    // redraw
    this.draw();
  }

}

这是我的 HTML 文件

<canvas #canvasDraw width=300 height=300></canvas>

我试图喜欢这个,但看起来它不起作用

<canvas #canvasDraw width=300 height=300 (mousedown)="handleMouseDown($event)" (mousemove)="handleMouseMove($event)"
    (mouseup)="handleMouseUpOut($event)" (mouseout)="handleMouseUpOut($event)"></canvas>
4

1 回答 1

1

您忘记确保使用以下方法设置偏移量:reOffset()。在您上面共享的代码中,您根本没有使用该方法,并且代码依赖于正确设置偏移量。

一旦视图完全初始化,就应该调用这个方法,不幸的是,即使 ngAfterViewInit() 也不会帮助捕获实际的偏移量,因为 Ionic 的标头不会完全初始化。

所以我使用 requestAnimationFrame 技巧来确保正确设置偏移量(你也可以使用 Promise.resolve 或使用 setTimeout):

ngAfterViewInit() {
    this.canvasElement = this.canvas.nativeElement;
    this.lines = [];
    this.lines.push({ x0: 75, y0: 25, x1: 125, y1: 25 });
    this.lines.push({ x0: 75, y0: 100, x1: 125, y1: 100 });
    this.lines.push({ x0: 50, y0: 35, x1: 50, y1: 85 });
    this.lines.push({ x0: 150, y0: 35, x1: 150, y1: 85 });
    this.draw();
    //this.reOffset();
    requestAnimationFrame(()=>{
      this.reOffset()
    })
  }

这里的工作版本:https ://stackblitz.com/edit/ionic-angular-v5-twdvkm?file=src/app/app.component.ts

于 2020-08-17T14:21:31.757 回答