Why does the last character keeps on printing repeatedly? - javascript

I have written the following to animate the text in a div, but I cannot find how does the last character gets printed repeatedly.
var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (var i in text) {
$(textClass).animate({
opacity: 0.25
}, 200, function() {
$(textClass).append(text.charAt(i));
});
}
p:not(:first-child) {
display: none;
}
p {
margin: 0 auto;
font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
<p class="first-text">HTML</p><br>
</div>
If I try to the alert the value of i or text.charAt(i), I always get the desired output, but when I try to append the same in a div, I always get the same last letter that is printed repeatedly. I cannot find where I am mistaken. I cannot the find the bug in my logic.
If anyone could enlighten me on my mistake in the above code, I would be glad to hear it.
Here is the link to my fiddle where I tried this code.
Thanks in advance.

You've stumbled into a bit of learning when it comes to closures. When i loops through, and eventually gets run inside the function, it's only looking at the last character, because that's what i was overwritten to before the first animate() actually fires.
You can counteract this by manually creating a closure yourself, wrapping it in a function and passing it in, to preserve the variable at the time of the loop.
For more information on closures, check out: What is a 'Closure'?
var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (var i in text) {
(function (char) {
$(textClass).animate({
opacity: 0.25
}, 200, function() {
$(textClass).append(text.charAt(char));
});
})(i)
}
p:not(:first-child) {
display: none;
}
p {
margin: 0 auto;
font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
<p class="first-text">HTML</p><br>
</div>
Alternatively, you can use new let or const syntax, which defines i for the scope of the block (Which essentially creates a closure around your if block.)
var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (const i in text) {
$(textClass).animate({
opacity: 0.25
}, 200, function() {
$(textClass).append(text.charAt(i));
});
}
p:not(:first-child) {
display: none;
}
p {
margin: 0 auto;
font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
<p class="first-text">HTML</p><br>
</div>

You can either create a closure or use let or const to declare the variable i inside for loop which will preserve the current value of i in each iteration:
var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (const i in text) {
$(textClass).animate({
opacity: 0.25
}, 200, function() {
$(textClass).append(text.charAt(i));
});
}
p:not(:first-child) {
display: none;
}
p {
margin: 0 auto;
font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
<p class="first-text">HTML</p><br>
</div>

Using the let and const instead of var you get a better scoping and do not need to create a closure. Also no need to keep doing $(textClass) - you can cache the object
const $textClass = $(".first-text");
const text = $textClass.text();
$textClass.text("");
for (let i in text) {
$textClass.animate({
opacity: 0.25
}, 200, function() {
$textClass.append(text.charAt(i));
});
}
p:not(:first-child) {
display: none;
}
p {
margin: 0 auto;
font-size: 24px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="animate-text">
<p class="first-text">HTML</p><br>
</div>

It seems to have a variable declaration in your script.
var textClass = $(".first-text");
var text = textClass.text();
textClass.text("");
for (const i in text){
$(textClass).animate({
opacity: 0.25
}, 200, function(){
$(textClass).append(text.charAt(i));
});
}
Please review the following JSFiddle link.
http://jsfiddle.net/tp3juw54/19/

Related

MathJax in div incorrect height

I am trying to figure out why MathJax render block gives me the wrong height for the div. The code is
<div class="text-field" id='inner-text'>\(\sqrt{b^{a}\frac{\partial y}{\partial x}}\)</div>
with CSS
.text-field {
display: inline-block;
overflow: hidden;
max-width: 15em;
}
When the following JS snippet is run
MathJax.typeset();
let text = document.getElementById("inner-text");
console.log(text.clientHeight,
text.offsetHeight,
text.getBoundingClientRect().height,
window.getComputedStyle(text).getPropertyValue('height'));
The console gives
41 41 41.25 "41.25px"
However, in inspect elements:
The actual height does not agree with any of height options accessible via JS. What is going on and how should can a get an accurate height value?
The problem is that it takes MathJax time to create the visualization. The idea of the solution I made is to give time to MathJax and when it is ready then we take the size of the element.
I made two versions of the code. Both work correctly in Firefox, Chrome, Edge... etc.
Option 1:
The script waits for MathJax to load then gives it another 100ms to complete and then takes the size of the inner-text
var checkEx = setInterval(function () {
let wrap = document.getElementById("inner-text");
var text = wrap.getElementsByClassName('MathJax')[0];
if (text) {
setTimeout(() => {
console.log(wrap.getBoundingClientRect().height, wrap.getBoundingClientRect().width);
}, 100);
clearInterval(checkEx);
}
}, 100);
.text-field {
display: inline-block;
overflow: hidden;
max-width: 15em;
}
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax#3/es5/tex-mml-chtml.js"></script>
<div class="text-field" id='inner-text'>\(\sqrt{b^{a}\frac{\partial y}{\partial x}}\)</div>
Option 2
The script waits for MathJax to load then begins to take the size of the element. When the size stops changing... return the size of the inner-text
var elhg;
var elwg;
var checkEx = setInterval(function () {
let wrap = document.getElementById("inner-text");
var text = wrap.getElementsByClassName('MathJax')[0];
if (text) {
elHeight = wrap.getBoundingClientRect().height;
elWidth = wrap.getBoundingClientRect().width;
if (elhg === elHeight && elwg === elWidth) {
console.log(elHeight, elWidth);
clearInterval(checkEx);
}
elhg = elHeight;
elwg = elWidth;
}
}, 100);
.text-field {
display: inline-block;
overflow: hidden;
max-width: 15em;
}
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax#3/es5/tex-mml-chtml.js"></script>
<div class="text-field" id='inner-text'>\(\sqrt{b^{a}\frac{\partial y}{\partial x}}\)</div>

Print the disappeared hovered numbers in the order that the user mouseover them using Java Script

I made this webpage, where random numbers appear from 1 to 9 in square divs.
What I need is:
When the user mouseover any number, the number will disappear, finally when the user finishes hovering all of the numbers, an alert should appear displaying all the numbers in the order that the user hovered.
Here is my attempt:
I could only make the numbers disappeared, but how can I print them in an alert in the same order that the user hovered:
document.getElementById("s1").addEventListener("mouseover", function(){
document.getElementById("s1").style.visibility = "hidden";})
document.getElementById("s2").addEventListener("mouseover", function(){
document.getElementById("s2").style.visibility = "hidden"; })
document.getElementById("s2").addEventListener("mouseover", function(){
document.getElementById("s2").style.visibility = "hidden"; })
document.getElementById("s3").addEventListener("mouseover", function(){
document.getElementById("s3").style.visibility = "hidden";})
document.getElementById("s4").addEventListener("mouseover", function(){
document.getElementById("s4").style.visibility = "hidden";})
document.getElementById("s5").addEventListener("mouseover", function(){
document.getElementById("s5").style.visibility = "hidden";})
document.getElementById("s6").addEventListener("mouseover", function(){
document.getElementById("s6").style.visibility = "hidden";})
document.getElementById("s7").addEventListener("mouseover", function(){
document.getElementById("s7").style.visibility = "hidden";})
document.getElementById("s8").addEventListener("mouseover", function(){
document.getElementById("s8").style.visibility = "hidden";})
document.getElementById("s9").addEventListener("mouseover", function(){
document.getElementById("s9").style.visibility = "hidden";})
function alertAfterHovering() {
alert(document.getElementById("s1").innerHTML+" "+document.getElementById("s2").innerHTML+"
"+document.getElementById("s3").innerHTML+" "+document.getElementById("s4").innerHTML+"
"+document.getElementById("s5").innerHTML+" "+document.getElementById("s6").innerHTML+"
"+document.getElementById("s7").innerHTML+" "+document.getElementById("s8").innerHTML+"
"+document.getElementById("s9").innerHTML)
}
You can do it using eventListener and using some dynamic code:
var squares = document.getElementsByClassName("square");
for (square of squares) {
square.addEventListener("mouseenter", addNumber);
}
var total = [];
function addNumber(e) {
if(e.target.textContent) {
total.push(e.target.textContent);
e.target.textContent = "";
if(total.length === squares.length) {
alert(total);
}
}
}
.square {
width: 29%;
height: 50px;
background: #00ffff;
margin: 2%;
display: flex;
align-items: center;
justify-content: center;
}
.box {
display: flex;
flex: 0 1 33%;
flex-wrap: wrap;
}
<div class="box">
<div class="square">1</div>
<div class="square">2</div>
<div class="square">3</div>
<div class="square">4</div>
<div class="square">5</div>
<div class="square">6</div>
<div class="square">7</div>
<div class="square">8</div>
<div class="square">9</div>
</div>
Create an array to capture the numbers as the user hovers. Then use that array to display the alert.
var numbers = [];
// repeat this for each element Or find a better way of targeting the elements so you don't have to hard code for each one
document.getElementById("s1").addEventListener("mouseover", function(){
var thisNumber = document.getElementById("s1").innerHTML;
// you need some way of making sure hovering over an invisible element does not add a duplicate to the array
if (!numbers.includes(thisNumber) {
numbers.push(thisNumber);
}
document.getElementById("s1").style.visibility = "hidden";
});
function alertAfterHovering() {
alert(numbers);
}

Why don't if statments work when repeated in JavaScript?

I am trying to make a grid where the different boxes will blink based off of a binary value defined within my HTML document. I have created a grid in HTML, where the background colour is automatically green and what I'm trying to achieve is that if my value changes to from 0 to 1 for each of the grid items it will then change the colour to red and blink respectively.
I have managed to get the first one working and thought I could just repeat the code with different variables assigned, however this hasn't worked. The weird thing is, if I remove the code for the first box the second box will start working.
Do I need to add some extra code in JS to separate the if statments?
CSS'
.grid-container {
display: grid;
grid-gap: 50px;
grid-template-columns: auto auto auto;
background-color: grey;
padding: 10px;
}
.grid-item {
background-color: green;
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 50px;
font-size: 30px;
text-align: center;
}
HTML
<div class="grid-container">
<div class="grid-item" id = "blink1">A</div>
<div class="grid-item" id = "blink2">B</div>
</div>
<div class = "values">
<div id = "$box1value"> 1 </div>
<div id = "$box2value"> 1 </div>
</div>
JS
var $box1 = document.getElementById("$box1value").innerHTML;
if ($box1 > 0) {
document.getElementById("blink1").style.backgroundColor = '#ff0000';
// blink "on" state
function show() {
if (document.getElementById)
document.getElementById("blink1").style.visibility = "visible";
}
// blink "off" state
function hide() {
if (document.getElementById)
document.getElementById("blink1").style.visibility = "hidden";
}
for (var i = 900; i < 99999999999; i = i + 900) {
setTimeout("hide()", i);
setTimeout("show()", i + 450);
}
} else {
document.getElementById("blink1").style.backgroundColor = '#098700';
}
/////////////////////next box/////////////////////////////
var $box2 = document.getElementById("$box2value").innerHTML;
if ($box2 > 0) {
document.getElementById("blink2").style.backgroundColor = '#ff0000';// blink "on" state
function show() {
if (document.getElementById)
document.getElementById("blink2").style.visibility = "visible";
}
// blink "off" state
function hide() {
if (document.getElementById)
document.getElementById("blink2").style.visibility = "hidden";
}
for (var i = 900; i < 99999999999999999; i = i + 900) {
setTimeout("hide()", i);
setTimeout("show()", i + 450);
}
} else {
document.getElementById("blink2").style.backgroundColor = '#098700';
}
2 different solutions (all JS vs. mostly CSS)
Keeping the core functionality in JS
Leveraging CSS for core functionality
I see what you're trying to achieve here, and I see a couple of different ways to accomplish this. Both of the solutions below allow your code to dynamically loop through any number of box items— no need to write a separate block for each item.
The first example below is modeled more similar to yours, based on
your code but rewritten to work more dynamically. The second solution
further down greatly simplifies things by moving all initialization
scripting into CSS, leaving JS responsible for only boolean switching
if you need to make any real-time state switches.
#1. Keeping the core functionality in JS
This solution modifies your original code to dynamically read the values for however many values there are, and then looping through them. In order to perform the repeated blinking in JS, I would suggest using setInterval. You'll also need to move that outside the rest of the code when using a loop or you'll end up with a conflict between the loop's iterator and the setInterval's and setTimeout's timing. More on that here. You can see the working example below:
function blink(el) {
if (el.style) {
setInterval(function() {
el.style.visibility = "visible";
setTimeout(function() {
el.style.visibility = "hidden";
}, 450);
}, 900);
}
}
const $boxes = document.querySelectorAll('[id^="blink"]');
for (const $box of $boxes) {
var boxId = $box.id.match(/\d+/)[0]; // store the ID #
if (document.getElementById('$box' + boxId + 'value')) {
var boxValue = parseInt(document.getElementById('$box' + boxId + 'value').innerHTML);
if (boxValue) {
$box.style.backgroundColor = '#ff0000';
blink($box);
} else {
$box.style.backgroundColor = '#098700';
}
}
}
.grid-container {
display: grid;
grid-gap: 50px;
grid-template-columns: auto auto auto;
background-color: grey;
padding: 10px;
}
.grid-item {
background-color: #098700;
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 50px;
font-size: 30px;
text-align: center;
}
.values {
display: none;
}
<div class="grid-container">
<div class="grid-item" id="blink1">A</div>
<div class="grid-item" id="blink2">B</div>
<div class="grid-item" id="blink3">C</div>
</div>
<div class="values">
<div id="$box1value">1</div>
<div id="$box2value">0</div>
<div id="$box3value">1</div>
</div>
CodePen: https://codepen.io/brandonmcconnell/pen/ecc954bad5552962574c080631700932
#2. Leveraging CSS for core functionality
This solution moves all of your JS code (color and animation) to the CSS, moving the binary boolean switch 0/1 to data-attributes on the grid-items themselves instead of separate items and then trigger any boolean switches on those containers using JS by targeting them by another attribute such as ID, or as I used in my example below, another data-attribute I called data-blink-id. This is my recommended solution if you're able to move all of this logic into CSS. It'll be much easier to maintain and to manipulate in real-time, as all it requires to change state is a simple boolean switch.
.grid-container {
display: grid;
grid-gap: 50px;
grid-template-columns: auto auto auto;
background-color: grey;
padding: 10px;
}
.grid-item {
background-color: #098700;
border: 1px solid rgba(0, 0, 0, 0.8);
padding: 50px;
font-size: 30px;
text-align: center;
}
.grid-item[data-blink-status="1"] {
background-color: #f00;
animation: blink 900ms linear infinite forwards;
}
#keyframes blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
<div class="grid-container">
<div class="grid-item" data-blink-id="1" data-blink-status="1">A</div>
<div class="grid-item" data-blink-id="2" data-blink-status="0">B</div>
<div class="grid-item" data-blink-id="3" data-blink-status="1">C</div>
</div>
CodePen: https://codepen.io/brandonmcconnell/pen/5b4f3090b3590902b11d50af43361758
To trigger the binary boolean switch on an item (turn ON/OFF), use the below JS command. I've commented this out in the CodePen example linked above. Un-comment this JS line to activate it and switch ON the block with data-blink-id=2
document.querySelector('[data-blink-id="2"]').setAttribute('data-blink-status', 1);
Even though your functions are declared inside if statements, they are still global.
So, you essentially redeclare the show and hide functions, and they stop working.
To make those functions local to the if statement, you'll have to use one of the ES6 block scope declarations, let or const, like this:
const show = function(){ ... }
const hide = function(){ ... }
To do this, you should also replace setTimeout's first argument with a reference to the function (actually, you should always do that):
setTimeout(hide, i)
setTimeout(show, i + 450)
Other improvements you can make:
Avoid that loop that sets timeouts. It's ugly, takes long to execute, and doesn't work forever. Instead, replace setTimeouts with setIntervals.
Remove the if (document.getElementById) part. You can count on it to be defined (it has been around for a loooong time...)
So, you get to:
var $box1 = document.getElementById("$box1value").innerHTML;
if ($box1 > 0) {
document.getElementById("blink1").style.backgroundColor = '#ff0000';// blink "on" state
const show = function () {
document.getElementById("blink1").style.visibility = "visible";
}
// blink "off" state
const hide = function () {
document.getElementById("blink1").style.visibility = "hidden";
}
let flag = false //This is needed to keep track if the element is visible
setInterval(function(){
if(flag = !flag)
hide()
else
show()
}, 450);
} else {
document.getElementById("blink1").style.backgroundColor = '#098700';
}
/////////////////////next box/////////////////////////////
var $box2 = document.getElementById("$box2value").innerHTML;
if ($box2 > 0) {
document.getElementById("blink2").style.backgroundColor = '#ff0000';// blink "on" state
const show = function () {
document.getElementById("blink2").style.visibility = "visible";
}
// blink "off" state
const hide = function () {
document.getElementById("blink2").style.visibility = "hidden";
}
let flag = false //This is needed to keep track if the element is visible
setInterval(function(){
if(flag = !flag)
hide()
else
show()
}, 450);
} else {
document.getElementById("blink2").style.backgroundColor = '#098700';
}

how to stop a sound when an animation ends

I have very little experience in coding in general. But I've somehow managed to get this far with this, and I'm stuck on the very last thing.
This is for a Twitch alert, I'm doing this through 'Stream Elements'
The thing I'm having issues with is stopping the sound once the typing letters have fully appeared, I have no idea how to do this. Is it even possible?
I Forgot to mention, the Typekit links are intentionally broken, as I didn't want to share the link (Since I'm assuming they're all unique and based off your adobe account)
$(document).ready(function() {
var timer, fullText, currentOffset, onComplete, hearbeat = document.getElementById('heartbeat');
heartbeat.play();
function Speak(person, text, callback) {
$("#usernamean-container").html(person);
fullText = text;
currentOffset = 0;
onComplete = callback;
timer = setInterval(onTick, 120
);
}
function onTick() {
currentOffset++;
if (currentOffset == fullText.length) {
complete();
return;
}
var text = fullText.substring(0, currentOffset);
$("#message").html(text);
}
function complete() {
clearInterval(timer);
timer = null;
$("#message").html(fullText);
onComplete()
;
}
$(".box").click(function () {
complete();
});
Speak("{{name}}",
"{{name}} Is now a Witness",
)
//get data from the 🤟 StreamElements 🤟 data injection
const name = '{{name}}';
// vanilla es6 query selection (can use libraries and frameworks too)
const userNameContainer = document.querySelector('#username-container');
// change the inner html to animate it 🤪
userNameContainer.innerHTML = stringToAnimatedHTML(name, animation);
/**
* return an html, with animation
* #param s: the text
* #param anim: the animation to use on the text
* #returns {string}
*/
function stringToAnimatedHTML(s, anim) {
let stringAsArray = s.split('');
stringAsArray = stringAsArray.map((letter) => {
return `<span class="animated-letter ${anim}">${letter}</span>`
});
return stringAsArray.join('');
}
heartbeat.pause();
heartbeat.currentTime = 0;
});
#import url(#import url("https://use.typekit.net/.css");
.awsome-text-container {
font-family: typeka, sans-serif;
font-size: 42px;
font-weight: 400;
}
.image-container {
margin: auto;
display: table;
}
.text-container {
font-family: typeka, sans-serif;
font-size: 26px;
color: rgb(204, 10, 33);
text-align: center;
margin: auto;
text-shadow: rgba(0, 0, 0, 0.5) 1px 1px 1px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="heart" class="heart">
<audio id="heartbeat" src="https://cdn.discordapp.com/attachments/135995830279733248/733547597305741332/typewriters.mp3" preload="auto"></audio>
<link rel="stylesheet" href="https://use.typekit.net/.css">
<div class="text-container">
<div class="image-container">
<img src="https://media.tenor.com/images/83d6a5ed40a24164dfe1e4e19fad23d9/tenor.gif">
</div>
<div>
<div class="awsome-text-container">
<span id="message"></span>
<br>
</div>
</div>
</div>
Hello and welcome to Stack Overflow!
I have seen messier code and was therefor disappointed ;-). Regarding your question:
Main problem would be that you have a typo in your code and you call the heartbeat.pause(); in the complete method and not at the end of script (as this would be called independently of the completion of the animation).
Typo:
hearbeat = document.getElementById('heartbeat');
Changed method:
function complete() {
clearInterval(timer);
timer = null;
$("#message").html(fullText);
heartbeat.pause();
heartbeat.currentTime = 0;
}
and remove the lines from the bottom of your script.

Filling div using letter-spacing

The problem I'm having is filling a div with text using letter-spacing. The main issue is, I don't know the width of the div.
First I was thinking using, text-align= justify, but since that I've been running in the dark and got no clue to how to solve this. I'm guessing some scripting magic might do the trick.
An imgur link giving you an idea what I mean:
<div id="container">
<h1>Sample</h1>
<p>Another even longer sample text</p>
</div>
Here is a link showcasing an example; JSfiddle.
Based the comment of the poster it seems JavaScript is no problem. Here's a possible approach to solve the problem with jQuery:
JSFiddle 1
function dynamicSpacing(full_query, parent_element) {
$(full_query).css('letter-spacing', 0);
var content = $(full_query).html();
var original = content;
content = content.replace(/(\w|\s)/g, '<span>$1</span>');
$(full_query).html(content);
var letter_width = 0;
var letters_count = 0;
$(full_query + ' span').each(function() {
letter_width += $(this).width();
letters_count++;
});
var h1_width = $(parent_element).width();
var spacing = (h1_width - letter_width) / (letters_count - 1);
$(full_query).html(original);
$(full_query).css('letter-spacing', spacing);
}
$(document).ready(function() {
// Initial
dynamicSpacing('#container h1', '#container');
// Refresh
$(window).resize(function() {
dynamicSpacing('#container h1', '#container');
});
});
Update
Small tweak for when the wrapper gets too small: JSFiddle 2
Another solution if you don't have to be semantic (because you will get many spans), I mean if you need only the visual result, is to use flexbox.
So you have your <div id="#myText">TEXT 1</div>
We need to get this:
<div id="#myText">
<span>T</span>
<span>E</span>
<span>X</span>
<span>T</span>
<span> </span>
<span>1</span>
</div>
So then you can apply CSS:
#myText {
display: flex;
flex-direction: row;
justify-content: space-between;
}
In order to transform the text to span you can use jQuery or whatever. Here with jQuery:
var words = $('#myText').text().split("");
$('#myText').empty();
$.each(words, function(i, v) {
if(v===' '){
$('#myText').append('<span> </span>');
} else {
$('#myText').append($("<span>").text(v));
}
});
For better results remove put letter-spacing: 0 into #myText so any extra spacing will be applied.
This is obviously evil, but since there is no straight forward way to do it with just css, you could do: demo
HTML:
<div>text</div>
CSS:
div, table {
background: yellow;
}
table {
width: 100%;
}
td {
text-align: center;
}
JS:
var text = jQuery("div").text();
var table = jQuery("<table><tr></tr></table>").get(0);
var row = table.rows[0];
for (var i = 0; i < text.length; i++) {
var cell = row.insertCell(-1);
jQuery(cell).text(text[i]);
}
jQuery("div").replaceWith(table);
This may help:
function fill(target) {
var elems = target.children();
$.each(elems, function(i,e) {
var x = 1;
var s = parseInt($(e).css('letter-spacing').replace('px',''));
while(x == 1) {
if($(e).width() <= target.width() - 10) {
s++;
$(e).css('letter-spacing', s+'px');
} else {
x = 0;
}
}
});
}
fill($('#test'));
Note: If letter spacing is : 0 then you don't have to use replace method. Or you can add letter-spacing:1px; to your css file.
For avoiding overflow, always give minus number to parent element's height for correct work.
An other approach I wrote for this question Stretch text to fit width of div. It calculates and aplies letter-spacing so the text uses the whole available space in it's container on page load and on window resize :
DEMO
HTML :
<div id="container">
<h1 class="stretch">Sample</h1>
<p class="stretch">Another even longer sample text</p>
</div>
jQuery :
$.fn.strech_text = function(){
var elmt = $(this),
cont_width = elmt.width(),
txt = elmt.text(),
one_line = $('<span class="stretch_it">' + txt + '</span>'),
nb_char = elmt.text().length,
spacing = cont_width/nb_char,
txt_width;
elmt.html(one_line);
txt_width = one_line.width();
if (txt_width < cont_width){
var char_width = txt_width/nb_char,
ltr_spacing = spacing - char_width + (spacing - char_width)/nb_char ;
one_line.css({'letter-spacing': ltr_spacing});
} else {
one_line.contents().unwrap();
elmt.addClass('justify');
}
};
$(document).ready(function () {
$('.stretch').each(function(){
$(this).strech_text();
});
$(window).resize(function () {
$('.stretch').each(function(){
$(this).strech_text();
});
});
});
CSS :
body {
padding: 130px;
}
#container {
width: 100%;
background: yellow;
}
.stretch_it{
white-space: nowrap;
}
.justify{
text-align:justify;
}

Categories

Resources