如何在 HTML5 画布上使用自定义字体?

如何在 HTML5 画布上绘制外部字体?

如果你想在 Konva.Text 中使用自定义字体,你只需:

  1. 将字体样式添加到你的页面
  2. fontFamily 属性设置为所需的字体。

但这里有一个重要的事情。当你为 DOM 元素(如 divspan)设置字体时,浏览器会在字体加载后自动更新那些元素。但对于画布文本,这种方式并不适用。你需要重新绘制画布。

要检测字体是否已加载,你可以使用类似 FontObserver 的东西。

但为了演示,我将使用更简单的字体加载检测。这种方法在许多字体上效果很好,而且文件大小要小得多。

还有一种更简单的解决方案是使用 setTimeout 延迟后重新绘制,但这并不能保证字体已加载。

Konva 自定义字体view raw
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/konva@9.3.18/konva.min.js"></script>
<meta charset="utf-8" />
<title>Konva Custom font loading Demo</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
background-color: #f0f0f0;
}
</style>

<!-- CUSTOM FONT STYLES -->
<link
href="https://fonts.googleapis.com/css?family=Kavivanar"
rel="stylesheet"
/>
</head>

<body>
<div id="container"></div>
<script>
// FONT LOADING DETECTION CODE:
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
ctx.font = 'normal 20px Kavivanar';

var isFontLoaded = false;
var TEXT_TEXT = 'Some test text;';
var initialMeasure = ctx.measureText(TEXT_TEXT);
var initialWidth = initialMeasure.width;

// here is how the function works
// different fontFamily may have different width of symbols
// when font is not loaded a browser will use startard font as a fallback
// probably Arial
// when font is loaded measureText will return another width
function whenFontIsLoaded(callback, attemptCount) {
if (attemptCount === undefined) {
attemptCount = 0;
}
if (attemptCount >= 20) {
callback();
return;
}
if (isFontLoaded) {
callback();
return;
}
const metrics = ctx.measureText(TEXT_TEXT);
const width = metrics.width;
if (width !== initialWidth) {
isFontLoaded = true;
callback();
} else {
setTimeout(function () {
whenFontIsLoaded(callback, attemptCount + 1);
}, 1000);
}
}

// NOW build our stage

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

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

var layer = new Konva.Layer();
stage.add(layer);
var text = new Konva.Text({
x: 50,
y: 50,
fontSize: 40,
text: 'A text with custom font.',
width: 250,
});

layer.add(text);

whenFontIsLoaded(function () {
// set font style when font is loaded
// so Konva will recalculate text wrapping if it has limited width
text.fontFamily('Kavivanar');
});
</script>
</body>
</html>