-1

I am trying to solve a problem where i need to know the length of the path of the text typed by the user. Example a user Types "Hello World" i need to check what will be the length of the path of Hello world when typed in a certain font with a certain font size(in pt).

The length that i will get i need to convert it into meters to i can use it in real world to build the Neon.

How should i approach the problem are there any libraries that can help me do this?

Thanks

Edi 0
  • 212
  • 5
  • 22
  • 1 pt is equal to 1/72 of an inch you should be able to calculate the width directly – DCR Jul 23 '20 at 00:11
  • Your question is ambiguous. Do you want to know the length along the base line, from first letter to last, or the length of a stroke a quill would have to draw when writing, or the length of the complete outline around each glyph? – ccprog Jul 23 '20 at 00:13
  • @ccprog I need to know the path of each glyph so i know how much neon tube would be used to construct it. – Edi 0 Jul 23 '20 at 00:41
  • @Edi0 thanks for that clarification. The snippet I did below just demos the canvas.measureText() api to measure line length, not the full length of tracing every letter. It sounds like you'll need a much more sophisticated algorithm. Best of luck. – EvanMorrison Jul 23 '20 at 01:13
  • @Edi0 to follow up on that, you may want to investigate a program like Adobe Illustrator. I'm not certain, but I believe it is capable of converting font text into vector paths and then giving a measure of the path length. – EvanMorrison Jul 23 '20 at 01:32
  • Not that simple its using https://svelte.dev/ all the code is minified. They are using https://opentype.js.org/ to do the calculations but i don't fully understand this library – Edi 0 Jul 23 '20 at 01:52

2 Answers2

1

I don't have any specific libraries to recommend, but here is a snippet of how you might go about doing what you want. The conversion from pixels to centimeters is approximate here, it's just a demo after all.

const getRuler = element => {
  const ctx = document.createElement('canvas').getContext('2d');
  const style = window.getComputedStyle(element);
  const fontSize = style.getPropertyValue('font-size');
  const fontFamily = style.getPropertyValue('font-family');
  ctx.font = `${fontSize} ${fontFamily}`;
  return ctx;
}

const element = document.querySelector('#my-element-with-text');

function updateLength(e) {
  const element = e.target
  const text = element.innerText;
  const ruler = getRuler(element);
  const length = ruler.measureText(text).width;

  const result = document.querySelector('#length');

  result.innerText = (length * 0.026458).toFixed(4) + ' centimeters';
}

element.addEventListener('keyup', updateLength);
body {
  height: 100%;
  width: 100%;
  margin: 0;
}

main {
  margin-top: 15vh;
  margin-left: 10vw;
  width: 85%;
}

#my-element-with-text {
  border: 1px solid black;
  border-radius: 3px;
  height: 2em;
  font-size: 5vw;
  width: fit-content;
  min-width: 200px;
  line-height: 2em;
  padding: 0 12px;
  font-family: 'Helvetica Neue', sans-serif;
}
<main>
  <div>Enter text here</div>
  <div id='my-element-with-text' contenteditable='true'></div>
  <div id='length'></div>
</main>
EvanMorrison
  • 1,212
  • 8
  • 13
  • Well, length is in pixels, but since OP mentions converting to meters I thought for fun I'd have it show centimeters. I just googled for the conversion factor, I don't vouch for it's accuracy in real world terms. – EvanMorrison Jul 23 '20 at 00:56
  • How should i use it to take the font-size in pts and then converting it to meters? What i am trying to achive is create this app that asks people to type the world and i calculate the length of that word in meters. Then we give them the exact cost as we know how many meters of neon tube will be used. – Edi 0 Jul 23 '20 at 00:58
  • 1
    @RenevanderLende No, 1 inch is only 96px on your screen, on mine it is 103px. This conversion is device-dependent. In addition, I think this answer fails to address what was asked, The question was about tracing along each letter with a neon tube. The length computed here gives only the distance from the start to the end of the text. – ccprog Jul 23 '20 at 01:12
0

This is a multistep process, and for now I don't have all the answers.

  1. Load the font to use as a webfont. Normally, this means you go to a provider like Google fonts and get a link to a stylesheet that will do the work for you, including deciding which font format your browser will understand. But in this case, you need the full address of the final font file. If you provide the font file on your own server, this would be trivial.

  2. Since you ultimately need the file content itself, the best strategy is probably to load the font file via an AJAX request and then both insert it into the document font resources and to load it also into a special parser that gives access to the font outline data. This could be opentype.js - note it is a major piece of software with 162kB minified. As soon as the font is loaded, you can start to look for the text you want to measure:

     window.fetch(fontUrl).then(response => {
         // read response into an ArrayBuffer
         return response.arrayBuffer();
     }).then(buffer => {
         // load into parser
         const parsedFont = opentype.parse(buffer);
         // load into browser resources, family is the name for CSS reference
         const fontFace = new FontFace(family, buffer);
         document.fonts.add(fontFace);
         // add an event listener to your text input
         document.querySelector('#textToMeasure').addEventListener('change', event => {
             textToOutline(parsedFont, event.target.value);
         });
     });
    
  3. Each time the text input changes, you now render that text to an SVG path. For that, you need to have an (invisible) SVG snippet in your page:

     <svg width="0px" height="0px"><path id="outlinePath" d="" /></svg>
    

    You get the path data by providing the text and the font size to the font object and then set them for your SVG <path>:

     function textToOutline (font, text) {
         // size means font size in pixels
         const pathData = font.getPath(text, 0, 0, size).toPathData(4);
         // write to path
         const path = document.querySelector('#outlinePath');
         path.setAttribute('d', pathData);
    
         measureOutline(path);
     }
    
  4. Now the text outline is in a format that the browser can measure with its own API.

     function measureOutline (path) {
         // length in pixels
         const pathLength = path.getTotalLength();
         // factor would be the conversion factor to your intended unit,
         // and unit the unit name
         document.querySelector('#lengthResult').innerText = (pathLength * factor) + unit;
     }
    
ccprog
  • 20,308
  • 4
  • 27
  • 44