JS/jQuery: Trying to fit an arbitrary text string within a certain width through substr
I'm trying to take a text string, (e.g. the word "testing") and calculating if the string, when displayed on screen, will exceed a certain width. I do this by putting it in a element and using width().
Now, the thing is I want to reduce the text string by a character at a time, and then determining the width. If the width is within say "130px", then i'll return that truncated string. I have the following recursive function, but I'm quite new to Js/jQuery and am unsure what I did wrong. If the string is determined to require truncating, the function returns undefined.
Any help is greatly appreciated. Thanks a lot!
function fitWidth(str) {
var width = $('span.width').html(str).width();
if (width > '130') {
strlength开发者_开发知识库 = str.length-1;
str = str.substr(0,strlength);
fitWidth(str);
} else {
return str; // something wrong here?
}
}
var testStr = 'Lorem Ipsum';
alert(fitWidth(testStr)); // returns undefined if it was truncated
if str requires truncating, fitWidth() will return "undefined"
You need to say return fitWidth(str);
in the recursive case.
// Here is one other method,
// but you'll need to translate it to jquery-
function truncate(str, w, pa){
if(!pa) pa= document.body;
w= w || pa.offsetWidth;
var wid, t, L= str.length, c= document.createElement('div');
c.style.cssText=
'position:absolute; visibility:hidden; font:inherit; white-space:pre';
t= document.createTextNode(str);
c.appendChild(t);
pa.appendChild(c);
wid= c.offsetWidth;
if(w< wid){
L= Math.floor(L*(w/wid))-1;
t.data= str= str.substring(0, L);
while(t.data && c.offsetWidth> w){
t.data= str= str.slice(0, -1);
}
}
pa.removeChild(c);
return str;
}
var testStr= 'The style is white-space:pre to keep it on one line';
alert(truncate(testStr, 130));
//comments
function truncate(str, w, pa){
// create a hidden element to measure the text-
// pass a parent element (pa) if the target's font family,
// weight or size is not the same as body text
// or if you use the parent's width to size the text
if(!pa) pa= document.body;
w= w || pa.offsetWidth;
var wid, t, L= str.length, c= document.createElement('div');
c.style.cssText=
'position:absolute;visibility:hidden;font:inherit;white-space:pre';
t= document.createTextNode(str);
c.appendChild(t);
pa.appendChild(c);
wid= c.offsetWidth;
// measure the width of the whole string
// if it fits your width, skip the calculations,
// otherwise multiply the length of the string by
// the width you want divided by the actual width
if(w< wid){
L= Math.floor(L*(w/wid))-1;
//I'd subtract 1 to grow on and call it str.substring(0, L);
//but if the exact to the pixel width is critical,
//measure the new string and chop it if it still needs it:
t.data= str= str.substring(0, L);
while(t.data && c.offsetWidth> w){
t.data= str= str.slice(0, -1);
}
}
// clean up, and return the (possibly) shortened string
pa.removeChild(c);
return str;
}
I modified the OP code to make it work for me.
This uses jQuery and requires you to add this function (endsWith) to the String prototype. See https://stackoverflow.com/a/2548133/80353.
function fitWidth(str, selector, widthLimit, heightLimit, suffix, original) {
if (typeof heightLimit == 'undefined') {
heightLimit = 10000000000;
}
if (typeof suffix == 'undefined') {
suffix = '';
}
if (typeof original == 'undefined') {
original = str;
}
if (suffix.length > 0 && str.endsWith(suffix)) {
str = str.substr(0, str.length - suffix.length);
}
var width = $(selector).html(str).width();
var height = $(selector).html(str).height();
if (suffix.length > 0 && original != str) {
var width = $(selector).html(str + suffix).width();
var height = $(selector).html(str + suffix).height();
}
// console.info($(selector));
// console.info(width);
if (width > widthLimit || height > heightLimit) {
strlength = str.length-1;
str = str.substr(0,strlength);
$(selector).html(str + suffix);
fitWidth(str + suffix, selector, widthLimit, heightLimit, suffix, original);
} else {
return true;
}
}
// if you want to consider suffix for shortened content like "I want to ..."
fixWidth("I want to break free", "#selector", 180, 60, " ...");
Hope this will help others.
New Answer: I don't know if this would be faster but it does work.
function fitWidth(str) {
var width = $('span.width').css('display', 'inline').html(str).width();
var charWidth = Math.round(width / str.length);
var maxLength = 130 / charWidth;
$('span.width').html(str.substr(0, maxLength));
}
Old Answer:
instead of doing this recursively why don't you just use substr() to make the width 130.
like so:
function fitWidth(str) {
var width = $('span.width').html(str).width();
if(width > 130) {
return str.substr(0, 130);
} else {
return str;
}
}
EDIT: oh, i see now that you are talking about width vs the length of the characters in the string. Still, if you take the width of a font being used i think you could still avoid doing multiple steps.
精彩评论