Delay of Javascript based Tumblr width calculation - javascript

my Tumblr theme CSS width is changed by javascript code (according to the number of posts).
Theme is loaded with the standard width and after the number of posts is known, the new width is calculated by the following javascript function (to fit posts).
PROBLEM is the big delay of this calculation (it waits until content of posts is loaded)!
Is it possible to calculate and set width immediately based on number of posts and not to wait for posts content loading?
<script type="text/javascript">
function resizedivs() {
$ = function(id) { return document.getElementById(id); }
fschildren = $("fs_wrapper").childNodes;
postc = 0;
thedivs = new Array();
for(i = 0; i < fschildren.length; i++) {
if(fschildren[i].tagName == "DIV") {
thedivs[postc] = fschildren[i];
postc++;
}
}
newwidth = 0;
for(i = 0; i < thedivs.length; i++) {
if(newwidth <= document.body.clientWidth) {
newwidth = newwidth + (thedivs[i].clientWidth)+15;
}
if(newwidth >= document.body.clientWidth || newwidth >= 1300) { // 100 for padding minus 15 extra
newwidth = newwidth - (thedivs[i].clientWidth+15);
break;
}
}
$("fs_wrapper").style.width = newwidth-0+"px";
$("fs_wrapper").style.position = "relative";
$("fs_wrapper").style.left = "0px";
$("sec2").style.width = newwidth-0+"px";
$("sec2").style.position = "relative";
$("sec2").style.left = "0px";
$("sec3").style.width = newwidth-0+"px";
$("sec3").style.position = "relative";
$("sec3").style.left = "0px";
}
window.onresize = function() {
resizedivs();
}
window.onload = function() {
resizedivs();
}
</script>

Related

How to prevent randomly generated images from overlapping using Javascript

I'm trying to spawn randomly generated targets on the screen using a function to copy an invisible image of the target to be spawned at a random place within the screen using window object properties.
For this to happen I think the image have to have position set to absolute, but then several images may be spawned in a way that they will overlap, how can I prevent this from happening?
The div element where I copy my first image and also store the other copies.
<div id="targetsDiv">
<img src="target2.png" alt="target_shot" class="target" />
</div>
Inside the script:
var x_pixels = window.innerWidth - 180;
var y_pixels = window.innerHeight - 180;
var x_midScreen = window.innerWidth / 2;
var y_midScreen = window.innerHeight / 2;
var xRandom = Math.floor(Math.random()*x_pixels) +1;
var yRandom = Math.floor(Math.random()*y_pixels) +1;
var targetCollection = document.getElementById("targetsDiv");
var targetCopy = targetCollection.innerHTML
var targetList = document.getElementsByClassName("target");
targetList[0].style.display = "none";
var targetNr = 1;
var numberOfSpawns = 3;
function spawnTargets () {
while (targetNr <= numberOfSpawns) {
if ((xRandom < x_midScreen - 126 || xRandom > x_midScreen + 26) || (yRandom < y_midScreen - 126 || yRandom > y_midScreen + 26)) {
targetCollection.innerHTML += targetCopy;
targetList[targetNr].style.left = xRandom + "px";
targetList[targetNr].style.top = yRandom + "px";
targetNr++;
}
xRandom = Math.floor(Math.random()*x_pixels) +1;
yRandom = Math.floor(Math.random()*y_pixels) +1;
}
}
PS: I appreciate all help, tips and tweaks that you guys provide:) Thanks for helping
The area you want to exclude in the centre of the screen is rather large, and on my little laptop, there isn't even any room to still show the random positioned images.
But anyway, this piece of code should do the job -- I added some infinite loop protection which on my PC was a life-saver:
HTML (added style attribute)
<div id="targetsDiv">
<img src="target2.png" alt="target_shot" class="target"
style="visibility:hidden"/>
</div>
JavaScript:
window.addEventListener('load', function () {
var targetCollection = document.getElementById("targetsDiv");
var template = document.getElementsByClassName("target")[0];
var targetWidth = template.offsetWidth;
var targetHeight = template.offsetHeight;
var x_pixels = window.innerWidth - targetWidth;
var y_pixels = window.innerHeight - targetHeight;
var x_midScreen = window.innerWidth / 2;
var y_midScreen = window.innerHeight / 2;
function spawnTargets (numberOfSpawns) {
var targets = [];
var count = 0; // infinite recursion protection
for (var i = 0; i < numberOfSpawns; i++) {
do {
do {
var x = Math.floor(Math.random()*x_pixels);
var y = Math.floor(Math.random()*y_pixels);
if (count++ > 200) {
console.log('give up');
return;
}
} while ((x >= x_midScreen-450 && x <= x_midScreen+300) && (y >= y_midScreen-350 || y <= y_midScreen+200));
for (var j = 0; j < i; j++) {
if (x >= targets[j].x - targetWidth && x <= targets[j].x + targetWidth &&
y >= targets[j].y - targetHeight && y <= targets[j].y + targetHeight) break; // not ok!
}
} while (j < i);
targets.push({x, y});
img = document.createElement('img');
img.src = template.src;
img.setAttribute('width', targetWidth + 'px');
img.setAttribute('height', targetHeight + 'px');
img.className = template.className;
targetCollection.appendChild(img);
img.style.left = x + "px";
img.style.top = y + "px";
}
}
spawnTargets(3);
});

