【问题标题】:How to vertically center align Multi-Line-Text on Canvas (in NodeJS)如何在画布上垂直居中对齐多行文本(在 NodeJS 中)
【发布时间】:2020-11-08 22:23:24
【问题描述】:

我正在尝试在 npm 模块 canvas 顶部使用 canvas-multiline-text 在画布上垂直居中对齐多行文本。我不知道如何(以编程方式/自动)垂直居中文本。

文本可能是 1 个单词,也可能是一个包含 10 个以上单词的句子。有没有办法计算出它的高度并相应地计算y 的位置?

注意:不在浏览器中,我使用的是 node.js。

const fs = require('fs')
const { registerFont, createCanvas, loadImage } = require('canvas')
const drawMultilineText = require('canvas-multiline-text')

const width = 2000;
const height = 2000;
let fontSize = 250;

const canvas = createCanvas(width, height)
const context = canvas.getContext('2d')

//Filling the square
context.fillStyle = '#fff'
context.fillRect(0, 0, width, height)

//Text Styles
context.font =  "normal 700 250px Arial";
context.textAlign = 'center'
context.textBaseline = 'middle';
context.fillStyle = '#000' 

//Drawing Multi Line Text
const fontSizeUsed = drawMultilineText(
    context,
    "Hello World, this is a test",
    {
        rect: {
            x: 1000,
            y: 1000, // <-- not sure what to put here / how to calculate this?
            width: context.canvas.width - 20,
            height: context.canvas.height - 20
        },
        font: 'Arial',
        verbose: true,
        lineHeight: 1.4,
        minFontSize: 100,
        maxFontSize: 250
      }
)

【问题讨论】:

    标签: javascript css node.js canvas html5-canvas


    【解决方案1】:

    我把这个作为答案,因为我还不能发表评论,但你使用的模块不支持这个。您可以做的是修改模块(或者只是将函数复制到您自己的代码中)。该函数有一个变量 y 存储文本的高度。您可以在 for 循环之外初始化变量,以便在绘制文本时可以使用它。然后,您可以从新的 y 变量中减去 opts.rect.height 并除以 2 以获得正确的偏移量,现在文本将位于调用函数时指定的 y 变量的中心。哦,最后得到“context.textBaseline = 'middle';”因为您使用的模块会在假设底部基线的情况下进行计算。这是drawMultiLineText函数的最终代码

    ...
    const words = require('words-array')(text)
    if (opts.verbose) opts.logFunction('Text contains ' + words.length + ' words')
    var lines = []
    let y;  //New Line
    ...
    var x = opts.rect.x;
    y = fontSize; //modified line
    lines = []
    ...
    if (opts.verbose) opts.logFunction("Font used: " + ctx.font);
    const offset = opts.rect.y + (opts.rect.height - y) / 2; //New line, calculates offset
    for (var line of lines)
        // Fill or stroke
        if (opts.stroke)
            ctx.strokeText(line.text.trim(), line.x, line.y + offset) //modified line
        else
            ctx.fillText(line.text.trim(), line.x, line.y + offset) //modified line
    
    ...
    

    您使用的这个模块并不是最干净的代码(使用 var 而不是 let,具有将字符串拆分为单词的依赖项),因此我强烈建议您自己重写此函数。但这些应该是必要的更改,以使其居中文本。

    编辑:仔细查看此依赖项的代码后,似乎有比我最初认为的更多的错误,代码将高度视为矩形的底部,而不是高度。要解决此问题,请从分配 y 的行中删除 opts.rect.y,并将其添加到偏移变量(我已经对代码进行了这些更改)

    【讨论】:

    • 哇,非常感谢。看起来你真的调查过这个。虽然我是初学者,但我不是 100% 确定我现在应该在自己的代码中为变量 y 赋予什么值?看来我仍然需要以某种方式计算,还是我弄错了?
    • 我放的所有代码只是对你使用的依赖的代码的修改canvas-multiline-text。尽管有些人会认为这是不道德的,但我建议将代码放在您自己的程序中而不是使用依赖项,然后进行我指定的更改,我在修改后的行附近添加行以向您显示它们的位置,但确切的行号您应该在第 33 行、第 45 行、第 76 行、第 81 行和第 83 行进行更改
    • 是的,我明白了,已经进行了更改。但我很困惑现在如何使用这个模块使文本居中,因为它需要一个 y 变量作为 rect 值,我不知道在里面放什么,因为看起来我需要知道文本的高度以便知道y 的值。如果我只输入x: 1000, y: 1000(整个画布为2000x2000),它会给我x 的正确结果(如前所述),但仍然不是y 的正确结果。
    • 您还需要指定一个高度,它应该使文本居中在 y 和 y + 高度之间。如果它没有让我知道,因为我只是当场写了这段代码,没有时间实际测试它。编辑:所以看看你的代码,你使用画布高度作为高度,如果你想要画布中间的文本,只需使用 y: 0 和画布高度。或者 y: 20 和画布高度 - 40。如果您不喜欢这种方法,我相信您足够聪明,可以修改代码以使用 topY 和 bottomY 而不是 y 和高度。
    • 非常感谢您的快速回复,抱歉无法正常使用。使用 y: 0height: context.canvas.height 不会垂直居中,而是水平居中,但在顶部。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 2021-07-19
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    • 2016-09-21
    • 1970-01-01
    相关资源
    最近更新 更多