Javascript 画布元素中的字母间距
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8952909/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Letter spacing in canvas element
提问by Pinpickle
The question says it all pretty much. I've been searching around and starting to worry that it's impossible.
这个问题几乎说明了一切。我一直在四处寻找,开始担心这是不可能的。
I've got this canvas element that I'm drawing text to. I want to set the letter spacing similar to the CSS letter-spacing
attribute. By that I mean increasing the amount of pixels between letters when a string is drawn.
我有我要向其绘制文本的画布元素。我想设置类似于 CSSletter-spacing
属性的字母间距。我的意思是在绘制字符串时增加字母之间的像素数量。
My code for drawing the text is like so, ctx is the canvas context variable.
我绘制文本的代码是这样的,ctx 是画布上下文变量。
ctx.font = "3em sheepsans";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = "rgb(255, 255, 255)";
ctx.fillText("Blah blah text", 1024 / 2, 768 / 2);
I've tried adding ctx.letterSpacing = "2px";
before the drawing but with no avail. Is there a way to do this just with a simple setting, or will I have to make a function to individually draw each character with the spacing in mind?
我试过ctx.letterSpacing = "2px";
在绘图之前添加但无济于事。有没有办法只用一个简单的设置来做到这一点,或者我是否必须制作一个函数来单独绘制每个字符并记住间距?
采纳答案by Phrogz
I'm not sure if it shouldwork (per specs), but in some browsers (Chrome) you can set the letter-spacing
CSS property on the <canvas>
element itself, and it will be applied to all text drawn on the context. (Works in Chrome v56, does not work in Firefox v51 or IE v11.)
我不确定它是否应该工作(根据规范),但在某些浏览器 (Chrome) 中,您可以letter-spacing
在<canvas>
元素本身上设置CSS 属性,它将应用于在上下文中绘制的所有文本。(适用于 Chrome v56,不适用于 Firefox v51 或 IE v11。)
Note that in Chrome v56 you must re-get the canvas 2d context (and re-set any values you care about) after each change to the letter-spacing
style; the spacing appears to be baked into the 2d context that you get.
请注意,在 Chrome v56 中,您必须在每次更改letter-spacing
样式后重新获取画布 2d 上下文(并重新设置您关心的任何值);间距似乎已融入您获得的 2d 上下文中。
Example: https://jsfiddle.net/hg4pbsne/1/
示例:https: //jsfiddle.net/hg4pbsne/1/
var inp = document.querySelectorAll('input'),
can = document.querySelector('canvas'),
ctx = can.getContext('2d');
can.width = can.offsetWidth;
[].forEach.call(inp,function(inp){ inp.addEventListener('input', redraw, false) });
redraw();
function redraw(){
ctx.clearRect(0,0,can.width,can.height);
can.style.letterSpacing = inp[0].value + 'px';
ctx = can.getContext('2d');
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '4em sans-serif';
ctx.fillText('Hello', can.width/2, can.height*1/4);
can.style.letterSpacing = inp[1].value + 'px';
ctx = can.getContext('2d');
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.font = '4em sans-serif';
ctx.fillText('World', can.width/2, can.height*3/4);
};
canvas { background:white }
canvas, label { display:block; width:400px; margin:0.5em auto }
<canvas></canvas>
<label>hello spacing: <input type="range" min="-20" max="40" value="1" step="0.1"></label>
<label>world spacing: <input type="range" min="-20" max="40" value="1" step="0.1"></label>
Original, cross-browser answer:
原始的跨浏览器答案:
This is not possible; the HTML5 Canvas does not have all the text-transformation power of CSS in HTML. I would suggest that you should combine the appropriate technologies for each usage. Use HTML layered with Canvas and perhaps even SVG, each doing what it does best.
这不可能; HTML5 Canvas 不具备 HTML 中 CSS 的所有文本转换能力。我建议您应该为每种用途组合适当的技术。使用与 Canvas 甚至 SVG 分层的 HTML,每个都做它最擅长的。
Note also that 'rolling your own'—drawing each character with a custom offset—is going to produce bad results for most fonts, given that there are letter kerning pairs and pixel-aligned font hinting.
另请注意,鉴于存在字母字距调整对和像素对齐字体提示,“滚动您自己的”(使用自定义偏移量绘制每个字符)将对大多数字体产生不良结果。
回答by Yanofsky
You can't set the letter spacing property, but you you can accomplish wider letter spacing in canvas by inserting one of the various white spaces in between every letter in the string. For instance
您无法设置字母间距属性,但您可以通过在字符串中的每个字母之间插入各种空格之一来在画布中实现更宽的字母间距。例如
ctx.font = "3em sheepsans";
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = "rgb(255, 255, 255)";
var ctext = "Blah blah text".split("").join(String.fromCharCode(8202))
ctx.fillText(ctext, 1024 / 2, 768 / 2);
This will insert a hair spacebetween every letter.
这将在每个字母之间插入一个头发空间。
Using 8201 (instead of 8202) will insert the slightly wider thin space
使用 8201(而不是 8202)将插入稍宽的薄空间
For more white space options, see this list of Unicode Spaces
有关更多空白选项,请参阅此 Unicode 空间列表
This method will help you to preserve the font's kerning much more easily than manually positioning each letter, however you wont be able to tighten your letter spacing this way.
与手动定位每个字母相比,此方法将帮助您更轻松地保留字体的字距,但是您将无法以这种方式收紧字母间距。
回答by Simon Sarris
You can't set letter-spacing as a property of the Canvas context.You can only achieve the effect by doing manual spacing, sorry. (As in, drawing each letter manually increasing the x by some pixel amount on each)
您不能将字母间距设置为 Canvas 上下文的属性。您只能通过手动间距来达到效果,抱歉。(如,手动绘制每个字母将 x 增加一些像素量)
For the record, you can set a few text properties by using ctx.font
but letter-spacing is not one of them. The ones you canset are: "font-style font-variant font-weight font-size/line-height font-family"
作为记录,您可以使用设置一些文本属性,ctx.font
但字母间距不是其中之一。您可以设置的是:“字体样式字体变体字体粗细字体大小/行高字体系列”
For instance you can technically write ctx.font = "bold normal normal 12px/normal Verdana"
(or any omission of any of those) and it will parse correctly.
例如,您可以在技术上编写ctx.font = "bold normal normal 12px/normal Verdana"
(或省略其中的任何内容),它会正确解析。
回答by Maria Campbell
Not true. You can add letter-spacing property to the canvas element in css and it works perfectly. No need for complicated workarounds. I just figured it out right now in my canvas project. i.e.: canvas { width: 480px; height: 350px; margin: 30px auto 0; padding: 15px 0 0 0; background: pink; display: block; border: 2px dashed brown; letter-spacing: 0.1em; }
不对。您可以在 css 中为 canvas 元素添加 letter-spacing 属性,它可以完美运行。不需要复杂的解决方法。我现在才在我的画布项目中弄清楚了。即:画布{宽度:480px;高度:350px;边距:30px 自动 0;填充:15px 0 0 0;背景:粉色;显示:块;边框:2px 虚线棕色;字母间距:0.1em;}
回答by Funkodebat
here's some coffeescript that allows you to set kerning to your context like so
这是一些咖啡脚本,允许您像这样将字距调整到您的上下文
tctx = tcanv.getContext('2d')
tctx.kerning = 10
tctx.fillStyle = 'black'
tctx.fillText 'Hello World!', 10, 10
the supporting code is:
支持代码是:
_fillText = CanvasRenderingContext2D::fillText
CanvasRenderingContext2D::fillText = (str, x, y, args...) ->
# no kerning? default behavior
return _fillText.apply this, arguments unless @kerning?
# we need to remember some stuff as we loop
offset = 0
_.each str, (letter) =>
_fillText.apply this, [
letter
x + offset + @kerning
y
].concat args # in case any additional args get sent to fillText at any time
offset += @measureText(letter).width + @kerning
The javascript would be
javascript将是
var _fillText,
__slice = [].slice;
_fillText = CanvasRenderingContext2D.prototype.fillText;
CanvasRenderingContext2D.prototype.fillText = function() {
var args, offset, str, x, y,
_this = this;
str = arguments[0], x = arguments[1], y = arguments[2], args = 4 <= arguments.length ? __slice.call(arguments, 3) : [];
if (this.kerning == null) {
return _fillText.apply(this, arguments);
}
offset = 0;
return _.each(str, function(letter) {
_fillText.apply(_this, [letter, x + offset + _this.kerning, y].concat(args));
offset += _this.measureText(letter).width + _this.kerning;
});
};
回答by James Carlyle-Clarke
To allow for 'letter kerning pairs' and the like, I've written the following. It should take that into account, and rough testing suggests it does. If you have any comments on it then I would point you to my question on the subject (Adding Letter Spacing in HTML Canvas)
为了允许“字母字距调整对”等,我写了以下内容。它应该考虑到这一点,粗略的测试表明确实如此。如果您对此有任何评论,那么我会向您指出我关于该主题的问题(在 HTML Canvas 中添加字母间距)
Basically it uses measureText() to get the width of the whole string, and then removes the first character of the string and measures the width of the remaining string, and uses the difference to calculate the correct positioning - thus taking into account kerning pairs and the like. See the given link for more pseudocode.
基本上它使用 measureText() 来获取整个字符串的宽度,然后删除字符串的第一个字符并测量剩余字符串的宽度,并使用差异来计算正确的定位 - 从而考虑到字距对和类似。有关更多伪代码,请参阅给定链接。
Here's the HTML:
这是 HTML:
<canvas id="Test1" width="800px" height="200px"><p>Your browser does not support canvas.</p></canvas>
Here's the code:
这是代码:
this.fillTextWithSpacing = function(context, text, x, y, spacing)
{
//Start at position (X, Y).
//Measure wAll, the width of the entire string using measureText()
wAll = context.measureText(text).width;
do
{
//Remove the first character from the string
char = text.substr(0, 1);
text = text.substr(1);
//Print the first character at position (X, Y) using fillText()
context.fillText(char, x, y);
//Measure wShorter, the width of the resulting shorter string using measureText().
if (text == "")
wShorter = 0;
else
wShorter = context.measureText(text).width;
//Subtract the width of the shorter string from the width of the entire string, giving the kerned width of the character, wChar = wAll - wShorter
wChar = wAll - wShorter;
//Increment X by wChar + spacing
x += wChar + spacing;
//wAll = wShorter
wAll = wShorter;
//Repeat from step 3
} while (text != "");
}
Code for demo/eyeball test:
演示/眼球测试代码:
element1 = document.getElementById("Test1");
textContext1 = element1.getContext('2d');
textContext1.font = "72px Verdana, sans-serif";
textContext1.textAlign = "left";
textContext1.textBaseline = "top";
textContext1.fillStyle = "#000000";
text = "Welcome to go WAVE";
this.fillTextWithSpacing(textContext1, text, 0, 0, 0);
textContext1.fillText(text, 0, 100);
Ideally I'd throw multiple random strings at it and do a pixel by pixel comparison. I'm also not sure how good Verdana's default kerning is, though I understand it's better than Arial - suggestions on other fonts to try gratefully accepted.
理想情况下,我会向它抛出多个随机字符串并逐个像素地进行比较。我也不确定 Verdana 的默认字距调整有多好,但我知道它比 Arial 更好 - 关于其他字体的建议尝试被感激地接受。
So... so far it looks good. In fact it looks perfect. Still hoping that someone will point out any flaws in the process.
所以……目前看来还不错。事实上,它看起来很完美。仍然希望有人能指出这个过程中的任何缺陷。
In the meantime I will put this here for others to see if they are looking for a solution on this.
同时,我将把它放在这里供其他人看看他们是否正在寻找解决方案。
回答by Praveen Chelumalla
Actually letter spacing concept canvas is not supporting.
实际上字母间距概念画布不支持。
So i used javascript to do this.
所以我用javascript来做到这一点。
var value = $('#sourceText1').val().split("").join(" ");
OR
或者
var sample_text = "Praveen Chelumalla"; var text = sample_text.split("").join(" ");
回答by modnarrandom
I don't know about other people but I have adjusted line spacing by increasing the y value on the text that I am writing. I'm actually splitting a string by spaces and kicking each word down a line inside a loop. The numbers i use are based on the default font. If you use a different font that these numbers may need to be adjusted.
我不知道其他人,但我通过增加我正在写的文本的 y 值来调整行距。我实际上是用空格分割一个字符串并将每个单词踢下一个循环内的一行。我使用的数字基于默认字体。如果您使用不同的字体,这些数字可能需要调整。
// object holding x and y coordinates
var vectors = {'x':{1:100, 2:200}, 'y':{1:0, 2:100}
// replace the first letter of a word
var newtext = YOURSTRING.replace(/^\b[a-z]/g, function(oldtext) {
// return it uppercase
return oldtext.toUpperCase();
});
// split string by spaces
newtext = newtext.split(/\s+/);
// line height
var spacing = 10 ;
// initial adjustment to position
var spaceToAdd = 5;
// for each word in the string draw it based on the coordinates + spacing
for (var c = 0; c < newtext.length; c++) {
ctx.fillText(newtext[c], vectors.x[i], vectors.y[i] - spaceToAdd);
// increment the spacing
spaceToAdd += spacing;
}
回答by Artyom Hachikov
Letter spacing in canvas IS SUPPORTED, I used this
支持画布中的字母间距,我使用了这个
canvas = document.getElementById('canvas');
canvas.style.letterSpacing = '2px';
回答by LaFeteParFete
I use:
我用:
ctx.font = "32px Tahoma";//set font
ctx.scale(0.75,1);//important! the scale
ctx.fillText("LaFeteParFete test text", 2, 274);//draw
ctx.setTransform(1,0,0,1,0,0);//reset transform