Sorry, if the title doesn't make too much sense, it's just that i don't even know what my problem is to begin trying to solve it. This code was meant to execute a function every second for 10 times that adds a div element, gives it a class, gives it a starting left position and starts moving it left. I've succeeded to create the div, give it a class and append it but where the problem comes in is making it move left.
I wanted to move it by having a variable that keeps track of the div left attribute, subtracting from that variable and always setting the divs left attribute to be equal to that variable, but it doesn't seem to be working correctly because all created divs follow one of that position tracking variable.
setInterval(function() {
var Count = 0;
var createddiv = document.createElement("div");
var divX = 1000;
if (Count < 1000) {
Count = Count + 100;
createddiv.classList.add("NewDiv");
createddiv.style.left = divX + "px";
document.body.appendChild(createddiv);
divX = divX - 100;
createddiv.style.left = divX + "px";
}
}, 1000)
From what I understand you want to move div from right to left in 10 seconds
JS
(function() {
var Count = 0;
var divX = 1000;
var createddiv;
var intervalRef = setInterval(function() {
if (Count < 1000) {
if(createddiv !== undefined) {
createddiv.parentNode.removeChild(createddiv);
}
createddiv = document.createElement("div");
Count = Count + 100;
createddiv.classList.add("NewDiv");
createddiv.style.left = divX + "px";
document.body.appendChild(createddiv);
divX = divX - 100;
createddiv.style.left = divX + "px";
} else {
clearInterval(intervalRef);
}
}, 1000);
})();
CSS
.NewDiv {
height: 100px;
width: 100px;
background-color: red;
position: relative;
}
Here is working demo in jsfiddle
Suggestion instead of creating new div every time, add one div and change it's left property.
Related
Im trying to make a javascript bookmark using The code I wrote. It's supposed to add an element (in this case it adds a div. The div is as large as the size of innerHeight and innerWidth. The height shrinks by a few pixels every 250 milliseconds. It works on CodePen, but when I try it on another website, it changes the entire HTML of the page to "white" (which is the background color of the added element). Here is the code:
var falseLoaderContainer = document.getElementsByTagName("html")[0];
falseLoaderContainer.innerHTML += `<div id="falseLoader"></div>`;
var falseLoader = document.getElementById("falseLoader");
falseLoader.style.position = `absolute`;
falseLoader.style.width = `${window.innerWidth}px`;
falseLoader.style.height = `${window.innerHeight}px`;
falseLoader.style.bottom = `0px`;
falseLoader.style.left = `0px`;
falseLoader.style.backgroundColor = `white`;
var falseLoaderHeight = falseLoader.style.height.replace(/px/g, "");
var updateFalseLoader = setInterval(function () {
falseLoaderHeight *= 1;
falseLoaderHeight -= Math.ceil(Math.random() * 4);
falseLoader.style.height = falseLoaderHeight + "px";
if (falseLoaderHeight <= 0) {
clearInterval(updateFalseLoader);
}
}, 250);
Try:
var element = document.getElementById("id");
element.setAttribute("style", "background-color: COLOR;");
or:
var element = document.getElementBYId("id");
element.style = "background-color: COLOR;");
Hope this helps!
I would like to fill an element with dots in random order. I have managed to write all the functionality, but I am not satisfied with the execution speed.
If I add all of the points using a while loop, the points just seem to appear all at the same time.
Therefore I add points one by one using a function that I call recursively with a timeout. This, on the other hand, appears too slow. Is there any chance to run a sequence of actions slower than in a loop but faster than setTimeout() can?
var dotCellSize;
var initialOffset;
var slotsHorizontally;
var slotsVertically;
var container;
var redDots;
var dots;
var newDotElement = $('<div class="dot">');
function randomInteger(min,max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function addDots()
{
if (!dots.length)
return;
var dotIndex = randomInteger(0, dots.length - 1);
var dot = dots[dotIndex];
dots.splice(dotIndex, 1);
var column = dot % slotsHorizontally;
var row = Math.floor(dot/slotsHorizontally);
var position = {
left: initialOffset + column*dotCellSize,
top: initialOffset + row*dotCellSize
};
var dotElement = newDotElement.clone().css(position);
if (-1 != redDots.indexOf(dot))
dotElement.addClass('red');
dotElement.appendTo(container);
setTimeout(function() {
addDots();
}, 1);
}
function generateDots(dotContainer, cellSize, numberOfRedDots)
{
container = dotContainer;
dotCellSize = cellSize;
dots = [];
redDots = [];
container.find('div.dot').remove();
numberOfRedDots = typeof numberOfRedDots !== 'undefined' ? numberOfRedDots : 3;
initialOffset = Math.floor(dotCellSize/2);
slotsHorizontally = Math.ceil(container.width()/dotCellSize);
slotsVertically = Math.ceil(container.height()/dotCellSize);
var numberOfSlots = slotsHorizontally*slotsVertically;
while (dots.length < numberOfSlots)
dots.push(dots.length);
while (redDots.length < numberOfRedDots)
{
var newRedDot = randomInteger(0, numberOfSlots - 1);
if (-1 == redDots.indexOf(newRedDot))
redDots.push(newRedDot);
}
addDots();
}
generateDots($('.dot-container'), 18, 15);
.dot {
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #C0E3EA;
position: absolute;
z-index: 1;
}
.dot.red {
background-color: #EF3D48;
}
.dot-container {
width: 420px;
height: 280px;
background-color: #333;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dot-container"></div>
Unfortunately, not really, this is because of how the browser engine decides to repaint the screen. Without the timeout, the browser engine recognizes it's going to do a bunch of updates (adding the dots to the DOM). Because repainting the screen is expensive, it waits to do as much as possible at one time, and, in your case, all of the dots show up at once. With the timeout added, each call to your function gets "deferred" for future execution.
This may or may not happen "right away" and is non-trivial to explain in detail so I would recommend watching this video https://www.youtube.com/watch?v=8aGhZQkoFbQ which explains the JS event loop or read some articles on browser reflow:
Minimizing browser reflow
What is Layout Thrashing?
Without changing much of what you've already done, one solution is to batch a few of the dots to be drawn together. I've added a for loop to your function which will make five dots get drawn together. Adjust this to 10, 20, or higher and you'll see the dots get painted even faster. I hope there is a number that you'll find suitable. I understand you may want to just speed up the drawing of every dot individually, but bear in mind that screens have refresh rates, so the faster you want the routine to finish the more they will appear in batches any way.
var dotCellSize;
var initialOffset;
var slotsHorizontally;
var slotsVertically;
var container;
var redDots;
var dots;
var newDotElement = $('<div class="dot">');
function randomInteger(min,max)
{
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function addDots()
{
if (!dots.length)
return;
for (let i = 0; i < 5; i++) {
var dotIndex = randomInteger(0, dots.length - 1);
var dot = dots[dotIndex];
dots.splice(dotIndex, 1);
var column = dot % slotsHorizontally;
var row = Math.floor(dot/slotsHorizontally);
var position = {
left: initialOffset + column*dotCellSize,
top: initialOffset + row*dotCellSize
};
var dotElement = newDotElement.clone().css(position);
if (-1 != redDots.indexOf(dot))
dotElement.addClass('red');
dotElement.appendTo(container);
}
setTimeout(function() {
addDots();
}, 1);
}
function generateDots(dotContainer, cellSize, numberOfRedDots)
{
container = dotContainer;
dotCellSize = cellSize;
dots = [];
redDots = [];
container.find('div.dot').remove();
numberOfRedDots = typeof numberOfRedDots !== 'undefined' ? numberOfRedDots : 3;
initialOffset = Math.floor(dotCellSize/2);
slotsHorizontally = Math.ceil(container.width()/dotCellSize);
slotsVertically = Math.ceil(container.height()/dotCellSize);
var numberOfSlots = slotsHorizontally*slotsVertically;
while (dots.length < numberOfSlots)
dots.push(dots.length);
while (redDots.length < numberOfRedDots)
{
var newRedDot = randomInteger(0, numberOfSlots - 1);
if (-1 == redDots.indexOf(newRedDot))
redDots.push(newRedDot);
}
addDots();
}
generateDots($('.dot-container'), 18, 15);
.dot {
width: 4px;
height: 4px;
border-radius: 50%;
background-color: #C0E3EA;
position: absolute;
z-index: 1;
}
.dot.red {
background-color: #EF3D48;
}
.dot-container {
width: 420px;
height: 280px;
background-color: #333;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="dot-container"></div>
Quickly profiling on my i7 3770k revealed that newDotElement.clone().css(position) took about .1 seconds. If you are running at 30 FPS, your frame time is .03 seconds. So you can see that Jquery clone is somewhat of a bottleneck.
However, your initial approach of drawing all the dots at once is sound, if you flag their styles to be "hidden". Then, when all the dots are added to the DOM, but are not visible, retrieve a list of their nodes (forgive the vanilla JS):
Array.from(document.getElementsByClassName("dot-container")[0].childNodes);
Now you can iterate over them and simply change their visibility style from "hidden" to "visible". As skyline3000 points out, the limit with setTimeout (or even requestAnimationFrame) is in the browser, and looping and setting one dot per iteration will take a little over 1 frame, which is actually a little slow. So you can write yourself a little abraction which per call will set a certain number of elements' visibility styles to "visible". By adjusting the quantity of dots you make visible per call, you will speed up or slow down the animation.
function showDots() {
var list = Array.from(document.getElementsByClassName("dot-container")[0].childNodes);
function draw(q) {
var e;
for (var i = 0; i < q; i++) {
if (list.length == 0) {
return;
}
e = list.shift();
e.style.visibility = "visible";
}
}
function callback() {
if (list.length == 0) {
return;
}
draw(4);
setTimeout(callback);
}
callback();
}
I have an an image moving across the screen and out of viewport, when the image reaches a particular absolute position (right: - 200), I want to trigger the below animation. I am relatively new to programming, not sure how to track when a particular function is done so that I can trigger the below animation.
var $startLessonButton = $('.startLessonButtonUp');
$startLessonButton.mouseup(function() {
$(this).addClass('animated slideInLeft');
});
---------
var movingOutAnimationCounter = 2;
var movingOutCurrentPosition = window.innerWidth / 2 - 200
function moveTrumpOut() {
movingOutCurrentPosition -= 2;
trumpyWrapper.style.right = movingOutCurrentPosition + 'px';
if (movingOutAnimationCounter < 9 ) {
trumpy.src = '../images/trump_walking_out_' + movingOutAnimationCounter + '.png';
movingOutAnimationCounter += 1;
} else {
movingOutAnimationCounter = 1;
trumpy.src = '../images/trump_walking_out_' + movingOutAnimationCounter + '.png';
}
if (movingOutCurrentPosition > -200 ) {
requestAnimationFrame(moveTrumpOut);
}
}
All the best!
If you know time, when moving element is hidden, you can use this function:
setTimeout(function(){ $('.elem').addClass("animCssClass") }, 1000);
Last parameter, in this example: 1000 is time in ms, when function inside should execute. Run this function on mouseup when you adding class to moving element.
I have a array of static images that I am using for an animation.
I have one frame image that I want to update the image of and I have seen a lot of tutorials on animating images with javascript just simply update the source of an image.
frame.src = animation[2].src; etc
When I look at the resource tracking in chrome, it doesnt look like they are getting cached even thought the web browser does download the image more than once but not once for each time it is displayed, so there is still some browser caching going on.
What is the best way to replace the frame image object with another image?
Well, you can either position all images absolute and give them a z-index, then use jQuery/JS to shuffle their z-indexes, bringing a new one to the top in a cross fader style,
or you can take all the id's and fadeone in slightly faster than the last one fades out.
Like so:
function fader(func) {
var currID = $('#mainimg ul').data('currLI');
var currLiStr = '#mainimg ul li#' + currID;
img = $(currLiStr).find('img').attr('src');
nextID = (currID == 'six') ? 'one' : $(currLiStr).next().attr('id');
nextLiStr = $('#mainimg ul li#' + nextID);
$(currLiStr).fadeOut(3000);
$(nextLiStr).fadeIn(2000).find('div.inner').delay(3000).fadeIn('slow').delay(6000).fadeOut('slow');
$('#mainimg ul').data('currLI',nextID);
}
Note 'six' is the id of the last li, reseting it back to one, but if you do $('#mainimg ul li:last').attr('id'); and $('#mainimg ul li:first').attr('id') to get the last and first id's, you can allow it to cope with any amount of images (obviously this is with li's given id's one, two and so on, but if you are finding out the last and first id you could use any structure.
Or you can set a ul width a width of all the li's multiplied, and give the li's the width of the images, and set overflow to hidden, then use JS to pull the li's left by the width of 1 li on each iteration in a slider like I have done here: http://www.reclaimedfloorboards.com/
There are loads of options
I ended up using jquery's replaceWith command and gave all the frames a class "frame" that i could select with $('.frame') which happened to only select visible frames.
<script type="text/javascript">
var animation = [];
var firstFrame = 1;
var lastFrame = 96;
var animationFrames = 16;
var loadedImageCount = 0;
$(function() {
$("button, input:submit",'#forecastForm').button();
$("#progressbar").progressbar({
value: 0
});
$('#id_Species').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
$('#id_Layer').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
$('#id_StartTime').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
$('#id_EndTime').attr('onChange', 'loadAnimation($(\'#id_Species\').val(),$(\'#id_Layer\').val(),$(\'#id_StartTime\').val(),$(\'#id_EndTime\').val())' )
});
if (document.images) { // Preloaded images
loadAnimation('Dry_GEM',1,1,96);
}
function rotate(animation, frame)
{
if (frame >= animation.length)
frame = 0;
$('.frame').replaceWith(animation[frame]);
window.setTimeout('rotate(animation,'+eval(frame+1)+')',150);
}
function loadAnimation(species, layer, startTime, endTime)
{
layer = Number(layer);
startTime = Number(startTime);
endTime = Number(endTime);
if (startTime > endTime)
{
swap = startTime;
startTime = endTime;
endTime = swap;
delete swap;
}
for (i=0;i<animation.length;i++)
delete animation[i];
delete animation;
animation = []
$('#progressbar').progressbar({value: 0});
loadedImgCount = 0;
animationFrames = endTime - startTime + 1;
for(i=0;i < animationFrames;i++)
{
animation[i] = new Image();
animation[i].height = 585;
animation[i].width = 780;
$(animation[i]).attr('class','frame');
animation[i].onload = function()
{
loadedImgCount += 1;
$('#progressbar').progressbar({value: eval(loadedImgCount / animationFrames * 100)});
};
animation[i].src = 'http://[[url]]/hemi_2d/' + species + '_' + layer + '_' + eval(i+startTime) + '.png';
}
}
</script>
The easiest way to do it is create a separate hidden image for each frame. Something like this:
var nextImage = (function(){
var imagePaths='basn0g01.png,basn0g02.png,basn0g04.png,basn0g08.png'.split(','),
imageHolder=document.getElementById('custom-header'),
i=imagePaths.length, imageIndex=i-1, img;
for (;i--;) {
img=document.createElement('img');
img.src='http://www.schaik.com/pngsuite/' + imagePaths[i];
if (i) img.style.display='none';
imageHolder.appendChild(img);
}
return function(){
imageHolder.childNodes[imageIndex].style.display='none';
if (++imageIndex >= imageHolder.childNodes.length) imageIndex=0;
imageHolder.childNodes[imageIndex].style.display='inline-block';
}
}());
Try this example on this page; paste it in the console and then call nextImage() a few times. Watch the top of the page.
edit
If you already have all the images in your HTML document, you can skip most of the above and just do something like this:
var nextImage = (function(){
var imageHolder=document.getElementById('custom-header'),
images=imageHolder.getElementsByTagName('img'),
i=images.length, imageIndex=0, img;
for (;i--;) if (i) images[0].style.display='none';
return function(){
imageHolder.childNodes[imageIndex].style.display='none';
if (++imageIndex >= imageHolder.childNodes.length) imageIndex=0;
imageHolder.childNodes[imageIndex].style.display='inline-block';
}
}());
I'm hopeless at Javascript. This is what I have:
<script type="text/javascript">
function beginrefresh(){
//set the id of the target object
var marquee = document.getElementById("marquee_text");
if(marquee.scrollLeft >= marquee.scrollWidth - parseInt(marquee.style.width)) {
marquee.scrollLeft = 0;
}
marquee.scrollLeft += 1;
// set the delay (ms), bigger delay, slower movement
setTimeout("beginrefresh()", 10);
}
</script>
It scrolls to the left but I need it to repeat relatively seamlessly. At the moment it just jumps back to the beginning. It might not be possible the way I've done it, if not, anyone have a better method?
Here is a jQuery plugin with a lot of features:
http://jscroller2.markusbordihn.de/example/image-scroller-windiv/
And this one is "silky smooth"
http://remysharp.com/2008/09/10/the-silky-smooth-marquee/
Simple javascript solution:
window.addEventListener('load', function () {
function go() {
i = i < width ? i + step : 1;
m.style.marginLeft = -i + 'px';
}
var i = 0,
step = 3,
space = ' ';
var m = document.getElementById('marquee');
var t = m.innerHTML; //text
m.innerHTML = t + space;
m.style.position = 'absolute'; // http://stackoverflow.com/questions/2057682/determine-pixel-length-of-string-in-javascript-jquery/2057789#2057789
var width = (m.clientWidth + 1);
m.style.position = '';
m.innerHTML = t + space + t + space + t + space + t + space + t + space + t + space + t + space;
m.addEventListener('mouseenter', function () {
step = 0;
}, true);
m.addEventListener('mouseleave', function () {
step = 3;
}, true);
var x = setInterval(go, 50);
}, true);
#marquee {
background:#eee;
overflow:hidden;
white-space: nowrap;
}
<div id="marquee">
1 Hello world! 2 Hello world! 3 Hello world!
</div>
JSFiddle
I recently implemented a marquee in HTML using Cycle 2 Jquery plugin :
http://jquery.malsup.com/cycle2/demo/non-image.php
<div class="cycle-slideshow" data-cycle-fx="scrollHorz" data-cycle-speed="9000" data-cycle-timeout="1" data-cycle-easing="linear" data-cycle-pause-on-hover="true" data-cycle-slides="> div" >
<div> Text 1 </div>
<div> Text 2 </div>
</div>
HTML5 does not support the tag, however a lot of browsers will still display the text "properly" but your code will not validate. If this isn't an issue for you, that may be an option.
CSS3 has the ability, supposedly, to have marquee text, however because anyone that knows how to do it believes it's a "bad idea" for CSS, there is very limited information that I have found online. Even the W3 documents do not go into enough detail for the hobbyist or self-teaching person to implement it.
PHP and Perl can duplicate the effect as well. The script needed for this would be insanely complicated and take up much more resources than any other options. There is also the possibility that the script would run too quickly on some browsers, causing the effect to be completely negated.
So back to JavaScript - Your code (OP) seems to be about the cleanest, simplest, most effective I've found. I will be trying this. For the seamless thing, I will be looking into a way to limit the white space between end and beginning, possibly with doing a while loop (or similar) and actually run two of the script, letting one rest while the other is processing.
There may also be a way with a single function change to eliminate the white space. I'm new to JS, so don't know off the top of my head. - I know this isn't a full-on answer, but sometimes ideas can cause results, if only for someone else.
This script used to replace the marquee tag
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('.scrollingtext').bind('marquee', function() {
var ob = $(this);
var tw = ob.width();
var ww = ob.parent().width();
ob.css({ right: -tw });
ob.animate({ right: ww }, 20000, 'linear', function() {
ob.trigger('marquee');
});
}).trigger('marquee');
});
</script>
<div class="scroll">
<div class="scrollingtext"> Flash message without marquee tag using javascript! </div>
</div>
Working with #Stano code and some jQuery I have created a script that will replace the old marquee tag with standard div. The code will also parse the marquee attributes like direction, scrolldelay and scrollamount.
Here is the code:
jQuery(function ($) {
if ($('marquee').length == 0) {
return;
}
$('marquee').each(function () {
let direction = $(this).attr('direction');
let scrollamount = $(this).attr('scrollamount');
let scrolldelay = $(this).attr('scrolldelay');
let newMarquee = $('<div class="new-marquee"></div>');
$(newMarquee).html($(this).html());
$(newMarquee).attr('direction',direction);
$(newMarquee).attr('scrollamount',scrollamount);
$(newMarquee).attr('scrolldelay',scrolldelay);
$(newMarquee).css('white-space', 'nowrap');
let wrapper = $('<div style="overflow:hidden"></div>').append(newMarquee);
$(this).replaceWith(wrapper);
});
function start_marquee() {
let marqueeElements = document.getElementsByClassName('new-marquee');
let marqueLen = marqueeElements.length
for (let k = 0; k < marqueLen; k++) {
let space = ' ';
let marqueeEl = marqueeElements[k];
let direction = marqueeEl.getAttribute('direction');
let scrolldelay = marqueeEl.getAttribute('scrolldelay') * 100;
let scrollamount = marqueeEl.getAttribute('scrollamount');
let marqueeText = marqueeEl.innerHTML;
marqueeEl.innerHTML = marqueeText + space;
marqueeEl.style.position = 'absolute';
let width = (marqueeEl.clientWidth + 1);
let i = (direction == 'rigth') ? width : 0;
let step = (scrollamount !== undefined) ? parseInt(scrollamount) : 3;
marqueeEl.style.position = '';
marqueeEl.innerHTML = marqueeText + space + marqueeText + space;
let x = setInterval( function () {
if ( direction.toLowerCase() == 'left') {
i = i < width ? i + step : 1;
marqueeEl.style.marginLeft = -i + 'px';
} else {
i = i > -width ? i - step : width;
marqueeEl.style.marginLeft = -i + 'px';
}
}, scrolldelay);
}
}
start_marquee ();
});
And here is a working codepen
I was recently working on a site that needed a marquee and had initially used the dynamic marquee, which worked well but I couldn't have the text begin off the screen. Took a look around but couldn't find anything quite as simple as I wanted so I made my own:
<div id="marquee">
<script type="text/javascript">
let marquee = $('#marquee p');
const appendToMarquee = (content) => {
marquee.append(content);
}
const fillMarquee = (itemsToAppend, content) => {
for (let i = 0; i < itemsToAppend; i++) {
appendToMarquee(content);
}
}
const animateMarquee = (itemsToAppend, content, width) => {
fillMarquee(itemsToAppend, content);
marquee.animate({left: `-=${width}`,}, width*10, 'linear', function() {
animateMarquee(itemsToAppend, content, width);
})
}
const initMarquee = () => {
let width = $(window).width(),
marqueeContent = "YOUR TEXT",
itemsToAppend = width / marqueeContent.split("").length / 2;
animateMarquee(itemsToAppend, marqueeContent, width);
}
initMarquee();
</script>
And the CSS:
#marquee {
overflow: hidden;
margin: 0;
padding: 0.5em 0;
bottom: 0;
left: 0;
right: 0;
background-color: #000;
color: #fff;
}
#marquee p {
white-space: nowrap;
margin: 0;
overflow: visible;
position: relative;
left: 0;
}