Angular9中HTML Canvas绘制线条与矩形无法同时显示问题
Angular Canvas绘制内容被清空问题修复方案
问题根因
- 每次点击绘制按钮切换Line/Pencil/Rectangle模式时,都会重新调用
createLine()方法,方法内部每次都会重新为canvas的width、height属性赋值:根据Canvas原生特性,只要修改这两个属性,画布就会自动清空所有已绘制内容 - 多次调用
createLine()会重复给canvas绑定鼠标监听事件,导致同一事件触发多次绘制逻辑,出现异常 - 绘制方法存在语法错误:铅笔绘制方法误用了不存在的
e.X属性,线条绘制方法错误给fillRect方法赋值颜色
修复方案
1. 修改HTML代码
给canvas添加模板引用变量,匹配TS中@ViewChild的选择器:
<div class="field"> <!-- 新增#canvas模板引用 --> <canvas #canvas id="canvas"></canvas> <div class="tools" style="margin-top: 20px;"> <button type="button" (click)="createLines()">Line</button> <button type="button" (click)="createPencil()">Pencil</button> <button type="button" (click)="createRectangle()">Rectangle</button> <div (click)="change_color_red()" class="color-field" style="background-color: red;"></div> <div (click)="change_color_blue()" class="color-field" style="background-color: blue;"></div> <div (click)="change_color_green()" class="color-field" style="background-color: green;"></div> </div> </div>
2. 修正TS代码
将画布初始化、事件绑定逻辑抽离到ngAfterViewInit生命周期中仅执行一次,切换绘制模式时仅修改mode参数,不再重新初始化画布:
import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core'; @Component({ // 替换为你的实际组件配置 selector: 'app-canvas-draw', templateUrl: './canvas-draw.component.html', styleUrls: ['./canvas-draw.component.css'] }) export class CanvasDrawComponent implements AfterViewInit { @ViewChild('canvas', {static: false}) canvas: ElementRef<HTMLCanvasElement>; mode: string; draw_color: string = 'black'; snapshot: ImageData; private canvasEle: HTMLCanvasElement; private context: CanvasRenderingContext2D; private startPosition = {x: 0, y: 0}; private lineCoordinates = {x: 0, y: 0}; private isDrawStart = false; ngAfterViewInit(): void { // 初始化逻辑仅执行一次,避免重复清空画布 this.canvasEle = this.canvas.nativeElement; this.context = this.canvasEle.getContext('2d'); this.canvasEle.height = window.innerHeight - 500; this.canvasEle.width = window.innerWidth - 500; this.bindEvents(); } createPencil(){ this.mode = "Pencil"; } createLines(){ this.mode = "Line"; } createRectangle(){ this.mode = "Rectangle"; } private bindEvents() { this.canvasEle.addEventListener('mousedown', this.mouseDownListener.bind(this)); this.canvasEle.addEventListener('mousemove', this.mouseMoveListener.bind(this)); this.canvasEle.addEventListener('mouseup', this.mouseupListener.bind(this)); } private getClientOffset = (event) => { const {pageX, pageY} = event.touches ? event.touches[0] : event; const x = pageX - this.canvasEle.offsetLeft; const y = pageY - this.canvasEle.offsetTop; return {x, y} } private drawRectangle = (e) => { this.context.beginPath(); this.context.lineWidth = 2; // 修正矩形宽高计算,支持反向绘制 const rectWidth = this.lineCoordinates.x - this.startPosition.x; const rectHeight = this.lineCoordinates.y - this.startPosition.y; this.context.rect(this.startPosition.x, this.startPosition.y, rectWidth, rectHeight); this.context.strokeStyle = this.draw_color; this.context.stroke(); e.preventDefault(); } private drawPencil = (e) => { this.context.lineWidth = 2; this.context.lineCap = "round"; this.context.strokeStyle = this.draw_color; this.context.beginPath(); this.context.moveTo(this.startPosition.x, this.startPosition.y); this.context.lineTo(this.lineCoordinates.x, this.lineCoordinates.y); this.context.stroke(); // 修正铅笔连续绘制的坐标衔接问题 this.startPosition = {...this.lineCoordinates}; e.preventDefault(); } private drawLine = (e) => { this.context.beginPath(); this.context.lineWidth = 2; this.context.moveTo(this.startPosition.x, this.startPosition.y); this.context.lineTo(this.lineCoordinates.x, this.lineCoordinates.y); // 修正颜色赋值错误 this.context.strokeStyle = this.draw_color; this.context.stroke(); e.preventDefault(); } private mouseDownListener = (event) => { this.startPosition = this.getClientOffset(event); this.isDrawStart = true; this.takesnapshot(); event.preventDefault(); } private mouseMoveListener = (event) => { if(!this.isDrawStart) return; this.lineCoordinates = this.getClientOffset(event); this.restoresnapshot(); if(this.mode == 'Line'){ this.drawLine(event); }else if(this.mode == 'Rectangle'){ this.drawRectangle(event); }else{ this.drawPencil(event); } } private mouseupListener = (event) => { this.isDrawStart = false; event.preventDefault(); } private takesnapshot = () => { this.snapshot = this.context.getImageData(0, 0, this.canvasEle.width, this.canvasEle.height); } private restoresnapshot = () => { this.context.putImageData(this.snapshot, 0, 0); } change_color_red(){ this.draw_color = "red"; } change_color_blue(){ this.draw_color = "blue"; } change_color_green(){ this.draw_color = "green"; } }
内容的提问来源于stack exchange,提问作者Mritunjay Sharma
相关产品推荐
相关产品推荐

