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

使用ng2-canvas-whiteboard时,context.fillText()添加文字不显示且无法保存求助

使用ng2-canvas-whiteboard开发文字组件的问题与解决方案

问题描述

  1. 文字无法显示:在画布上点击弹出输入框,输入文字回车后,文字未出现在画布上。
  2. 文字无法保存:即便文字能显示,也无法随画布内容一起存入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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:22:16