Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript: calculating number of columns of a dynamically sized textarea

I've got an HTML textarea whose width is set to 100% of the browser window, using CSS.

How can I calculate how many columns of text fit within the textarea?

like image 872
jes5199 Avatar asked Jul 19 '09 07:07

jes5199


1 Answers

. @jes5199 I am writing to you from the future. I am roughly 11 years ahead of you and I come with news. Perhaps the best news I have is directly related to your question: it is entirely possible to calculate the cols in a text area. The second piece of news, is that I can rapidly demonstrate how to count a <textarea />'s columns with some handy web prototyping tools. The final piece of news I can share, is that you should absolutely without a doubt invest in Facebook, because I am going to use one of their magic javascript tools to quickly demonstrate how you can solve this problem. We have no idea how it works. It will be a few years before you'll enjoy such magic, but let's take a look at what the future has in store.

I have created a small CodeSandbox application that will calculate the number of columns in a text area here: https://codesandbox.io/s/stack-textarea-width-dkwij

The application depends on this function that performs the calculation you are looking for:

/**
 * calTextAreaCols -- function
 * @param {string} divId The element id of the `<textarea />` that requires measuring.
 * @param {string} font The font that is used in the targeted `<textarea />`.
 * @return {number} The number of characters / columns that fit within the width of the `<textarea />`
 */
export default function calcTextAreaCols(divId, font) {
  // get div font size; from: https://stackoverflow.com/a/15195345
  var element = document.getElementById(divId);
  var style = window
    .getComputedStyle(element, null)
    .getPropertyValue("font-size");
  var fontSize = parseFloat(style) + "px";

  // prepare environment to figure out row maximum; from: https://stackoverflow.com/a/21015393
  var canvas =
    calcTextAreaCols.canvas ||
    (calcTextAreaCols.canvas = document.createElement("canvas"));
  var context = canvas.getContext("2d");
  context.font = fontSize + " " + font;

  // <textarea> offsetWidth, minus border and padding
  var rawWidth = element.offsetWidth;
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("border-left-width")
  );
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("border-right-width")
  );
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("padding-left")
  );
  rawWidth -= parseInt(
    getComputedStyle(element, null).getPropertyValue("padding-right")
  );

  // <textarea> width, divided by the width of the 'a' character
  rawMeasure = rawWidth / context.measureText("a").width;

  // round down
  var measure = Math.floor(rawMeasure);

  return measure;
}

Essentially this function will use a <canvas> element to determine how many characters can fit within the width of your <textarea /> element.

In my demo above there are some apparent flaws that I will note, but I leave it in your trusty hands to go from here:

  1. This calculation works only if the font styled to the <textarea /> is uniform, like monospace. If the characters are different widths, then that needs to be accounted for with some additional code.
  2. In the simple React App I created, you will see that the setTextAreaCols hook is only called on re-render and when the user inputs new information into the <textarea /> but not necessarily when the element is resized.
like image 118
Harley Lang Avatar answered Nov 13 '22 04:11

Harley Lang