简体   繁体   English

html5 canvas:绘制的包裹旋转文本的自动字体大小

[英]html5 canvas: auto font size for drawn wrapped rotated text

suppose that there is a text to be drawn inside a rotated bounding rectangle (not aligned to normal axes xy), and that text can be also rotated , given the max width of the bounding box, how to select the best font size to use to draw a wrapped text inside that bounding box in html5 canvas and javascript? 假设在旋转的边界矩形(未与法线轴xy对齐)内绘制文本,并且在给定边界框的最大宽度的情况下, 也可以旋转文本 ,如何选择最佳字体大小以用于在html5 canvas和javascript中的边界框内绘制包装文本

I know that method: measureText () can measure dimensions of give font size, but I need the inverse of that: using a known width to get the problem font size. 我知道该方法: measureText ()可以测量给定字体大小的尺寸,但是我需要相反的方法:使用已知宽度来获取问题字体大小。

thanks 谢谢

You do not have to find the font point size to make it fit. 您不必找到合适的字体大小即可。 The font will smoothly scale up and down according to the current transformation scale. 字体将根据当前转换比例平滑地上下缩放。

All you do is measureText to find its textWidth , get the pointSize from the context.font attribute then if you have the width and height of the box you need to fit then find the minimum of the width / textWidth and height / pointSize and you have the scale that you need to render the font at. 你要做的就是measureText找到它的textWidth ,得到pointSizecontext.font属性,那么如果你有widthheight ,你需要适合再找到最小的盒子的width / textWidthheight / pointSize和你有渲染字体所需的比例。

As a function 作为功​​能

var scale2FitCurrentFont = function(ctx, text, width, height){
    var points, fontWidth;
    points = Number(ctx.font.split("px")[0]); // get current point size
    points += points * 0.2; // As point size does not include hanging tails and
                            // other top and bottom extras add 20% to the height
                            // to accommodate the extra bits  
    var fontWidth = ctx.measureText(text).width;
    // get the max scale that will allow the text to fi the current font
    return Math.min(width / fontWidth, height / points);
}

The arguments are 参数是

  • ctx is current context to draw to ctx是当前要吸引的上下文
  • text the text to draw 文本的文本绘制
  • width the width to fit the text to width宽度以适合文本
  • height the height to fit the text to 高度的高度以适应文本

Returns the scale to fit the text within the width and height. 返回比例以使文本适合宽度和高度。

