如何在 HTML5 画布中使用自定义字体?
如何在 HTML5 画布上绘制外部字体?
如果您想在 Konva.Text
中使用自定义字体,只需执行以下步骤:
- 将字体样式添加到您的页面
- 将
fontFamily
属性设置为所需的字体面。
但这里有一个重要的事情。当您为 DOM 元素(如 div
或 span
)设置字体时,浏览器会在字体加载后自动更新这些元素。但这对于画布文本则不起作用。您需要再次重绘画布。
现代方法:CSS 字体加载 API
检测字体何时加载的最现代方法是使用 CSS 字体加载 API,它在所有现代浏览器中都得到了支持。
该 API 提供了一种干净、基于 Promise 的方式来加载和检测字体,而无需任何黑客或变通方法。
- Vanilla
- React
- Vue
import Konva from 'konva'; // 建立我们的舞台 const width = window.innerWidth; const height = window.innerHeight; const stage = new Konva.Stage({ container: 'container', width: width, height: height, }); const layer = new Konva.Layer(); stage.add(layer); // 添加一个默认字体的文本节点 const text = new Konva.Text({ x: 50, y: 50, fontSize: 40, text: '带有自定义字体的文本。', width: 250, // 开始使用默认字体 fontFamily: 'Arial' }); // 添加另一个文本帮助调试字体加载 const debugText = new Konva.Text({ x: 50, y: 0, fontSize: 16, text: '加载字体...', fill: 'green' }); layer.add(text); layer.add(debugText); // 首先,通过样式表链接加载字体(更可靠) const fontLink = document.createElement('link'); fontLink.href = 'https://fonts.googleapis.com/css2?family=Kavivanar&display=swap'; fontLink.rel = 'stylesheet'; document.head.appendChild(fontLink); // 使用浏览器的字体加载机制检测何时准备好 document.fonts.ready.then(() => { // 检查我们的字体是否被加载 if (document.fonts.check('1em Kavivanar')) { text.fontFamily('Kavivanar'); debugText.text('字体加载成功!'); } else { // 备选方案 - 尝试稍作延迟(某些浏览器的常见问题) setTimeout(() => { debugText.text('使用备选计时器 - 现在尝试设置字体'); text.fontFamily('Kavivanar'); }, 500); } }).catch(err => { debugText.text('加载字体错误: ' + err.message); debugText.fill('red'); console.error('字体加载失败:', err); });
import { Stage, Layer, Text } from 'react-konva'; import { useState, useEffect } from 'react'; const App = () => { const [fontLoaded, setFontLoaded] = useState(false); const [fontStatus, setFontStatus] = useState('加载字体...'); useEffect(() => { // 使用常规样式表链接加载字体(更可靠) const fontLink = document.createElement('link'); fontLink.href = 'https://fonts.googleapis.com/css2?family=Kavivanar&display=swap'; fontLink.rel = 'stylesheet'; document.head.appendChild(fontLink); // 使用 document.fonts.ready promise 检测何时加载字体 document.fonts.ready.then(() => { // 检查我们的字体是否被加载 if (document.fonts.check('1em Kavivanar')) { setFontStatus('字体加载成功!'); setFontLoaded(true); } else { // 备选方案 - 尝试稍作延迟 setTimeout(() => { setFontStatus('使用备选计时器 - 现在尝试设置字体'); setFontLoaded(true); }, 500); } }).catch(err => { setFontStatus('加载字体错误: ' + err.message); console.error('字体加载失败:', err); }); }, []); return ( <Stage width={window.innerWidth} height={window.innerHeight}> <Layer> <Text x={50} y={50} fontSize={40} text="带有自定义字体的文本。" width={250} fontFamily={fontLoaded ? 'Kavivanar' : 'Arial'} /> <Text x={50} y={0} fontSize={16} text={fontStatus} fill={fontStatus.includes('错误') ? 'red' : 'green'} /> </Layer> </Stage> ); }; export default App;
<template> <v-stage :config="stageSize"> <v-layer> <v-text :config="textConfig" /> <v-text :config="debugTextConfig" /> </v-layer> </v-stage> </template> <script setup> import { ref, onMounted } from 'vue'; const stageSize = { width: window.innerWidth, height: window.innerHeight }; const textConfig = ref({ x: 50, y: 50, fontSize: 40, text: '带有自定义字体的文本。', width: 250, fontFamily: 'Arial' }); const debugTextConfig = ref({ x: 50, y: 0, fontSize: 16, text: '加载字体...', fill: 'green' }); onMounted(() => { // 使用常规样式表链接加载字体(更可靠 ) const fontLink = document.createElement('link'); fontLink.href = 'https://fonts.googleapis.com/css2?family=Kavivanar&display=swap'; fontLink.rel = 'stylesheet'; document.head.appendChild(fontLink); // 使用 document.fonts.ready promise 检测何时加载字体 document.fonts.ready.then(() => { // 检查我们的字体是否被加载 if (document.fonts.check('1em Kavivanar')) { debugTextConfig.value.text = '字体加载成功!'; textConfig.value.fontFamily = 'Kavivanar'; } else { // 备选方案 - 尝试稍作延迟 setTimeout(() => { debugTextConfig.value.text = '使用备选计时器 - 现在尝试设置字体'; textConfig.value.fontFamily = 'Kavivanar'; }, 500); } }).catch(err => { debugTextConfig.value.text = '加载字体错误: ' + err.message; debugTextConfig.value.fill = 'red'; console.error('字体加载失败:', err); }); }); </script>