Optimizing jQuery plugin to truncate text based on size of container

I am not the most savey at javascript or jQuery but I know them well enough. I put together a quick plugin I can drop into any of my websites that will truncate the text of a container dynamically without actually removing the text.
So if I have a container 600x600 pixels, I want the text to fit nicely in there, and when it needs to be cut off, add ... after the last word.
I couldn't find anything that really did this, so I created the following plugin.
It works, it works really great, the only problem is it is painfully slow. Simply because if goes through each line of text.
Is there a way to optimize this at all and not loose the functionality?
// To work the parent div to class .jFit must have it's height defined.
// Stylized spans may cause problems.
$(function() {
$('.jFit').each(function() {
$(this).jFit();
});
});
var resizeTimer;
$(window).on('resize', function(e) {
clearTimeout(resizeTimer);
resizeTimer = setTimeout(function() {
$('.jFit').each(function() {
$(this).jFit(true);
});
}, 150);
});
jQuery.fn.jFit = function(resize = false) {
var parentHeight = $(this).parent().height(),
maxHeight = parentHeight,
height = 0,
char = 0,
i = 1,
str = '',
last = 0;
$(this).siblings().each(function() {
maxHeight -= $(this).outerHeight();
maxHeight -= parseInt($(this).css('margin-top'));
maxHeight -= parseInt($(this).css('margin-bottom'));
});
if (resize) {
$(this).find('.jFit-ellipsis').remove();
var span = $(this).find('.jFit-hide'),
contents = span.html();
span.remove();
$(this).append(contents);
}
while ((str = $(this).line(i))['text'] != "") {
height += str['lineHeight'];
if (maxHeight > height) {
char += str['text'].length;
last = str['text'].length - $.trim(str['text']).lastIndexOf(' ');
i++;
} else {
break;
}
}
if ($.trim(str['text']).lastIndexOf(' ')<0) {
char -= str['text'].length;
str['text'] = $(this).line(i-1 | 0)['text'];
if (str['text'].match('<br\s*\/?>$')) {
char -= str['text'].length;
char += str['text'].lastIndexOf('<');
}
last = 0;
}
if (str['text'].match('/(.|,|;|:)$/')) {
last += 1;
}
if (str['text']!='') {
$(this).html($(this).html().substring(0,char-(last))+'<span class="jFit-ellipsis">...</span><span class="jFit-hide" style="display: none;">'+$(this).html().substring(char-(last)));
$(this).append('</span>');
}
}
jQuery.fn.line = function(line) {
var dummy = this.clone().css({
top: -9999,
left: -9999,
position: 'absolute',
width: this.width()
}).appendTo(this.parent());
var text = dummy.html().match(/(<.*?span[^>]*>|<br.*?>|[\w\.\,]+[\s\.\,])/g);
var words = text.length,
lastTopOffset = 0,
lineNumber = 0,
lineHeight = 0,
ret = '',
found = false;
for (var i = 0; i < words; ++i) {
dummy.html(
text.slice(0,i).join('') +
text[i].replace(/(\S)/, '$1<span id="jFit-lh" style="line-height:inherit;"/>') +
text.slice(i+1).join('')
);
var topOffset = jQuery('#jFit-lh', dummy).offset().top;
lineHeight = $('#jFit-lh').height();
if (topOffset !== lastTopOffset) {
lineNumber += 1;
}
lastTopOffset = topOffset;
if (lineNumber === line) {
found = true;
ret += text[i];
} else {
if (found) {
break;
}
}
}
dummy.remove();
return {text:ret,lineHeight:lineHeight};
}

