一、非流畅实现
1.canvas.component.html
<button (click)="switchMark(1)">画笔</button> <button (click)="switchMark(2)">矩形</button> <button (click)="switchMark(3)">圆形</button> <button (click)="switchMark(4)">文字</button> <button (click)="switchMark(0)">撤销</button> <input type="text" [(ngModel)]="text"> <canvas class="vp-canvas" #canvas1 width="470" height="300" style="border: 1px solid #ccc;">您的浏览器不支持画布!</canvas>
2.canvas.component.ts
// canvas @ViewChild('canvas1') public canvasRef: ElementRef; // canvas1 public canvas1; // contex1 public context1; // 操作次数 public canvasIndex = -1; // canvas图片 public canvasData = []; // 轨迹结束判断 public isSameMove = false; // 起点对象 public startXY = { x1: 0, y1: 0, x2: 0, y2: 0 }; // 开关 public switchType = null; // 文字 public Text = null; // 初始化canvas public initCanvas() { this.canvas1 = null; this.context1 = null; this.canvasIndex = -1; this.canvasData = []; this.isSameMove = false; this.startXY = { x1: 0, y1: 0, x2: 0, y2: 0 }; this.switchType = null; this.Text = null; } // 生成canvas内容及事件 public createCanvas(base64PImg) { this.initCanvas(); this.canvas1 = this.canvasRef.nativeElement; const context1 = this.canvasRef.nativeElement.getContext('2d'); var img = new Image(); img.onload = function () { context1.drawImage(img, 0, 0, 470, 300); } img.src = base64PImg; this.context1 = context1; // 添加默认图片到历史记录 this.canvasIndex++; this.canvasData.push(base64PImg); // 绑定canvas参数 this.canvas1.canvas1 = this.canvasRef.nativeElement; this.canvas1.context1 = this.canvasRef.nativeElement.getContext('2d'); this.canvas1.canvasIndex = this.canvasIndex; this.canvas1.canvasData = this.canvasData; this.canvas1.startXY = this.startXY; this.canvas1.switchType = this.switchType; this.canvas1.Text = this.Text; // 绑定canvas方法 this.canvas1.windowToCanvas = this.windowToCanvas; // 绑定canvas事件 this.canvas1.onmousedown = this.canvasMouseDown; this.canvas1.onmouseup = this.canvasMouseUp; this.canvas1.onmousemove = this.canvasMouseMove; } // 增加文字内容 public updateText(ev) { this.canvas1.Text = ev; } // 切换绘制 public switchMark(type) { if (type === 0) { this.undo(); } if (type === 0) { this.switchType = null; this.canvas1.switchType = this.switchType; return; } this.switchType = type; this.canvas1.switchType = this.switchType; } // 撤销 public undo() { if (this.canvas1.canvasIndex > 0) { this.canvasData.pop(); this.canvas1.canvasIndex--; this.context1.clearRect(0, 0, 470, 300); var context1 = this.canvasRef.nativeElement.getContext('2d'); var img = new Image(); img.onload = function () { context1.drawImage(img, 0, 0, 470, 300); } img.src = this.canvasData[this.canvas1.canvasIndex]; } else { console.log('不能再继续撤销了'); } } // 求鼠标坐标函数 public windowToCanvas(canvas, x, y) { var rect = canvas.getBoundingClientRect(); return { x: x - rect.left * (canvas.width / rect.width), y: y - rect.top * (canvas.height / rect.height) }; } // 鼠标按下开始绘制图形函数 public canvasMouseDown(e) { if (this.switchType === null) { return; } this.context1.strokeStyle = 'red'; this.context1.fillStyle = 'red'; // 绘制曲线 if (this.switchType === 1) { this.isSameMove = true; var ele = this.windowToCanvas(this.canvas1, e.clientX, e.clientY); this.context1.beginPath(); this.context1.moveTo(ele.x, ele.y); } // 绘制矩形 if (this.switchType === 2) { var ele = this.windowToCanvas(this.canvas1, e.clientX, e.clientY); this.startXY.x1 = ele.x; this.startXY.y1 = ele.y; } // 绘制圆形 if (this.switchType === 3) { var ele = this.windowToCanvas(this.canvas1, e.clientX, e.clientY); this.startXY.x1 = ele.x; this.startXY.y1 = ele.y; } // 绘制文字 if (this.switchType === 4) { var str = this.Text; var ele = this.windowToCanvas(this.canvas1, e.clientX, e.clientY); this.startXY.x1 = ele.x; this.startXY.y1 = ele.y; this.context1.font = "24px Arial"; this.context1.fillText(str, ele.x, ele.y); } } // 鼠标弹起 public canvasMouseUp(e) { if (this.switchType === null) { return; } // 曲线 if (this.switchType === 1) { this.isSameMove = false; } // 矩形 if (this.switchType === 2) { var ele = this.windowToCanvas(this.canvas1, e.clientX, e.clientY); this.startXY.x2 = ele.x; this.startXY.y2 = ele.y; this.context1.strokeRect(this.startXY.x1, this.startXY.y1, this.startXY.x2 - this.startXY.x1, this.startXY.y2 - this.startXY.y1); } // 圆形 if (this.switchType === 3) { var ele = this.windowToCanvas(this.canvas1, e.clientX, e.clientY); this.startXY.x2 = ele.x; this.startXY.y2 = ele.y; this.context1.beginPath(); var cx = (this.startXY.x1 + this.startXY.x2) / 2; var cy = (this.startXY.y1 + this.startXY.y2) / 2; var rx = Math.abs((this.startXY.x1 - this.startXY.x2) / 2); var ry = Math.abs((this.startXY.y1 - this.startXY.y2) / 2); this.context1.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2); this.context1.stroke(); } this.canvas1.canvasIndex++; this.canvasData.push(this.canvas1.toDataURL()); } // 鼠标移动 public canvasMouseMove(e) { if (this.switchType === 1) { if (this.isSameMove) { var ele = this.windowToCanvas(this.canvas1, e.clientX, e.clientY); this.context1.lineTo(ele.x, ele.y); this.context1.stroke(); this.context1.save(); } } }