如何在Node canvas中实现文本自动换行?
解决方案
Node Canvas 没有内置文本自动换行API,你可以通过measureText()方法手动计算文本宽度实现换行,具体实现如下:
核心逻辑
- 预设文本区域的最大宽度,你当前文本从x=500的位置开始绘制,画布总宽1920,建议最大宽度设为1300,预留右侧边距
- 把待绘制的文本按空格拆分为单词,逐个拼接计算宽度,超过最大宽度就拆为新行
- 按行逐行绘制文本,每行的y坐标按行高递增即可
修改后完整代码
// 字体注册放到事件外,避免重复注册 const { registerFont, createCanvas, loadImage } = require('canvas') registerFont('./disc2.otf', { family: 'Comic Sans' }) const Discord = require('discord.js') // 自动换行工具函数:传入画布上下文、待绘制文本、最大宽度,返回拆分好的行数组 function wrapText(ctx, text, maxWidth) { let words = text.split(' ') let lines = [] let currentLine = words[0] for (let i = 1; i < words.length; i++) { let word = words[i] let width = ctx.measureText(currentLine + ' ' + word).width if (width < maxWidth) { currentLine += ' ' + word } else { lines.push(currentLine) currentLine = word } } lines.push(currentLine) return lines } client.on("message", async (message) => { if (message.author.bot) return; if (message.content.startsWith("R!write")) { let sliced = message.content.slice(31) let msg = `"${sliced}" - 2021` const canvas = createCanvas(1920, 900); let background = await loadImage('./lmao.jpg'); const ctx = canvas.getContext('2d') ctx.drawImage(background, 0, 0, canvas.width, canvas.height); const taggeduser = message.mentions.users.first(); if (!taggeduser) return message.channel.send('mention someone pleb') let avatar = await loadImage(taggeduser.displayAvatarURL({ dynamic: false, format: 'jpg', size: 256 })); ctx.drawImage(avatar, 160, 340); ctx.font = '100px "Comic Sans"' ctx.fillStyle = '#000' // 可自行调整文本颜色 // 拆分多行 const lines = wrapText(ctx, msg, 1300) // 逐行绘制,行高设为120px,起始y坐标为500 lines.forEach((line, index) => { ctx.fillText(line, 500, 500 + index * 120) }) let attachment = new Discord.MessageAttachment(canvas.toBuffer(), 'example.png') return message.channel.send(attachment); } });
可选优化
如果需要支持中文、emoji 等无空格分隔的字符,可以把拆分逻辑改成按单个字符拆分,逐个计算宽度即可,修改wrapText函数的拆分规则就行:
// 支持中文的换行版本 function wrapText(ctx, text, maxWidth) { let chars = text.split('') let lines = [] let currentLine = chars[0] for (let i = 1; i < chars.length; i++) { let char = chars[i] let width = ctx.measureText(currentLine + char).width if (width < maxWidth) { currentLine += char } else { lines.push(currentLine) currentLine = char } } lines.push(currentLine) return lines }
内容的提问来源于stack exchange,提问作者lelbro420
相关产品推荐
相关产品推荐

