Calculate letter size in javascript

2019-07-04 03:14发布

问题:

I need to calculate the exact size of the letter in javascript. The letter can have different font-size or font-family attributes, etc.

I tried to use div element for this, but this method gives only the size of the div, not letter.

<div style="display: inline; background-color: yellow; font-size: 53px; line-height:32px">A</div>

Does anybody know how to solve this issue?

回答1:

This is basically not possible for the general case. Font kerning will result in variable "widths" of letters depending on the operating system, browser, etc etc, and based on which letters are next to each other. Font substitution may happen if the os+browser don't have the font you specify.

Perhaps re-asking the question with the higher-level goal you're shooting for might result in proposed other approaches to your problem that might be more fruitful?



回答2:

@Irongaze.com is right that your fonts, depending on conditions, will have varying actual sizes.

If you want to calibrate for a specific letter, I believe element.getBoundingClientRect() will give you useful coordinates. Be sure to fully reset the container wich you are using as a control box. Mind that on different systems you might get different results.

jsFiddle

Please note that this will not give you the size of the actual visible part of the letter, but the size of the container it determines. line-height for example, will not change the actual letter size, but it will affect other letters' positioning. Be aware of that.

It will help us if you describe the problem you are trying to solve. There might be better solutions.



回答3:

As others have mentioned, this isn't possible to measure directly. But you can get at it in a more roundabout way: draw the letter onto a canvas and determine which pixels are filled in.

Here's a demo that does this. The meat is this function:

/**
 * Draws a letter in the given font to an off-screen canvas and returns its
 * size as a {w, h, descenderH} object.
 * Results are cached.
 */
function measureLetter(letter, fontStyle) {
  var cacheKey = letter + ' ' + fontStyle;
  var cache = measureLetter.cache;
  if (!cache) {
    measureLetter.cache = cache = {};
  }
  var v = cache[cacheKey];
  if (v) return v;

  // Create a reasonably large off-screen <canvas>
  var cnv = document.createElement('canvas');
  cnv.width = '200';
  cnv.height = '200';

  // Draw the letter
  var ctx = cnv.getContext('2d');
  ctx.fillStyle = 'black';
  ctx.font = fontStyle;
  ctx.fillText(letter, 0.5, 100.5);

  // See which pixels have been filled
  var px = ctx.getImageData(0, 0, 200, 200).data;
  var minX = 200, minY = 200, maxX = 0, maxY = 0;
  var nonZero = 0;
  for (var x = 0; x < 200; x++) {
    for (var y = 0; y < 200; y++) {
      var i = 4 * (x + 200 * y);
      var c = px[i] + px[i + 1] + px[i + 2] + px[i + 3];
      if (c === 0) continue;
      nonZero++;
      minX = Math.min(x, minX);
      minY = Math.min(y, minY);
      maxX = Math.max(x, maxX);
      maxY = Math.max(y, maxY);
    }
  }

  var o = {w: maxX - minX, h: maxY - minY, descenderH: maxY - 100};
  cache[cacheKey] = o;
  return o;
}

Note that this is sensitive to antialiasing—the results might be off by a pixel.