Skip to content

Commit

Permalink
Vanilla JS version of FastEllipsis
Browse files Browse the repository at this point in the history
  • Loading branch information
tarekw committed May 29, 2014
1 parent 8d2c9be commit c741e52
Show file tree
Hide file tree
Showing 2 changed files with 242 additions and 0 deletions.
154 changes: 154 additions & 0 deletions js/Vanilla.FastEllipsis.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
// Native JavaScript version of Dobiatowski's Fast Ellipsis Algorithm that originially used JQuery
// License: MIT

// Modified by tarekw (Tarek Wahab)

function FastEllipsis (cssStyle) {
var _charWidthArray = {},
_cssStyle = (!!cssStyle) ? cssStyle : "font-family: arial; font-size: 12pt",
_maxWidth = 0,
testDrive = 0;

// Generate cache for width of all ASCII chars
function generateASCIIwidth() {
var container, charWrapper, obj, character,
totalWidth = 0, oldTotalWidth = 0, charWidth = 0;

// Temporary container for generated ASCII chars
container = document.createElement('div');
container.style.width = '6000px';
container.style.visibility = 'hidden';
document.body.appendChild(container);

charWrapper = document.createElement('span');
charWrapper.style.cssText = _cssStyle;
container.appendChild(charWrapper);

// DUMMY chars
charWrapper.innerHTML += "f";

testDrive = document.createElement('span');
testDrive.innerHTML = "i";
charWrapper.appendChild(testDrive);
totalWidth = charWrapper.offsetWidth;

// Space char
charWrapper.innerHTML = " " + charWrapper.innerHTML;
oldTotalWidth = totalWidth;
totalWidth = charWrapper.offsetWidth;
charWidth = (totalWidth - oldTotalWidth)+0.4; // hack: add 0.4px to every space
_charWidthArray["_ "] = charWidth;

// Other ASCII chars
for( var i = 33; i <= 126; i++ ) {
character = String.fromCharCode( i );
charWrapper.innerHTML = "" + character + character + charWrapper.innerHTML;

oldTotalWidth = totalWidth;
totalWidth = charWrapper.offsetWidth;
charWidth = (totalWidth - oldTotalWidth)/2; // While cache is generating add two the same chars at once, and then divide per 2 to get better kerning accuracy.
_charWidthArray["_"+character] = charWidth;

// Finds max width for char - it will be given for every undefined char like: Ą or Ć
if (_maxWidth < _charWidthArray["_"+character]) {
_maxWidth = _charWidthArray["_"+character];
}
}

// Remove temporary container
document.body.removeChild(container);
}

// Get the width of specified char
function getCharWidth (myChar) {
// If there is a char in cache
if (!!_charWidthArray["_"+myChar]) {
return _charWidthArray["_"+myChar];
}
// If there is no char in cache set max width and save in cache
else {
_charWidthArray["_"+myChar] = _maxWidth;
return _maxWidth;
}
}

// Get the width of the word
function getWordWidth(myWord) {
myWord = myWord.trim();

// Check if this word is already cached
if (!!_charWidthArray["_"+myWord]) {
return _charWidthArray["_"+myWord];
}
// If no, calculate it
else {
var sum = 0;
for (var i = 0, len = myWord.length; i < len; i++) {
sum = sum + getCharWidth(myWord[i]);
}
sum = Math.floor(sum);
_charWidthArray["_"+myWord] = sum;
return sum;
}
}

// Ellipse text based on CSS styling set in constructor.
function ellipseIt(myString, maxLine, lineWidth) {
var lineNo = 1,
wordsInLineWidth = 0,
wordArr = myString.trim().strip_tags().replace("-", "- ").split(/\s+/g), // trim string, remove HTML tags, remove space duplicates, detect dash word breaking
spaceWidth = getCharWidth(" "),
threeDotsWidth = getWordWidth("...");

for (var i = 0, len = wordArr.length; i < len; i++) {
// Adding widths of words in the loop
wordsInLineWidth += getWordWidth(wordArr[i]);

// Check if the total width of words calculated so far is larger than width of container passed in the parameter
if (wordsInLineWidth > lineWidth) {
// If yes, go to next line and reset the words width
lineNo++;
wordsInLineWidth = 0;

// If accessing to the last line subtract width of ellipsis (...) from line width to reserve place for ellipsis
if (lineNo == maxLine) {
lineWidth -= threeDotsWidth;
}
// When you reached the end of maxLine parameter break the loop and return the result
else if (lineNo > maxLine) {
return wordArr.slice(0, i).join(" ").replace("- ", "-") + "..."; // replace to reverse dash word breaking
}

// If the words width was bigger than line width go back in the loop to take last word for use in the beggining of next line
i--;
}
else {
// Adding width of space between words
wordsInLineWidth += spaceWidth;
}
}

// If there was no need to ellipsis
return myString;
}

generateASCIIwidth();

return {
ellipseIt: ellipseIt
}
};

// Add string functions to String prototype

if (typeof String.prototype.trim !== "function") {
String.prototype.trim = function () {
return this.replace(/^\s*/, "").replace(/\s*$/, "");
};
};

if (typeof String.prototype.strip_tags !== "function") {
String.prototype.strip_tags = function() {
return this.replace(/<\/?[^>]+(>|$)/g, "");
};
};
88 changes: 88 additions & 0 deletions vanilla_index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript" src="js/Vanilla.FastEllipsis.js"></script>
<style type="text/css">
div {
padding:5px;
margin-bottom:10px;
margin-left:5px;
text-align:justify;
}
</style>
</head>
<body>

<div style="float:left;">
<p>Full text:</p>
<div id="containerA" style="background:#cdf; width:320px;font-family:arial;font-size:16px;letter-spacing:0;"></div>
</div>

<div style="float:left;" id="containerB">
<p>Ellipsised width 320px, 5 rows:</p>

</div>
<div style="float:left;" id="containerC">
<p>Ellipsised width 450px, 3 rows:</p>

</div>

<script type="text/javascript">
(function() {

function randOrd() {return (Math.round(Math.random())-0.5); }

function getRandomText() {
return ("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum").split(" ").sort( randOrd ).join(" ");
}


var myEllipsis = new FastEllipsis("font-family: arial; font-size: 16px; letter-spacing: 0px;");

var longText = getRandomText();
var containerA = document.getElementById('containerA');
containerA.innerHTML = longText;


var ellipsed;
var containerB = document.getElementById('containerB');
var containerC = document.getElementById('containerC');

for (var i = 0, max = 1000; i < max; i++) {
ellipsed = myEllipsis.ellipseIt(
getRandomText(), // string to ellipsis
5, // maxline number
320 // width of container
);

var div = document.createElement('div');
div.style.background = '#fcd';
div.style.width = '320px';
div.style.fontFamily = 'arial';
div.style.fontSize = '16px';
div.style.letterSpacing = '0';
div.innerHTML = ellipsed;
containerB.appendChild(div);
}

for (var i = 0, max = 1000; i < max; i++) {
ellipsed = myEllipsis.ellipseIt(
getRandomText(), // string to ellipsis
3, // maxline number
450 // width of container
);

var div = document.createElement('div');
div.style.background = '#dcf';
div.style.width = '450px';
div.style.fontFamily = 'arial';
div.style.fontSize = '16px';
div.style.letterSpacing = '0';
div.innerHTML = ellipsed;
containerC.appendChild(div);
}
})();
</script>
</body>
</html>

0 comments on commit c741e52

Please sign in to comment.