Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find the last visible word position in a text container?

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!

like image 687
Pek Avatar asked Oct 14 '13 09:10

Pek


3 Answers

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).

like image 126
MDEV Avatar answered Nov 02 '22 15:11

MDEV


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.

like image 2
Matansh Avatar answered Nov 02 '22 15:11

Matansh


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/

like image 1
VisioN Avatar answered Nov 02 '22 14:11

VisioN