skip to Main Content

Given a

<div
  lang="en"
  style="
    overflow-wrap: word-break;
    hyphens: auto;
    width: 8.6em;
    background-color: highlight;
    color: highlightText;
    font-size: 20px;
  ">
    This is a text that is long enough
    to cause a line break if set so.
    By using words like
    "incomprehensibilities",
    we can demonstrate word breaks.
</div>

I would like to access the formatted text with hyphenations with JavaScript to get a string similar to:

"This is a text that is long enough to cause a line break if set so. By using words like "incomprehensibilit-ies", we can demon-strate word breaks.".

N.B. hyphens in incomprehensibilit-ies and demon-strate.

Is this possible?

The use case is that I need a way to break and hyphenate text in a <text> element of an SVG by only using SVG elements.

2

Answers


  1. Perhaps try with this

    const wrapText = (context, text, x, y, maxWidth, lineHeight) => {
      const words = text.split(' ');
      let line = '';
    
      words.forEach(word => {
        const testLine = line + word + ' ';
        const {
          width: testWidth
        } = context.measureText(testLine);
    
        if (testWidth > maxWidth && line !== '') {
          context.fillText(line, x, y);
          line = word + ' ';
          y += lineHeight;
        } else {
          line = testLine;
        }
      });
    
      context.fillText(line, x, y); // Render the last line
    };
    
    const canvas = document.getElementById('myCanvas');
    const context = canvas.getContext('2d');
    const maxWidth = 400;
    const lineHeight = 25;
    const x = (canvas.width - maxWidth) / 2;
    const y = 60;
    const text = document.getElementById('e83v8').textContent;
    
    context.font = '16pt Calibri';
    context.fillStyle = '#333';
    wrapText(context, text, x, y, maxWidth, lineHeight);
    <div id="e83v8" style="width: 86px; background-color: red; font-size: 10px; overflow-wrap: word-break; hyphens: auto;">This is a text that is long enough to cause a line break if set so. By using words like "incomprehensibilities", we can demonstrate word breaks.</div>
    
    <canvas id="myCanvas" width="500" height="200"></canvas>
    Login or Signup to reply.
  2. Far from perfect. This one:

    • wraps each word in a <span>
    • calculates by offsetHeight if a SPAN spans multiple lines
    • of so it found a hyphened word
    • it then removes each last character from the <span>
      to find when the word wrapped to a new line
    <style>
      .hyphen { background: pink }
      .remainder { background: lightblue }
    </style>
    
    <process-text lang="en" style="display:inline-block;
             overflow-wrap: word-break; hyphens: auto; zoom:1.2; width: 7em">
      By using words like
      "incomprehensibilities",
      we can demonstrate word breaks.
    </process-text>
    
    <script>
      customElements.define('process-text', class extends HTMLElement {
        connectedCallback() {
          setTimeout(() => {
            let words = this.innerHTML.trim().split(/(W+)/);
            let spanned = words.map(w => `<span>${w}</span>`).join('');
            this.innerHTML = spanned;
            let spans = [...this.querySelectorAll("span")];
            let defaultHeight = spans[0].offsetHeight;
            let hyphend = spans.map(span => {
              let hyphen = span.offsetHeight > defaultHeight;
              console.assert(span.offsetHeight == defaultHeight, span.innerText, span.offsetWidth);
              span.classList.toggle("hyphen", hyphen);
              if (hyphen) {
                let saved = span.innerText;
                while (span.innerText && span.offsetHeight > defaultHeight) {
                  span.innerText = span.innerText.slice(0, -1);
                }
                let remainder = document.createElement("span");
                remainder.innerText = saved.replace(span.innerText, "");
                remainder.classList.add("remainder");
                span.after(remainder);
              }
            })
            console.log(this.querySelectorAll("span").length, "<SPAN> created" );
          }) //setTimeout to read innerHTML
        } // connectedCallback
      });
    </script>

    The error is "demonstrate" fits when shortened to "demonstr" "ate"

    Needs some more JS voodoo

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search