Check if all percentages in the array were shown

I'm using this Code to show the current progress in my progressbar:
var rotatingTextElement;
var rotatingText = new Array();
var ctr = 0;
function initRotateText() {
rotatingTextElement = document.getElementById("percent");
rotatingText[0] = rotatingTextElement.innerHTML;
rotatingText[1] = "5%";
rotatingText[2] = "10%";
rotatingText[3] = "15%";
rotatingText[4] = "20%";
rotatingText[5] = "25%";
rotatingText[6] = "30%";
rotatingText[7] = "35%";
rotatingText[8] = "40%";
rotatingText[9] = "45%";
rotatingText[10] = "50%";
rotatingText[11] = "55%";
rotatingText[12] = "60%";
rotatingText[13] = "65%";
rotatingText[14] = "70%";
rotatingText[15] = "75%";
rotatingText[16] = "80%";
rotatingText[17] = "85%";
rotatingText[18] = "90%";
rotatingText[19] = "95%";
rotatingText[20] = "100%";
setInterval(rotateText, 500);
}
function rotateText() {
ctr++;
if(ctr >= rotatingText.length) {
ctr = 0;
}
rotatingTextElement.innerHTML = rotatingText[ctr];
}
window.onload = initRotateText;
It basicly writs a new percentage in span#percent every 500 miliseconds.
The problem is that after the progressbar has reached 100% it starts again with 0%, 5% and so on.
How can I check if the percentages in the array rotatingText till [20] were all shown and then stop the rotation?
Do this instead:
var rotatingTextElement = document.getElementById("percent");
var ctr = 0;
function rotateText() {
rotatingTextElement.innerHTML = ctr + "%";
ctr += 5;
if (ctr <= 100) {
window.setTimeout(rotateText, 500);
}
}
rotateText();
There are a few ways you can tidy this up. To answer your question, start by assigning the interval to a variable:
var rotator = null;
...
rotator = setInterval(rotateText, 500);
...
function rotateText() {
ctr++;
if(ctr >= rotatingText.length -1) {
clearInterval(rotator);
}
rotatingTextElement.innerHTML = rotatingText[ctr];
}
...
Then instead of resetting the iterator to 0 when it goes out of bounds, clear the interval so it stops changing the value. You'll need to add the -1 so that it stops on rotatingText[length-1] (the last element)

How to add scroll background effect to multiple elements with different settings?

