7

Is it possible to find the position of the last visible word of a text(overflow:hidden) shown in a small div?

For example:

<div style="height: 50px; width: 50px; overflow: hidden;">
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor 
invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et 
accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet.
</div>

How to calculate the position of the last visible Word in the div container? I like to fill the whole div133!

Xyz
  • 5,955
  • 5
  • 40
  • 58
Pek
  • 121
  • 1
  • 7

6 Answers6

6

JSFiddle here: http://jsfiddle.net/SmokeyPHP/NQLcc/1/

HTML:

<div id="txt">
Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor 
invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et 
accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata
sanctus est Lorem ipsum dolor sit amet.
</div>

CSS:

#txt {
    width: 75px;
    height: 75px;
    border: 1px solid #F00;
    overflow: hidden;
}

JS:

var cntnr = $("#txt");
cntnr.html('<span>'+cntnr.html().replace(/ /g,'</span> <span>')+'</span>')
var words = Array.prototype.slice.call(cntnr.find("span"),0).reverse();
var lastw = null;
for(var i=0,c=words.length;i<c;i++)
{
    var w = $(words[i]);
    var wbot = w.height() + w.offset().top;
    var wleft = w.offset().left;
    var wright = wleft+w.width();
    if(wbot <= cntnr.height() && wleft <= cntnr.width() && wright <= cntnr.width())
    {
        lastw = w.text();
        break;
    }
}
cntnr.html(cntnr.text());
alert(lastw);

The JS could probably be shortened, but I've left it as I was writing & thinking at the same time... In essence, you wrap all words in a span, then loop backwards through the spans, see if their bounds fall within the container, and as soon as we find a span that does sit inside the container's boundaries, break out of the loop and return that word, after returning the text back to plain text (removing the temporary spans).

MDEV
  • 10,730
  • 2
  • 33
  • 49
  • This is a very clever solution. – BananaNeil Feb 09 '15 at 23:38
  • This solution is great and I'm using it, but I'd like to note that if your container element isn't positioned at the top of the page you'd have to calculate the container edges based on it's offset + width/height, then compare the word position vs the container edges. – besseddrest Oct 16 '19 at 20:50
2

In addition to @SmokeyPhp answer:

First of all, that was a great answer that helped me a lot, but there were some mistakes in the condition there.

Second of all, I'm working with jqlite library instead of jQuery, so that answer was also very helpful in that area (all the methods he used were part of the jqlite library).

In addition to detecting the last visible word in a span or a div, my function is also replacing the rest of the text with "...".

I'm posting the code I'm using, basically the code @SmokeyPhp posted, but fixed where needed, and I hope others will benefit from it:

function dotdotdot(containersToDotdotdot) {
    function dotdotdotContainers(containers) {
        for (var i = 0; i < containers.length; i++) {
            var cntnr = $jq(containers[i]);
            cntnr.html('<span>' + cntnr.html().replace(/ /g,'</span> <span>') + '</span>');
            var words = Array.prototype.slice.call(cntnr.find("span"), 0).reverse();
            var lastw = null;

            for (var j = 0; j < words.length; j++) {
                var w = $jq(words[j]);
                var wbot = w.height() + w.offset().top;
                var wleft = w.offset().left;
                var wright = wleft + w.width();

                if (wbot <= (cntnr.offset().top + cntnr.height()) && wleft >= (cntnr.offset().left) && wright <= (cntnr.offset().left + cntnr.width())) {
                    lastw = words.length - j - 1;
                    break;
                }
            }

            cntnr.html(lastw === null || lastw === (words.length - 1) ? cntnr.text() : (cntnr.text().split(' ').slice(0, lastw).join(' ') + '...'));
        }
    }

    if (containersToDotdotdot instanceof Array) {
        for (var i = 0; i < containersToDotdotdot.length; i++) {
            dotdotdotContainers($jq(containersToDotdotdot[i]));
        }
    } else {
        dotdotdotContainers($jq(containersToDotdotdot));
    }
}

As you can see, my dotdotdot function can get an array of classes/ids to dotdotdot, or a single class/id.

The $jq is the jqlite replacement for jQuery's $.

Thanks @SmokeyPhp, I looked for a long time for a method that does not require jQuery to dotdotdot text, and your method is fantastic.

Matansh
  • 764
  • 4
  • 13
1

Working DEMO

Borrowed an answer from here and tweaked it a bit.

function countVisibleCharacters(element) {
    var text = element.firstChild.nodeValue;
    var r = 0;

    element.removeChild(element.firstChild);

    for(var i = 0; i < text.length; i++) {
        var newNode = document.createElement('span');
        newNode.appendChild(document.createTextNode(text.charAt(i)));
        element.appendChild(newNode);

        if(newNode.offsetLeft < element.offsetWidth) {
            r++;
        }
    }

    return r;
}

var c = countVisibleCharacters(document.getElementsByTagName('div')[0]);

var str = document.getElementById('myDiv');
str = str.textContent;
str = str.substring(0, c);
str = str.substr(str.trim().lastIndexOf(" ")+1);
alert(str);
Community
  • 1
  • 1
Gurpreet Singh
  • 20,907
  • 5
  • 44
  • 60
1

One possible solution:

var $div = $('div'),
    size = [$div.width(), $div.height()],
    words = $.trim($div.text()).split(/\s+/),
    word;

for (var i = 0, len = words.length; i < len; i++) {
    var $clone = $div.clone().text(words.join(' ')).insertAfter($div);
    $clone.contents().wrap('<span />');
    var $child = $clone.children('span');

    if ($child.width() <= size[0] && $child.height() <= size[1]) {
        word = words.pop();
        $clone.remove();
        break;
    }
    words.pop();
    $clone.remove();
}

console.log(word);

DEMO: http://jsfiddle.net/bcn78/

VisioN
  • 143,310
  • 32
  • 282
  • 281
1

Yes, it is possible to detect the last word that is being displayed using Javascript.

Unfortunately I do not have the time to write the code that can do this, however, I will explain the algorithm.

If you have a box that is 50x50 and you want to detect what the last visible word is then do the following:

  1. Create a div offscreen that has 50 pixels of width but no restriction on height. For this demonstration, we'll call this div the clonedDiv.
  2. Get the string that was in the original div and insert the first word of it inside the clonedDiv.
  3. Check the height of the clonedDiv.
  4. Apply this logic: If it is <= 50px then add the next word and try again. If it is greater then 50px tall, then that is the word causing the overflow to happen. Your answer will be the PREVIOUS word.

Please note that the algorithm above uses a brute force method of finding the word. The algorithm is basically adding one word at a time until it finds the word that causes the overflow. You can improve this by using a variation of the binary search algorithm which will improve the algorithm from being O(n) to O(log(n)).

richardaday
  • 2,814
  • 1
  • 22
  • 17
0

Hi got ur work done as below...

function Searchinput()
{
var str = "This is a test "; // Content of the div
var lastWord = str.substr(str.trim().lastIndexOf(" ")+1);
  alert(lastWord)
}

http://jsbin.com/UWUTar/1/edit

codebreaker
  • 1,465
  • 1
  • 12
  • 18
  • 2
    That's last word, not last **visible** word – MDEV Oct 14 '13 at 09:12
  • 1
    okay, that gives me the last word of the text. But I like to know the last visible word position in the container, which is far to small for the whole text. The last visible word position is somewhere in the text. – Pek Oct 14 '13 at 09:15
  • the last visible word is based on the div width and height and regarding that i have tried a fiddle which gives the characters that are visible in div, now u work a little to get the last word by using ...http://jsfiddle.net/sJ2wG/43/ – codebreaker Oct 14 '13 at 09:32