You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular(TypeScript)的Canvas元素上绘制矩形?

Angular Canvas 绘制矩形问题修复

问题分析

你的代码核心问题在于初始坐标记录时机错误和当前鼠标位置取值错误:

  • startX/startY应该在鼠标按下(mousedown)时记录,而不是在mousemove的pairwise回调中(回调里的res[0]是上一次移动的位置,不是按下的初始点)。
  • 计算矩形宽高时,错误使用了上一次移动的位置(res[0]),而非当前鼠标位置(res[1]),导致矩形无法跟随鼠标拖拽更新。

修正后的代码

TypeScript 代码

import { Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core';
import { fromEvent, Subscription } from 'rxjs';
import { switchMap, takeUntil } from 'rxjs/operators';
import { VERSION } from '@angular/core';

export class AppComponent implements OnDestroy {
  @Input() width = 512;
  @Input() height = 418;
  @ViewChild('canvas') canvas: ElementRef<HTMLCanvasElement>;
  cx: CanvasRenderingContext2D;
  drawingSubscription: Subscription;
  name = 'Angular ' + VERSION.major;

  ngAfterViewInit() {
    const canvasEl = this.canvas.nativeElement;
    this.cx = canvasEl.getContext('2d');
    canvasEl.width = this.width;
    canvasEl.height = this.height;

    this.cx.lineWidth = 2;
    this.captureEvents(canvasEl);
  }

  captureEvents(canvasEl: HTMLCanvasElement) {
    let startX: number;
    let startY: number;

    this.drawingSubscription = fromEvent(canvasEl, 'mousedown')
      .pipe(
        switchMap((e: MouseEvent) => {
          // 鼠标按下时记录初始坐标
          const rect = canvasEl.getBoundingClientRect();
          startX = e.clientX - rect.left;
          startY = e.clientY - rect.top;

          // 监听鼠标移动,直到松开或离开画布
          return fromEvent(canvasEl, 'mousemove').pipe(
            takeUntil(fromEvent(canvasEl, 'mouseup')),
            takeUntil(fromEvent(canvasEl, 'mouseleave'))
          );
        })
      )
      .subscribe((e: MouseEvent) => {
        const rect = canvasEl.getBoundingClientRect();
        // 获取当前鼠标位置
        const currentX = e.clientX - rect.left;
        const currentY = e.clientY - rect.top;

        // 清空画布,重新绘制矩形
        this.cx.clearRect(0, 0, canvasEl.width, canvasEl.height);
        // 计算宽高,处理正负方向(strokeRect支持负数宽高)
        const width = currentX - startX;
        const height = currentY - startY;
        this.cx.strokeRect(startX, startY, width, height);
      });
  }

  ngOnDestroy() {
    this.drawingSubscription?.unsubscribe();
  }
}

HTML 代码

<canvas #canvas></canvas>

关键修复点

  1. 初始坐标记录:在mousedown事件触发时直接记录起始点,确保矩形的起点是鼠标按下的位置。
  2. 当前位置取值:在mousemove回调中使用当前事件的坐标,而非上一次移动的坐标,保证矩形能实时跟随鼠标拖拽。
  3. 移除不必要的pairwise:因为我们不需要基于前后两点绘制线条,只需要根据起始点和当前点绘制矩形,所以可以去掉pairwise操作符,简化逻辑。

内容的提问来源于stack exchange,提问作者Sathishkumar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 01:40:45