草庐IT

javascript - 保持文本在 Canvas 上垂直居中

coder 2023-08-12 原文

我遇到的问题是让用户输入的文本在 canvas 元素内垂直居中。我已经构建了一个测试环境来尝试解决这个问题,我在这篇文章中提供了这个问题以及一个 fiddle 。这是我的代码:

HTML:

Enter Your Text: <br/>
<textarea id="inputtextuser" onkeyup="inputtextgo()" name="Text">Enter Your</textarea> <br/>
TextBaseline: 
<select id="inputtextbaseline" onchange="inputtextgo()";> 
    <option value="alphabetic">alphabetic</option>
    <option value="top">top</option>
    <option value="bottom">bottom</option>
    <option value="middle">middle</option>
    <option value="hanging">hanging</option>
</select> <br/>
<canvas id="canvas1"  width="300px" height="200px" >Your browser does not support the HTML5 canvas tag.</canvas> <br/>
<div id ="textheightentered"></div>

CSS:

canvas {
    border: solid 1px black;
}

JavaScript/jQuery:

//Declaring the Canvas
var canvas1 = document.getElementById('canvas1');
context1 = canvas1.getContext('2d');

//running the function to update the canvas
 inputtextgo();

function inputtextgo() {
    //Retrieving the text entered by the user
    var inputtext = document.getElementById("inputtextuser").value;
    //Calling the function to calculate the height on the text entered by the user
    var textheight = fontheight(inputtext);
    //retrieving the baseline selected by the user
    var baseline = document.getElementById("inputtextbaseline").value;
    //calculating the new y needed to center the text based on the height of the text
    var y = 100 + textheight/2;

    //Updating the canvas for the new text entered by the user
    context1.clearRect(0, 0, 300, 200);
    context1.font = "36px arial";
    context1.textBaseline = baseline;
    context1.fillText (inputtext, 0, y);   

    //Drawing a line across the middle of the canvas for reference
    context1.strokeStyle="red";
    context1.moveTo(5,100);
    context1.lineTo(290,100);
    context1.stroke();
    $("#textheightentered").text("Text Height: " + textheight);
}

function fontheight(text){

    var canvas=document.createElement("canvas");
    canvas.width = 1000;
    canvas.height = 200;
    var ctx=canvas.getContext("2d");

    function measureTextHeight(left, top, width, height,text) {

        // Draw the text in the specified area
        ctx.save();
        ctx.clearRect(0,0, canvas.width, canvas.height);
        ctx.baseline = "top";
        ctx.fillText(text, 0, 35); // This seems like tall text...  Doesn't it?
        ctx.restore();

        // Get the pixel data from the canvas
        var data = ctx.getImageData(left, top, width, height).data,
            first = false, 
            last = false,
            r = height,
            c = 0;

        // Find the last line with a non-white pixel
        while(!last && r) {
            r--;
            for(c = 0; c < width; c++) {
                if(data[r * width * 4 + c * 4 + 3]) {
                    last = r;
                    break;
                }
            }
        }

        // Find the first line with a non-white pixel
        while(r) {
            r--;
            for(c = 0; c < width; c++) {
                if(data[r * width * 4 + c * 4 + 3]) {
                    first = r;
                    break;
                }
            }

            // If we've got it then return the height
            if(first != r) return last - first;
        }

        // We screwed something up...  What do you expect from free code?
        return 0;
    }
    ctx.font= "36px arial";
    var height = measureTextHeight(0, 0, canvas.width, canvas.height,text);
    //return the height of the string
    return height;
} // end $(function(){});

JSFiddle:http://jsfiddle.net/grapien/R6DWN/3/

我遇到的问题是,如果用户输入小写字母“y”,例如文本高度会发生变化,并且文本不会保留在 Canvas 的中心。这是因为在 y 变量中执行的基线校正需要根据输入的文本(小写和大写字符的组合)而有所不同,因为基线以下的文本会扭曲在 y 变量中执行的校正。

这是我遇到问题的地方,因为我想让文本始终在 canvas 元素内居中。我唯一能想到的就是计算文本基线引用点上方和下方的非空白像素。然后使用从基线到文本末端的差异来偏移文本以使其在 Canvas 上居中。我不确定您是如何编写此脚本的,或者是否有可能。但这是我想出的最好的方法。

如果有人有任何想法或指导,我将不胜感激,因为开发一种解决此问题的方法让我很困惑。

最佳答案

我相信我已经使用我在问题中陈述的技术解决了这个问题。我创建了一个新函数来计算延伸到输入文本基线以下的字体量。使用与用于计算高度的方法类似的技术。我使用字母基线,然后计算包含高于该基线的内容的像素。请参阅下面的功能。

function fontheight2(text){

    var canvas=document.createElement("canvas");
    canvas.width = 1000;
    canvas.height = 200;
    var ctx=canvas.getContext("2d");

    function measureTextHeight(left, top, width, height,text) {

        // Draw the text in the specified area
        ctx.save();
        ctx.clearRect(0,0, canvas.width, canvas.height);
        ctx.fillText(text, 0, 100); // This seems like tall text...  Doesn't it?
        ctx.restore();

        // Get the pixel data from the canvas
        var data = ctx.getImageData(left, top, width, height).data,
            first = false, 
            last = false,
            r = 100,
            c = 0;

        // Find the first line with a non-white pixel
        while(r) {
            r--;
            for(c = 0; c < width; c++) {
                if(data[r * width * 4 + c * 4 + 3]) {
                    first = r;
                    break;
                }
            }

            // If we've got it then return the height
            if(first != r) return 99 - first;
        }

        // We screwed something up...  What do you expect from free code?
        return 0;
    }
    ctx.baseline = "Alphabetic";
    ctx.font= "36px arial";
    var height = measureTextHeight(0, 0, canvas.width, canvas.height,text);
    //return the height of the string
    return height;
} // end $(function(){});

