Home > Software design >  Get row count of a string inside a div
Get row count of a string inside a div

Time:12-31

I have a div tag with dynamic text value and I want to find how to calculate the number of rows that the string spreads out to according to the font size and the div width

For example:

div {
 width: 15px
 fontSize: 12px
 overflow: hidden
 display: block
 overflow-wrap: break-word
}

and the string is: "abcdefghijk"

the result in the UI will be:

first row- "abc" second row- "defg" third row- "hijk"

So expected calculation value should be 3 (3 rows).

Is it possible to calculate that?

http://jsfiddle.net/b6upgdqz/15/

CodePudding user response:

I guess you would have to explicit also the line-height and then divide the total height of the containing div by the line-height you set...

const input = document.getElementById("text");
const container = document.getElementById("container");
const rows = document.getElementById("rows");

input.addEventListener("input", function handleInputChange(event) {
  updateRowsCount(event.currentTarget.value);
});

function updateRowsCount(text) {
  writeText(text);
  computeRows(container);
}

function writeText(text) {
  container.innerHTML = text;
}

function computeRows(container) {
  const style = window.getComputedStyle(container);
  
  const containerHeight = parseFloat(style.height);
  const lineHeight = parseFloat(style.lineHeight);
  
  const rowsCount = Math.ceil(containerHeight / lineHeight);
  
  rows.innerHTML = rowsCount;
}

updateRowsCount(input.value);
#sample {
  display: flex;
  align-items: flex-start;
}

#sample > * {
  margin-right: 2rem;
}

#container {
  width: 15px;
  font-size: 12px;
  line-height: 1.2;
  overflow: hidden;
  display: block;
  overflow-wrap: break-word;
  
  background: pink;
}
<div id="sample">
  <input id="text" value="abcdefghijkl" />
  <div id="container"></div>
  <div id="rows"></div>
</div>

CodePudding user response:

Working Demo: https://dojo.telerik.com/EzEjucOF/5

var calculateLineCount = function (element) {
    var lineHeightBefore = element.css("line-height"),
        boxSizing = element.css("box-sizing"),
        height,
        lineCount;

    // Force the line height to a known value
    element.css("line-height", "1px");

    // Take a snapshot of the height
    height = parseFloat(element.css("height"));

    // Reset the line height
    element.css("line-height", lineHeightBefore);

    if (boxSizing == "border-box") {
        // With "border-box", padding cuts into the content, so we have to subtract
        // it out
        var paddingTop = parseFloat(element.css("padding-top")),
            paddingBottom = parseFloat(element.css("padding-bottom"));

        height -= (paddingTop   paddingBottom);
    }

    // The height is the line count
    lineCount = height;

    return lineCount;
}

$("#lineCount").html("Total number(s) of line : "   calculateLineCount($(".divwrap")));
div {
  width: 22px;
  font-size: 12px;
  overflow: hidden;
  display: block;
  overflow-wrap: break-word;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div >
    abcdefghijk
</div>

<h2 id="lineCount"></h2>

CodePudding user response:

You can get the bounding boxes for each line through Range#getClientRects().

If your #container contains further markup like <div>s etc. The bounding boxes for these are also added to the list and need to be filtered out.

const input = document.getElementById("text");
const container = document.getElementById("container");
const rows = document.getElementById("rows");

input.addEventListener("input", function handleInputChange(event) {
  updateRowsCount(event.currentTarget.value);
});


function updateRowsCount(text) {
  container.innerHTML = text;
  const range = document.createRange();
  range.selectNodeContents(container);
  
  let rects = range.getClientRects();
  // deal with markup;
  rects = [...rects]
    // sort them by vertical position, leafnodes before their parents.
    .sort((a, b) => a.bottom - b.bottom || b.top - a.top)
    // remove the bounding boxes for nested markup; in this case, the <p>
    .filter((v, i, a) => !i || v.top >= a[i - 1].bottom);
  
  const rowsCount = rects.length;
  
  rows.innerHTML = rowsCount;
}

updateRowsCount(input.value);
#sample {
  display: flex;
  align-items: flex-start;
}

#sample > * {
  margin-right: 2rem;
}

#container {
  width: 15px;
  font-size: 12px;
  line-height: 1.2;
  overflow: hidden;
  display: block;
  overflow-wrap: break-word;
  
  background: pink;
}
<div id="sample">
  <input id="text" value="ab<p>cdefghij</p>kl" />
  <div id="container"></div>
  <div id="rows"></div>
</div>

  • Related