2016-01-20 71 views
0

假设有一个旋转的边界矩形(未对准,以正常轴XY)内的被绘制的文本,并且文本也可以被旋转, 给出的最大宽度的边框,如何选择最佳的字体大小用来画内一个换行文本,在HTML5画布和JavaScript边框的HTML5画布:自动字体大小绘制包裹旋转的文本

我知道方法:measureText()可以测量给出的字体大小的尺寸,但我需要的是相反的:使用已知宽度来获取问题字体大小。

谢谢

回答

4

您不必查找字体大小以使其合适。根据当前的转换规模,字体将平滑地放大和缩小。

你要做的就是measureText找到它textWidth,从context.font属性得到pointSize那么如果你有width,你需要适应,然后找出最小的width/textWidthheight/pointSize的盒子height,你有规模你需要渲染字体。

作为功能

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); 
} 

的参数是

  • CTX是当前上下文提请
  • 文本文本绘制
  • 宽度宽度使文字符合
  • 高度高度与文本适合

返回规模以适应宽度和高度中的文本。

该演示将所有内容整合在一起,并绘制随机框,并用随机文本填充问题。它使字体选择和点大小与字体缩放分开,所以你可以看到它可以适用于任何字体和任何点的大小。

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 x-y), 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 **/

+1

奈斯利高效! :-) – markE

+0

谢谢Blindman67,你的回答非常有帮助,我会在我的代码上试试。非常感谢 –