In this demo http://www.htmldrive.net/items/demo/527/Animated-background-image-with-jQuery
This code is for one background only. I want to add multiple background with different direction and speed.
var scrollSpeed = 70;
var step = 1;
var current = 0;
var imageWidth = 2247;
var headerWidth = 800;
var restartPosition = -(imageWidth - headerWidth);
function scrollBg(){
current -= step;
if (current == restartPosition){
current = 0;
}
$('#header').css("background-position",current+"px 0");
}
var init = setInterval("scrollBg()", scrollSpeed);
Currently it has settings for
$('#header').css("background-position",current+"px 0");
In a website I want to use this effect on #footer or #content background also. but with different speed and direction.
And is there any better and more optimized jquery method to achieve same effect?
And can we get same effect using CSS 3, without javascript?
Just saw the OP's answer, but decided to post anyway:
I've created a jQuery plugin to do this:
(function($) {
$.fn.scrollingBackground = function(options) {
// settings and defaults.
var settings = options || {};
var speed = settings.speed || 1;
var step = settings.step || 1;
var direction = settings.direction || 'rtl';
var animStep;
// build up a string to pass to animate:
if (direction === 'rtl') {
animStep = "-=" + step + "px";
}
else if (direction === 'ltr') {
animStep = '+=' + step + "px";
}
var element = this;
// perform the animation forever:
var animate = function() {
element.animate({
backgroundPosition: animStep + " 0px"
}, speed, animate);
};
animate();
};
})(jQuery);
Usage:
$("#header").scrollingBackground({
speed: 50,
step: 50,
direction: 'ltr'
});
This is pretty basic, and assumes that you're background-repeat is 'repeat-x' on the element you call it on. This way, there's no need to reset the background position every so often.
Working example: http://jsfiddle.net/andrewwhitaker/xmtpr/
I could work out the following solution. Am not sure if it is efficient. Will wait for anyone to comment or provide a better option.
Till then...:
var scrollSpeed = 70;
var step = 1;
var current = 0;
var images =
[
{
imageWidth:2247,
imagePath:"images/image1"
},
{
imageWidth:1200,
imagePath:"images/image2"
}
]
var headerWidth = 800;
var imageRotateCount = 0;
var imagesLength = images.length;
$('#header').css("background-image", images[0].imagePath);
function scrollBg(){
var curIndex = imageRotateCount%imagesLength;
var curImage = images[curIndex];
current -= step;
var restartPosition = -(curImage.imageWidth - headerWidth);
if (current == restartPosition){
current = 0;
imageRotateCount++;
curIndex = imageRotateCount%imagesLength;
curImage = images[curIndex];
$('#header').css("background-image", curImage.imagePath);
}
$('#header').css("background-position",current+"px 0");
}
var init = setInterval("scrollBg()", scrollSpeed);

Make javascript-snippet affect 3 divs instead of 1

I have this very usefull little piece of javascript that centers mig div. By i would like to make it apply to 3 divs on the same site, without repeating the same piece of code 3 times.
Any ideas on how to do it?
Putting all 3 divs into 1 divs that takes care of it, is not and option.
<script type="text/javascript">
<!--
function getWindowHeight() {
var windowHeight = 0;
if (typeof(window.innerHeight) == 'number') {
windowHeight = window.innerHeight;
}
else {
if (document.documentElement && document.documentElement.clientHeight) {
windowHeight = document.documentElement.clientHeight;
}
else {
if (document.body && document.body.clientHeight) {
windowHeight = document.body.clientHeight;
}
}
}
return windowHeight;
}
function setContent() {
if (document.getElementById) {
var windowHeight = getWindowHeight();
if (windowHeight > 0) {
var contentElement = document.getElementById('outer');
var contentHeight = contentElement.offsetHeight;
if (windowHeight < 570) {
contentElement.style.position = 'relative';
contentElement.style.top = '30px';
}
else if (windowHeight - contentHeight > 0) {
contentElement.style.position = 'relative';
contentElement.style.top = ((windowHeight / 2) - (contentHeight / 2)) + 'px';
}
else {
contentElement.style.position = 'static';
}
}
}
}
window.onload = function() {
setContent();
}
window.onresize = function() {
setContent();
}
//-->
</script>
Regards Troels
You don't need to check if document.getElementById exists. It has been supported since the Roman Empire.
Pass the id or the actual element that has to be centered to your function. That removes the dependency on a fixed element (#outer) in your case and makes it more flexible. Also try to name your functions to be indicative of what they are actually doing. setContent is a very generic name and doesn't indicate the centering aspect anywhere.
function centerElementWithId(id) {
..
var contentElement = document.getElementById(id);
..
}
Then call it thrice,
centerElementWithId('outer')
centerElementWithId('secondDiv')
centerElementWithId('thirdDiv');

Categories

Resources