The demo has it all integrated and it draws random boxes and fills with random text from your question. 该演示将所有功能集成在一起,并绘制随机的框并用您的问题中的随机文本填充。 It keeps the font selection and point size separate from the font scaling so you can see it will work for any font and any point size. 它使字体选择和磅值与字体缩放保持分开,因此您可以看到它适用于任何字体和磅值。

 var demo = function(){ /** fullScreenCanvas.js begin **/ var canvas = (function(){ var canvas = document.getElementById("canv"); if(canvas !== null){ document.body.removeChild(canvas); } // creates a blank image with 2d context canvas = document.createElement("canvas"); canvas.id = "canv"; canvas.width = window.innerWidth; canvas.height = window.innerHeight; canvas.style.position = "absolute"; canvas.style.top = "0px"; canvas.style.left = "0px"; canvas.style.zIndex = 1000; canvas.ctx = canvas.getContext("2d"); document.body.appendChild(canvas); return canvas; })(); var ctx = canvas.ctx; /** fullScreenCanvas.js end **/ /** FrameUpdate.js begin **/ var w = canvas.width; var h = canvas.height; var cw = w / 2; var ch = h / 2; var PI2 = Math.PI * 2; // 360 to save typing var PIh = Math.PI / 2; // 90 // draws a rounded rectangle path function roundedRect(ctx,x, y, w, h, r){ ctx.beginPath(); ctx.arc(x + r, y + r, r, PIh * 2, PIh * 3); ctx.arc(x + w - r, y + r, r, PIh * 3, PI2); ctx.arc(x + w - r, y + h - r, r, 0, PIh); ctx.arc(x + r, y + h - r, r, PIh, PIh * 2); ctx.closePath(); } // random words var question = "Suppose that there is a text to be drawn inside a rotated bounding rectangle (not aligned to normal axes xy), and that text can be also rotated, given the max width of the bounding box, how to select the best font size to use to draw a wrapped text inside that bounding box in html5 canvas and javascript? I know that method: measureText() can measure dimensions of give font size, but I need the inverse of that: using a known width to get the problem font size. thanks."; question = question.split(" "); var getRandomWords= function(){ var wordCount, firstWord, s, i, text; wordCount = Math.floor(rand(4)+1); firstWord = Math.floor(rand(question.length - wordCount)); text = ""; s = ""; for(i = 0; i < wordCount; i++){ text += s + question[i + firstWord]; s = " "; } return text; } // fonts to use?? Not sure if these are all safe for all OS's var fonts = "Arial,Arial Black,Verdanna,Comic Sans MS,Courier New,Lucida Console,Times New Roman".split(","); // creates a random font with random points size in pixels var setRandomFont = function(ctx){ var size, font; size = Math.floor(rand(10, 40)); font = fonts[Math.floor(rand(fonts.length))]; ctx.font = size + "px " + font; } var scale2FitCurrentFont = function(ctx, text, width, height){ var points, fontWidth; var points = Number(ctx.font.split("px")[0]); // get current point size points += points * 0.2; var fontWidth = ctx.measureText(text).width; // get the max scale that will allow the text to fi the current font return Math.min(width / fontWidth, height / points); } var rand = function(min, max){ if(max === undefined){ max = min; min = 0; } return Math.random() * (max - min)+min; } var randomBox = function(ctx){ "use strict"; var width, height, rot, dist, x, y, xx, yy,cx, cy, text, fontScale; // get random box width = rand(40, 400); height = rand(10, width * 0.4); rot = rand(-PIh,PIh); dist = Math.sqrt(width * width + height * height) x = rand(0, ctx.canvas.width - dist); y = rand(0, ctx.canvas.height - dist); xx = Math.cos(rot); yy = Math.sin(rot); ctx.fillStyle = "white"; ctx.strokeStyle = "black"; ctx.lineWidth = 2; // rotate the box ctx.setTransform(xx, yy, -yy, xx, x, y); // draw the box roundedRect(ctx, 0, 0, width, height, Math.min(width / 3, height / 3)); ctx.fill(); ctx.stroke(); // get some random text text = getRandomWords(); // get the scale that will fit the font fontScale = scale2FitCurrentFont(ctx, text, width - textMarginLeftRigth * 2, height - textMarginTopBottom * 2); // get center of rotated box cx = x + width / 2 * xx + height / 2 * -yy; cy = y + width / 2 * yy + height / 2 * xx; // scale the transform xx *= fontScale; yy *= fontScale; // set the font transformation to fit the box ctx.setTransform(xx, yy, -yy, xx, cx, cy); // set up the font render ctx.fillStyle = "Black"; ctx.textAlign = "center"; ctx.textBaseline = "middle" // draw the text to fit the box ctx.fillText(text, 0, 0); } var textMarginLeftRigth = 8; // margin for fitted text in pixels var textMarginTopBottom = 4; // margin for fitted text in pixels var drawBoxEveryFrame = 60; // frames between drawing new box var countDown = 1; // update function will try 60fps but setting will slow this down. function update(){ // restore transform ctx.setTransform(1, 0, 0, 1, 0, 0); // fade clears the screen ctx.fillStyle = "white" ctx.globalAlpha = 1/ (drawBoxEveryFrame * 1.5); ctx.fillRect(0, 0, w, h); // reset the alpha ctx.globalAlpha = 1; // count frames countDown -= 1; if(countDown <= 0){ // if frame count 0 the draw another text box countDown = drawBoxEveryFrame; setRandomFont(ctx); randomBox(ctx); } if(!STOP){ // do until told to stop. requestAnimationFrame(update); }else{ STOP = false; } } update(); } // demo code to restart on resize var STOP = false; // flag to tell demo app to stop function resizeEvent(){ var waitForStopped = function(){ if(!STOP){ // wait for stop to return to false demo(); return; } setTimeout(waitForStopped,200); } STOP = true; setTimeout(waitForStopped,100); } window.addEventListener("resize",resizeEvent); demo(); /** FrameUpdate.js end **/ 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM