Skip to main content

如何在画布上使用 Konva 显示丰富的 HTML

如何显示复杂样式(如粗体)并启用富文本编辑功能?

Canvas 的文本 API 非常有限。Konva.Text 允许您添加多种不同的样式,支持多行文本等。但目前它存在一些限制。您无法为 Konva.Text 的不同部分使用不同的样式。在这种情况下,您必须使用多个 Konva.Text 实例。

如果您想在画布上显示复杂样式,我们可以使用一种 hacky 的变通方法。这个想法很简单:

  1. 创建一个 DOM 元素并在其中放入样式化文本
  2. 使用 html2canvas 将 DOM 元素转换为图像。
  3. 使用该图像作为 Konva.Image

说明:尝试在上面的编辑器中输入和格式化文本。格式化后的文本将作为图像呈现在下面的画布上。您可以拖动渲染的文本。

import Konva from 'konva';

// 首先我们需要加载 Quill 和 html2canvas
const loadScript = (src) => {
  return new Promise((resolve, reject) => {
    const script = document.createElement('script');
    script.src = src;
    script.onload = resolve;
    script.onerror = reject;
    document.head.appendChild(script);
  });
};

const loadCSS = (href) => {
  const link = document.createElement('link');
  link.rel = 'stylesheet';
  link.href = href;
  document.head.appendChild(link);
};

// 创建编辑器容器
const editorContainer = document.createElement('div');
editorContainer.id = 'editor-container';
editorContainer.style.height = '80px';
editorContainer.innerHTML = `
  那是 <u>一些</u> <span style="color: red"> 样式化文本</span> 在
  <strong>画布</strong>上!
  <h2>你觉得怎么样?</h2>
`;
document.body.appendChild(editorContainer);

// 加载依赖
Promise.all([
  loadScript('https://cdn.quilljs.com/1.3.6/quill.js'),
  loadScript('https://html2canvas.hertzen.com/dist/html2canvas.min.js'),
]).then(() => {
  loadCSS('https://cdn.quilljs.com/1.3.6/quill.snow.css');

  const quill = new Quill('#editor-container', {
    modules: {
      toolbar: [
        [{ header: [1, 2, false] }],
        ['bold', 'italic', 'underline'],
        ['image', 'code-block'],
      ],
    },
    placeholder: '撰写一篇史诗...',
    theme: 'snow',
  });

  const stage = new Konva.Stage({
    container: 'container',
    width: window.innerWidth,
    height: 200,
  });

  const layer = new Konva.Layer();
  stage.add(layer);

  const shape = new Konva.Image({
    x: 10,
    y: 10,
    draggable: true,
    stroke: 'red',
    scaleX: 1 / window.devicePixelRatio,
    scaleY: 1 / window.devicePixelRatio,
  });
  layer.add(shape);

  function renderText() {
    // 将 DOM 转换为图像
    html2canvas(document.querySelector('.ql-editor'), {
      backgroundColor: 'rgba(0,0,0,0)',
    }).then((canvas) => {
      // 在 Konva.Image 中显示它
      shape.image(canvas);
    });
  }

  // 批量更新,以便我们不会频繁渲染文本
  let timeout = null;
  function requestTextUpdate() {
    if (timeout) {
      return;
    }
    timeout = setTimeout(function () {
      timeout = null;
      renderText();
    }, 500);
  }

  // 在所有更改上渲染文本
  quill.on('text-change', requestTextUpdate);
  // 进行初始渲染
  renderText();
});