从那里我简单地使用以下对 y 的调整来将文本偏移到中心:

var textheight = fontheight(inputtext); //Calculate Text Height
var textheight2 = fontheight2(inputtext); //Calculate portion above the baseline
var difference = textheight - textheight2; // Calculate the portion below the baseline
var y = 100 - difference + textheight/2; // Adjust the y cordinate

这会偏移 y 以针对低于文本基线的文本部分进行调整。我在这里更新了 JSFiddle http://jsfiddle.net/grapien/R6DWN/6/ .

关于javascript - 保持文本在 Canvas 上垂直居中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15648267/

有关javascript - 保持文本在 Canvas 上垂直居中的更多相关文章

  1. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  2. ruby - 在 Ruby 中,垂直线是什么? - 2

    1.upto(9){|x|printx}为什么这行不通?{printx|x}}y呢? 最佳答案 它用于传递给您的block的参数。即在您的示例中,upto将使用1到9中的每个数字调用您的block,当前值可作为x获得。block参数可以有任何名称,就像方法参数一样。例如1.upto(9){|num|putsnum是有效的。就像一个方法的参数一样,一个block也可以有多个参数。例如hash.each_pair{|key,value|puts"#{key}is#{value}"} 关于ru

  3. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  4. ruby-on-rails - rspec - 我怎样才能让 "pendings"有我的文本而不仅仅是 "No reason given" - 2

    我有这个代码:context"Visitingtheusers#indexpage."dobefore(:each){visitusers_path}subject{page}pending('iii'){shouldhave_no_css('table#users')}pending{shouldhavecontent('Youhavereachedthispageduetoapermissionic错误')}它会导致几个待处理,例如ManagingUsersGivenapractitionerloggedin.Visitingtheusers#indexpage.#Noreason

  5. ruby - 如何为 pbcopy 生成富文本链接 - 2

    我一直在玩一个脚本,它在Chrome中获取选定的文本并在Google中查找它,提供四个最佳选择,然后粘贴相关链接。它以不同的格式粘贴,具体取决于当前在Chrome中打开的页面-DokuWiki打开的DokuWiki格式,普通网站的HTML,我想要我的WordPress所见即所得编辑器的富文本。我尝试使用pbpaste-Preferrtf来查看没有其他样式的富文本链接在粘贴板上的样子,但它仍然输出纯文本。在文本编辑中保存文件并进行试验后,我想出了以下内容text=%q|{\rtf1{\field{\*\fldinst{HYPERLINK"URL"}}{\fldrsltTEXT}}}|te

  6. ruby-on-rails - 尝试打开 .gitignore 以在文本编辑器中对其进行编辑,但在 OS X Mountain Lion 上找不到文件位置 - 2

    我使用“newapp_name”创建了一个新的Rails应用程序,我正在尝试编辑.gitignore文件,但在我的应用程序文件夹中找不到它。我在哪里可以找到它?我安装了Git。 最佳答案 .gitignore位于项目的root中,而不是app子目录中。首先打开终端并进入您的目录。您需要使用ls-a来显示stash文件。然后使用打开.gitignore 关于ruby-on-rails-尝试打开.gitignore以在文本编辑器中对其进行编辑,但在OSXMountainLion上找不到文件位

  7. ruby - 如何保持我不常用的编程语言技能 - 2

    关闭。这个问题是off-topic.它目前不接受答案。想改进这个问题吗?Updatethequestion所以它是on-topic用于堆栈溢出。关闭11年前。Improvethisquestion我不经常使用ruby​​-通常它加起来相当于每两个月或更长时间编写一次脚本。我的大部分编程都是使用C++进行的,这与ruby​​有很大不同。由于我与ruby​​之间的差距如此之大,我总是忘记语言的基本方面(比如解析文本文件和其他简单的东西)。我想每天练习一些基本的东西,我想知道是否有一些我可以订阅的网站,并且会向我发送当天的Ruby问题或类似的东西。有人知道这样的站点/Internet服务吗?

  8. ruby - 如何将一段文本可逆地压缩成更少的 ASCII 字符? - 2

    我想获取任意的ASCII文本字符串,例如“Helloworld”,并将其压缩为字符数较少(尽可能少)的版本,但要采用可以解压缩的方式。压缩版本应仅由ascii字符组成。有没有一种方法可以做到这一点,尤其是在Ruby中? 最佳答案 如果知道只会使用ASCII字符,那就是每个字节的低7位。通过位操作,您可以将每8个字节混合成7个字节(节省12.5%)。如果您可以将其放入更小的范围(仅限64个有效字符),则可以删除另一个字节。但是,因为您希望压缩形式也只包含ASCII字符,所以会丢失一个字节-除非您的输入可以限制为64个字符(例如,有损压

  9. ruby-on-rails - ActiveRecord:除非另有说明,否则在保存之前使所有文本字段都调用 strip - 2

    多年来,我在各种网站上遇到过各种问题,用户在字符串和文本字段的开头/结尾放置空格。有时这些会导致格式/布局问题,有时会导致搜索问题(即搜索顺序看起来不对,但实际上并非如此),有时它们实际上会使应用程序崩溃。我认为这会很有用,而不是像我过去所做的那样放入一堆before_save回调,向ActiveRecord添加一些功能以在保存之前自动调用任何字符串/文本字段上的.strip,除非我告诉它不是,例如do_not_strip:field_x,:field_y或类定义顶部的类似内容。在我去弄清楚如何做到这一点之前,有没有人看到更好的解决方案?明确一点,我已经知道我可以做到这一点:befor

  10. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

    我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

随机推荐