How can I get textBaseline="alphabetic" behavior in Kineticjs? -
i'm trying align text in way canvas context textbaseline property set "alphabetic" does. can't same effect 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 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 render text (function expected() { var c = document.getelementbyid("mycanvas"), ctx = c.getcontext("2d"), baseline = 60; ctx.textbaseline = "alphabetic"; // redundant it's 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">
same code on jsfiddle.
i'm aware of this question haven't found right way of calculating offset alphabetic baseline.
the proper "y" position can calculated follows:
y = baseline - fontsize + descent;
where "descent" can obtained using "gettextheight" function this answer
the code below gives pixel perfect results in firefox , decent ones in 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 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; } { $div.remove(); } return result; }; })(); // how render text (function expected() { var c = document.getelementbyid("mycanvas"), ctx = c.getcontext("2d"), baseline = 60; ctx.textbaseline = "alphabetic"; // redundant it's 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">
Comments
Post a Comment