Skip to content

canvas 文字

绘制文本主要使用两个 api。

  1. CanvasRenderingContext2D.fillText() 是 Canvas 2D API 在 (x, y) 位置填充文本的方法。如果选项的第四个参数提供了最大宽度,文本会进行缩放以适应最大宽度。
js
void ctx.fillText(text, x, y, [maxWidth]);
  1. CanvasRenderingContext2D.strokeText() 是 Canvas 2D API 在给定的 (x, y) 位置绘制文本轮廓的方法。如果提供了表示最大值的第四个参数,文本将会缩放适应宽度。
js
void ctx.strokeText(text, x, y [, maxWidth]);

绘制一个 Hello World

可以看到文字有种被压扁的感觉。因为正常来讲文字会超出 canvas 的区域,但是我们设置了 maxWidth 参数,所以文字会压缩来适应最大宽度。

除此之外,还可以使用 fillText 来填充文本。

vue
<template>
  <canvas id="hello-world" width="80" height="100"></canvas>
  <canvas id="hello-world3" class="mt-10px" width="200" height="100"></canvas>
  <canvas id="hello-world2" class="mt-10px" width="200" height="100"></canvas>
</template>
<script setup lang='ts'>
import { onMounted } from 'vue';

onMounted(() => {
  const ctx = (document.getElementById('hello-world') as HTMLCanvasElement).getContext('2d')!
  ctx.strokeRect(0, 0, 80, 100)
  ctx.font = '48px serif'
  ctx.strokeText('hello, world', 0, 50, 80) 

  const ctx2 = (document.getElementById('hello-world2') as HTMLCanvasElement).getContext('2d')!
  ctx2.strokeRect(0, 0, 200, 100)
  ctx2.font = '48px serif'
  ctx2.fillText('hello', 0, 50) 

  const ctx3 = (document.getElementById('hello-world3') as HTMLCanvasElement).getContext('2d')!
  ctx3.strokeRect(0, 0, 200, 100)
  ctx3.font = '48px serif'
  ctx3.strokeText('hello', 0, 50) 
})
</script>

有样式的文本

文本居中方式 textAlign

ctx.textAlign

这里的 textAlign="center"比较特殊。textAlign 的值为 center 时候文本的居中是基于你在 fillText 的时候所给的 x 的值,也就是说文本一半在 x 的左边,一半在 x 的右边(可以理解为计算 x 的位置时从默认文字的左端,改为文字的中心,因此你只需要考虑 x 的位置即可)。所以,如果你想让文本在整个 canvas 居中,就需要将 fillText 的 x 值设置成 canvas 的宽度的一半。

vue
<template>
  <canvas id="style-text" width="200" height="200"></canvas>
</template>
<script setup lang='ts'>
import { onMounted } from 'vue';

onMounted(() => {
  const ctx = (document.getElementById('style-text') as HTMLCanvasElement).getContext('2d')!
  ctx.strokeRect(0, 0, 200, 200)
  // 使用和 css 的 font 相同的属性值
  ctx.font = '48px serif'
  // 如果想让文本在 canvas 水平居中,不仅要设置 textAlign = 'center',还要设置绘制文本的 x 在画布中间。
  ctx.textAlign = 'center'
  // 基线对齐选项
  ctx.textBaseline = 'bottom'
  // 文本阅读方向
  ctx.direction = 'rtl'
  ctx.strokeText('hello', 100, 50) 
})
</script>

文本垂直居中方式 textBaseline

ctx.textBaseline

js
ctx.textBaseline = "top" || "hanging" || "middle" || "alphabetic" || "ideographic" || "bottom";
vue
<template>
  <canvas id="textBaseline" width="550" height="550" class="w-full"></canvas>
</template>
<script setup lang='ts'>
import { onMounted } from 'vue'

onMounted(() => {
  const ctx = (document.getElementById('textBaseline') as HTMLCanvasElement).getContext('2d')!
  ctx.strokeRect(0, 0, 550, 550)
  const baselines = ['top', 'hanging', 'middle', 'alphabetic', 'ideographic', 'bottom'] as CanvasTextBaseline[]
  ctx.font = '36px serif'
  ctx.strokeStyle = 'red'

  baselines.forEach((baseline, index) => {
    ctx.textBaseline = baseline
    const y = 75 + index * 75
    ctx.beginPath()
    ctx.moveTo(0, y + 0.5)
    ctx.lineTo(550, y + 0.5)
    ctx.stroke()
    ctx.fillText(`Abcdnop 啊瑟瑟发抖 (${baseline})`, 0, y)
  })
})
</script>

绘制文本的方向 direction

ctx.direction

比如要绘制一个文本 hello

从左到右绘制:h -> e -> l -> l -> 0

从右到左绘制:o -> l -> l -> e -> h

虽然最后呈现的一样,但是绘制字母的顺序不一样。

预测量文本宽度 measureText

当你需要获得更多的文本细节时,下面的方法可以给你测量文本的方法。

js
measureText()

将返回一个 TextMetrics 对象的宽度、所在像素,这些体现文本特性的属性。

下面的代码段将展示如何测量文本来获得它的宽度:

js
function draw() {
  var ctx = document.getElementById('canvas').getContext('2d');
  var text = ctx.measureText("foo"); // TextMetrics object
  text.width; // 16;
}

Released under the MIT License.