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

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

Canvas 的文本 API 非常有限。Konva.Text 允许您添加多种不同的样式,支持多行文本等。但目前存在一些限制。您不能为 Konva.Text 的不同部分使用不同的样式。对此,您需要使用多个 Konva.Text 实例。

如果您想在 Canvas 上显示复杂样式,我们可以采用一种黑科技的解决方案。这个思路很简单:

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

说明:尝试在编辑器中输入文本

Konva Rich Text Demoview raw
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@9.3.18/konva.min.js"></script>
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<link
rel="stylesheet"
href="https://cdn.quilljs.com/1.3.6/quill.snow.css"
/>

<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<meta charset="utf-8" />
<title>Konva Rich text on Canvas Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}

#editor-container {
height: 80px;
}
</style>
</head>

<body>
<div id="editor-container">
That is <u>some</u> <span style="color: red"> styled text</span> on
<strong>canvas</strong>!
<h2>What do you think about it?</h2>
</div>
Rendered stage:
<div id="container"></div>
<script>
var quill = new Quill('#editor-container', {
modules: {
toolbar: [
[{ header: [1, 2, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block'],
],
},
placeholder: 'Compose an epic...',
theme: 'snow', // or 'bubble'
});

var width = window.innerWidth;
var height = window.innerHeight;

var stage = new Konva.Stage({
container: 'container',
width: width,
height: height,
});

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() {
// convert DOM into image
html2canvas(document.querySelector('.ql-editor'), {
backgroundColor: 'rgba(0,0,0,0)',
}).then((canvas) => {
// show it inside Konva.Image
shape.image(canvas);
});
}

// batch updates, so we don't render text too frequently
var timeout = null;
function requestTextUpdate() {
if (timeout) {
return;
}
timeout = setTimeout(function () {
timeout = null;
renderText();
}, 500);
}

// render text on all changes
quill.on('text-change', requestTextUpdate);
// make initial rendering
renderText();
</script>
</body>
</html>