如何在 Kineticjs 中获得 textBaseline="alphabetic" 行为?
How can I get textBaseline="alphabetic" behavior in Kineticjs?
我正在尝试以 canvas context textBaseline 属性 设置为 "alphabetic" 的方式对齐文本。我无法使用 kineticjs 获得完全相同的效果。
var letters = [
{ symbol: "A", x: 3.0, size: 20 },
{ symbol: "B", x: 36.3, size: 30 },
{ symbol: "C", x: 86.3, size: 40 },
{ symbol: "D", x: 158.6, size: 50 },
{ symbol: "E", x: 248.9, size: 40 },
{ symbol: "F", x: 315.5, size: 30 },
{ symbol: "G", x: 361.3, size: 20 } ];
// How kineticjs renders the text
(function actual() {
var stage = new Kinetic.Stage({ container: "mycontainer", width: 400, height: 100 }),
layer = new Kinetic.Layer(),
baseline = 60;
letters.forEach(function(letter) {
layer.add(new Kinetic.Text({
x: letter.x,
y: baseline - letter.size,
text: letter.symbol,
fontSize: letter.size,
fill: 'black',
}));
});
// Baseline visualization
layer.add(new Kinetic.Line({
points: [0, baseline, 400, baseline ],
stroke: "red"
}));
stage.add(layer);
})();
// How I would like it to render the text
(function expected() {
var c = document.getElementById("mycanvas"),
ctx = c.getContext("2d"),
baseline = 60;
ctx.textBaseline = "alphabetic"; // redundant as it's actually default behaviour
letters.forEach(function(letter) {
ctx.font = letter.size + "px Arial";
ctx.fillText(letter.symbol, letter.x, baseline);
});
// Baseline visualization
ctx.strokeStyle = "red";
ctx.moveTo(0, baseline);
ctx.lineTo(400, baseline);
ctx.stroke();
})();
<script src="https://cdn.lukej.me/kineticjs/5.1.0/kinetic.min.js"></script>
<div id="mycontainer"></div>
<canvas id="mycanvas" width="400" height="150" style="position: absolute; left: 10px; top: 100px">
jsfiddle 上的相同代码。
我知道 this question 但是我还没有找到计算字母基线偏移量的正确方法。
正确的"y"位置可以计算如下:
y = baseline - fontSize + descent;
其中 "descent" 可以使用来自 this answer
的 "getTextHeight" 函数获得
下面的代码在 Firefox 中给出了像素完美的结果,在 Chrome 中给出了不错的结果。
var letters = [
{ symbol: "A", x: 3.0, size: 20 },
{ symbol: "B", x: 36.3, size: 30 },
{ symbol: "C", x: 86.3, size: 40 },
{ symbol: "D", x: 158.6, size: 50 },
{ symbol: "E", x: 248.9, size: 40 },
{ symbol: "F", x: 315.5, size: 30 },
{ symbol: "G", x: 361.3, size: 20 } ];
// How kineticjs renders the text
(function actual() {
var stage = new Kinetic.Stage({ container: "mycontainer", width: 400, height: 100 }),
layer = new Kinetic.Layer(),
baseline = 60;
letters.forEach(function(letter) {
layer.add(new Kinetic.Text({
x: letter.x,
y: baseline - letter.size + getMetrics("Arial", letter.size).descent,
text: letter.symbol,
fontSize: letter.size,
fill: 'black',
}));
});
// Baseline visualization
layer.add(new Kinetic.Line({
points: [0, baseline, 400, baseline ],
stroke: "red"
}));
stage.add(layer);
function getMetrics(fontFamily, fontSize) {
var $text = $("<span>Hg</span>").css({
"fontFamily": fontFamily,
"font-size": fontSize + "px",
"line-height": "normal"
});
var $block = $("<div></div>").css({
"display": "inline-block",
"width": "1px",
"height": "0px"
});
var $div = $("<div></div>");
$div.append($text, $block);
$("body").append($div);
try {
var result = {};
$block.css({ verticalAlign: "baseline" });
result.ascent = $block.offset().top - $text.offset().top;
$block.css({ verticalAlign: "bottom" });
result.height = $block.offset().top - $text.offset().top;
result.descent = result.height - result.ascent;
} finally {
$div.remove();
}
return result;
};
})();
// How I would like it to render the text
(function expected() {
var c = document.getElementById("mycanvas"),
ctx = c.getContext("2d"),
baseline = 60;
ctx.textBaseline = "alphabetic"; // redundant as it's actually default behaviour
letters.forEach(function(letter) {
ctx.font = letter.size + "px Arial";
ctx.fillText(letter.symbol, letter.x, baseline);
});
// Baseline visualization
ctx.strokeStyle = "red";
ctx.moveTo(0, baseline);
ctx.lineTo(400, baseline);
ctx.stroke();
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.lukej.me/kineticjs/5.1.0/kinetic.min.js"></script>
<div id="mycontainer"></div>
<canvas id="mycanvas" width="400" height="150" style="position: absolute; left: 10px; top: 100px">
我正在尝试以 canvas context textBaseline 属性 设置为 "alphabetic" 的方式对齐文本。我无法使用 kineticjs 获得完全相同的效果。
var letters = [
{ symbol: "A", x: 3.0, size: 20 },
{ symbol: "B", x: 36.3, size: 30 },
{ symbol: "C", x: 86.3, size: 40 },
{ symbol: "D", x: 158.6, size: 50 },
{ symbol: "E", x: 248.9, size: 40 },
{ symbol: "F", x: 315.5, size: 30 },
{ symbol: "G", x: 361.3, size: 20 } ];
// How kineticjs renders the text
(function actual() {
var stage = new Kinetic.Stage({ container: "mycontainer", width: 400, height: 100 }),
layer = new Kinetic.Layer(),
baseline = 60;
letters.forEach(function(letter) {
layer.add(new Kinetic.Text({
x: letter.x,
y: baseline - letter.size,
text: letter.symbol,
fontSize: letter.size,
fill: 'black',
}));
});
// Baseline visualization
layer.add(new Kinetic.Line({
points: [0, baseline, 400, baseline ],
stroke: "red"
}));
stage.add(layer);
})();
// How I would like it to render the text
(function expected() {
var c = document.getElementById("mycanvas"),
ctx = c.getContext("2d"),
baseline = 60;
ctx.textBaseline = "alphabetic"; // redundant as it's actually default behaviour
letters.forEach(function(letter) {
ctx.font = letter.size + "px Arial";
ctx.fillText(letter.symbol, letter.x, baseline);
});
// Baseline visualization
ctx.strokeStyle = "red";
ctx.moveTo(0, baseline);
ctx.lineTo(400, baseline);
ctx.stroke();
})();
<script src="https://cdn.lukej.me/kineticjs/5.1.0/kinetic.min.js"></script>
<div id="mycontainer"></div>
<canvas id="mycanvas" width="400" height="150" style="position: absolute; left: 10px; top: 100px">
jsfiddle 上的相同代码。
我知道 this question 但是我还没有找到计算字母基线偏移量的正确方法。
正确的"y"位置可以计算如下:
y = baseline - fontSize + descent;
其中 "descent" 可以使用来自 this answer
的 "getTextHeight" 函数获得下面的代码在 Firefox 中给出了像素完美的结果,在 Chrome 中给出了不错的结果。
var letters = [
{ symbol: "A", x: 3.0, size: 20 },
{ symbol: "B", x: 36.3, size: 30 },
{ symbol: "C", x: 86.3, size: 40 },
{ symbol: "D", x: 158.6, size: 50 },
{ symbol: "E", x: 248.9, size: 40 },
{ symbol: "F", x: 315.5, size: 30 },
{ symbol: "G", x: 361.3, size: 20 } ];
// How kineticjs renders the text
(function actual() {
var stage = new Kinetic.Stage({ container: "mycontainer", width: 400, height: 100 }),
layer = new Kinetic.Layer(),
baseline = 60;
letters.forEach(function(letter) {
layer.add(new Kinetic.Text({
x: letter.x,
y: baseline - letter.size + getMetrics("Arial", letter.size).descent,
text: letter.symbol,
fontSize: letter.size,
fill: 'black',
}));
});
// Baseline visualization
layer.add(new Kinetic.Line({
points: [0, baseline, 400, baseline ],
stroke: "red"
}));
stage.add(layer);
function getMetrics(fontFamily, fontSize) {
var $text = $("<span>Hg</span>").css({
"fontFamily": fontFamily,
"font-size": fontSize + "px",
"line-height": "normal"
});
var $block = $("<div></div>").css({
"display": "inline-block",
"width": "1px",
"height": "0px"
});
var $div = $("<div></div>");
$div.append($text, $block);
$("body").append($div);
try {
var result = {};
$block.css({ verticalAlign: "baseline" });
result.ascent = $block.offset().top - $text.offset().top;
$block.css({ verticalAlign: "bottom" });
result.height = $block.offset().top - $text.offset().top;
result.descent = result.height - result.ascent;
} finally {
$div.remove();
}
return result;
};
})();
// How I would like it to render the text
(function expected() {
var c = document.getElementById("mycanvas"),
ctx = c.getContext("2d"),
baseline = 60;
ctx.textBaseline = "alphabetic"; // redundant as it's actually default behaviour
letters.forEach(function(letter) {
ctx.font = letter.size + "px Arial";
ctx.fillText(letter.symbol, letter.x, baseline);
});
// Baseline visualization
ctx.strokeStyle = "red";
ctx.moveTo(0, baseline);
ctx.lineTo(400, baseline);
ctx.stroke();
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdn.lukej.me/kineticjs/5.1.0/kinetic.min.js"></script>
<div id="mycontainer"></div>
<canvas id="mycanvas" width="400" height="150" style="position: absolute; left: 10px; top: 100px">