Skip to content

Instantly share code, notes, and snippets.

@bolasblack
Last active April 17, 2020 03:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bolasblack/2d9ddebb9753f736d59fe55cb9f85e70 to your computer and use it in GitHub Desktop.
Save bolasblack/2d9ddebb9753f736d59fe55cb9f85e70 to your computer and use it in GitHub Desktop.
break lines in html5 canvas
import { textBreakLinesInCanvas } from "./textBreakLinesInCanvas"
const maxWidth = 300
const lineHeight = 24
document.querySelectorAll('canvas').forEach((e) => e.remove())
const canvas = document.createElement('canvas')
canvas.width = maxWidth
canvas.height = 300
canvas.style.lineHeight = `${lineHeight}px`
document.body.appendChild(canvas)
const context = canvas.getContext('2d')
context.font = '15pt Calibri'
context.textBaseline = 'top'
context.fillStyle = '#333'
textBreakLinesInCanvas(
context,
`测试中文 \uD83D\uDC69\u200D\u2764\uFE0F\u200D\uD83D\uDC69 🤣 F̸̡̢͓̳̜̪̟̳̠̻̖͐̂̍̅̔̂͋͂͐l̸̢̹̣̤̙͚̱͓̖̹̻̣͇͗͂̃̈͝a̸̢̡̬͕͕̰̖͍̮̪̬̍̏̎̕͘ͅv̸̢̛̠̟̄̿i̵̮͌̑ǫ̶̖͓͎̝͈̰̹̫͚͓̠̜̓̈́̇̆̑͜ͅ 🌚All the world\'s a stage`,
maxWidth,
lineHeight,
).forEach((lineInfo) => {
context.fillText(lineInfo.line, 0, lineInfo.y)
})
export function textBreakLinesInCanvas(context, text, maxWidth, lineHeight) {
// 因为一些特殊的字符(比如 emoji)用 .split('') 会被拆成两个字符,所以这里用
// 这个方式来拆字符串,参考 https://flaviocopes.com/javascript-unicode/
return [...(text || '')].reduce(
(lineInfos, char) => {
const currLineInfo = lineInfos[lineInfos.length - 1]
const newLine = currLineInfo.line + char
const metrics = context.measureText(newLine)
const newWidth = metrics.width
if (newWidth > maxWidth) {
lineInfos.push({
line: char,
y: currLineInfo.y + lineHeight,
})
} else {
currLineInfo.line = newLine
}
return lineInfos
},
[{ line: '', y: 0 }],
)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment