使用ng2-canvas-whiteboard时,context.fillText()添加文字不显示且无法保存求助
使用ng2-canvas-whiteboard开发文字组件的问题与解决方案
问题描述
- 文字无法显示:在画布上点击弹出输入框,输入文字回车后,文字未出现在画布上。
- 文字无法保存:即便文字能显示,也无法随画布内容一起存入sessionStorage。
原代码片段
TextBox组件draw方法
draw(context: CanvasRenderingContext2D): void { //console.log('Intial', context); if (!this.endPosition) { return; } var canvas = document.getElementById('canvasWhiteboard'), font = '35px sans-serif', hasInput = false; canvas.onclick = function (e) { if (hasInput) return; addInput(e.clientX, e.clientY); }; //Function to dynamically add an input box: function addInput(x, y) { var input = document.createElement('input'); input.type = 'text'; input.style.position = 'fixed'; input.style.left = x - 4 + 'px'; input.style.top = y - 4 + 'px'; input.style.zIndex = '205'; input.onkeydown = handleEnter; document.body.appendChild(input); input.focus(); hasInput = true; } function handleEnter(e) { var keyCode = e.keyCode; if (keyCode === 13) { drawText( this.value, parseInt(this.style.left, 10), parseInt(this.style.top, 10) ); document.body.removeChild(this); hasInput = false; } } function drawText(txt, x, y) { context.textBaseline = 'top'; context.textAlign = 'left'; context.font = 'bold 18px Arial'; context.strokeStyle = 'black'; context.fillStyle = 'red'; context.lineWidth = 5; context.fillText(txt, x, y); context.strokeText(txt, x, y); } }
主组件saveToStorage方法
saveToStorage(): void { this.buttonSave = true; // Get the current full update history this.iframeHeight = this.iframe.nativeElement.offsetHeight; this.iframeWidth = this.iframe.nativeElement.offsetWidth; const updates: Array<CanvasWhiteboardUpdate> = this.canvasWhiteboardComponent.getDrawingHistory(); // Stringify the updates, which will return an Array<string> const stringifiedUpdatesArray: Array<string> = updates.map((update) => update.stringify() ); // Stringify the Array<string> to get a "string", so we are now ready to put this item in the storage const stringifiedStorageUpdates: string = JSON.stringify( stringifiedUpdatesArray ); // Save the item in storage of choice sessionStorage.setItem('iframeHeight', this.iframeHeight); sessionStorage.setItem('iframeWidth', this.iframeWidth); sessionStorage.setItem( 'canvasWhiteboardDrawings', stringifiedStorageUpdates ); }
解决方案
1. 修复文字无法显示问题
核心问题
- 坐标错误:
clientX/clientY是浏览器视口坐标,未转换为画布内部相对坐标。 - 直接操作context无效:ng2-canvas-whiteboard的
draw方法传入的context是临时的,后续重绘会覆盖直接绘制的内容,必须通过组件的更新机制添加绘制操作。
修改后的TextBox组件逻辑
import { Component, OnInit, ViewChild } from '@angular/core'; import { CanvasWhiteboardComponent, CanvasWhiteboardUpdate, CanvasWhiteboardUpdateType } from 'ng2-canvas-whiteboard'; @Component({ selector: 'app-text-box', templateUrl: './text-box.component.html', styleUrls: ['./text-box.component.css'] }) export class TextBoxComponent implements OnInit { @ViewChild(CanvasWhiteboardComponent) canvasWhiteboardComponent!: CanvasWhiteboardComponent; ngOnInit(): void { const canvas = document.getElementById('canvasWhiteboard') as HTMLCanvasElement; // 只绑定一次点击事件,避免重复绑定 canvas.addEventListener('click', (e) => this.handleCanvasClick(e)); } private handleCanvasClick(e: MouseEvent): void { const canvas = e.target as HTMLCanvasElement; const rect = canvas.getBoundingClientRect(); // 转换为画布内部相对坐标 const canvasX = e.clientX - rect.left; const canvasY = e.clientY - rect.top; // 创建输入框 const input = document.createElement('input'); input.type = 'text'; input.style.position = 'fixed'; input.style.left = `${e.clientX - 4}px`; input.style.top = `${e.clientY - 4}px`; input.style.zIndex = '205'; input.onkeydown = (event) => { if (event.key === 'Enter' && input.value.trim()) { // 创建自定义文字更新 const textUpdate = new CanvasWhiteboardUpdate( CanvasWhiteboardUpdateType.Custom, { text: input.value, x: canvasX, y: canvasY, font: 'bold 18px Arial', fillStyle: 'red', strokeStyle: 'black', lineWidth: 5 }, // 自定义绘制函数,会在白板重绘时调用 (ctx: CanvasRenderingContext2D, data: any) => { ctx.textBaseline = 'top'; ctx.textAlign = 'left'; ctx.font = data.font; ctx.strokeStyle = data.strokeStyle; ctx.fillStyle = data.fillStyle; ctx.lineWidth = data.lineWidth; ctx.fillText(data.text, data.x, data.y); ctx.strokeText(data.text, data.x, data.y); } ); // 将更新添加到白板组件,这样会被纳入绘制历史 this.canvasWhiteboardComponent.addUpdate(textUpdate); document.body.removeChild(input); } }; document.body.appendChild(input); input.focus(); } }
2. 修复文字无法保存问题
ng2-canvas-whiteboard的getDrawingHistory()会自动包含所有通过addUpdate添加的自定义更新,只要正确创建CanvasWhiteboardUpdate,原有的保存逻辑无需修改。
关键验证
- 确保自定义更新的
data是可JSON序列化的(避免函数、循环引用等)。 - 确认
CanvasWhiteboardComponent已正确注入到主组件中。
关键注意事项
- 避免在
draw方法中重复绑定事件,应在组件初始化时绑定一次。 - 所有绘制操作必须通过
CanvasWhiteboardUpdate添加,才能被白板的历史管理和保存逻辑识别。 - 坐标转换是基础,必须将视口坐标转为画布内部坐标,否则文字会绘制到错误位置。
内容的提问来源于stack exchange,提问作者Shrey Shah
相关产品推荐
相关产品推荐

