Timers in a webpage are synchronous to times in phantomjs - javascript

I have a problem concerning phantomjs and timers. It seems that timers in a web page are synchronous to the times in pahntomjs, as a result you can't create nice gif which will show nice website animations (animations always use times).
Here is the code illustrating the problem:
test.phantom.js
var page = new WebPage();
page.open("test.html", function(){
var i = 0
setInterval(function(){
page.render('test-capture/'+i+'.gif', {format : "gif"});
i++;
if(i == 20)
phantom.exit();
}, 20);
});
test.html
<!doctype html>
<html>
<script>
var div;
window.onload = function(){
div = document.getElementById("t");
var times = 0;
setInterval(function(){
div.innerHTML = "" + (++times);
}, 1)
}
</script>
<body>
<div id="t">
0
</div>
</body>
</html>
As you can see phantomjs triggers a render call every 20 milliseconds, while the webpage changes the content of div#t every millisecond. You may expect that in the resulting 20 images the content of div#t will change with a step of 20 but this is not happening. I don't have enough reputation to post images, but the content in div#t is changing with a step of 1 millisecond.
Is this a bug or it should happen like this ? Thanks in advance.

This happens because javascript execution is single-threaded even if you have the page context and the outside context. The second thing is that rendering (gif) isn't cheap. On my machine it takes around 100 msec to render the gif on average. During that time, no javascript can be executed and time stands still.
So when you the rendering is complete, then both timers can continue to run. So the formula would be:
var pageContextAdvancement = Math.max(outsideIntervalDuration - timeToRender, 1);
So, no it's not possible to animate something with PhantomJS. It just isn't the right tool.
At least on my machine, the following seems to work, but this might change if the workload changes.
page.open("test.html", function(){
var i = 0
function run(){
page.render('test/'+i+'.gif', {format : "gif"});
i++;
if(i == 20)
phantom.exit();
setTimeout(run, 200);
}
setTimeout(run, 170);
});

Related

Constant reload of a DIV?

Ok, I've looked around Stack and other places for the past 4 or 5 hours trying to find a solution to my problem.
I have an Iframe inside of a page which contains 5 lines of information, the information is fetched from a database. Said info will constantly change, therefor a need it to be refreshed every 1-5 seconds, can stretch to 10 seconds if needs be.
I have used the below code, which works, but crashed my browser(s) for some reason, I'm guessing reloading too fast?
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.0/jquery.min.js"></script>
<script type="text/javascript">
var auto_refresh = setInterval(
function ()
{
$('#info').load('mid.php');
}, 5000); // refresh every 5000 milliseconds
</script>
Below is the code from mid.php (There is PHP inside the page but this is the part that I need refreshing).
<div id="info"><font size="2">
<b>Crimes: </b><font color="white"><?php if ($fetch->lastcrime <= time()){ echo 'Ready'; }else{ echo "".maketime($fetch->lastcrime).""; } ?></font><br>
<b>GTA: </b><font color="white"><?php if ($fetch->lastgta <= time()){ echo 'Ready'; }else{ echo "".maketime($fetch->lastgta).""; } ?></font><br>
<b>Chase: </b><font color="white"><?php if ($fetch->last_chase < time()){ echo 'Ready'; }else{ echo "".maketime($fetch->last_chase).""; } ?></font><br>
<b>Extortion: </b><font color="white"><?php if ($fetch->last_ext < time()){ echo 'Ready'; }else{ echo "".maketime($fetch->last_ext).""; } ?></font><br>
<b>Rank:</b><?php echo "$fetch->rank"; ?></td></tr>
</div>
</table>
I know I can use HTML to refresh the Iframe but it looks unsightly when the whole top left corner of the screen refreshes every 3 seconds, any help is much appreciated.
Thanks
I'd expect you to use Ajax calls for this kind of thing. You'd tonally ice jQuery to update the contents of elements in place to avoid the refresh of your iframe. Iframes are limited in their capabilities and it typically doesn't make sense to use them just for updating web page contents.
The browser crash may be coming from the use of set internal. If the calls take longer than 5 seconds to complete, multiple calls might stack up. But for your case I feel like it's not the problem, as it should be able to update that orange pretty quick. Any way, a better approach is to set a timer for one execution of your update process every time it gets done running. That way, if the call does take too long, you don't just keep stacking up requests.
Use can use .load() callback, substitute setTimeout() for setInterval
$(document).ready(function() {
let timeout;
let duration = 5000;
let stop = false;
function update() {
$("#info").load("mid.php", function() {
if (timeout) {
clearTimeout(timeout)
}
if (stop === false) {
timeout = setTimeout(update, duration)
}
});
}
update();
});
Thanks.
I ended up using pretty much the same script, just splitting the PHP and HTML into separate files and calling the div from the HTML file.

How do you refresh a page or certain content for a number of times and then stop?

I have a HTML page which has CSS animations and I wanted to know if there is a way where I wanted the page to reload 3 times and then stop it. Also when reloading it 3 times, for each time I want it to have a delay so for example the first time when my page loads it will play the animations and then after all the animations have been played I want it to reload again so some kind of a delay function?
Thank you.
Add this on page load.
<script>
var timeinmilliseconds = 3000;
var reloadCnt = window.sessionStorage.getItem( "reloadCounter") ? parseInt(window.sessionStorage.getItem( "reloadCounter")) + 1 : 1;
window.sessionStorage.setItem( "reloadCounter", reloadCnt )
console.log(reloadCnt);
if ( reloadCnt <= 3 )
setTimeout(function(){ window.location.reload(true) }, timeinmilliseconds);
</script>
Let me know if this helps. This is pure javascript, just add it to your page and let me know. Here is the link http://jsfiddle.net/

Automate html in Javascript/jQuery

I'm currently preparing a cool video presentation on my html web page. At the end of it, I want to be able to click on the video and be taken to a page - however I only want the link to come into effect at a certain time.
I've done some research and I can't find anything about this.
As an example, let's say that I want to make a link on something...
This link will go somewhere after 15 seconds
How can I make it so that <a> tag doesn't work for 15 seconds with jQuery or JavaScript? (JavaScript preferred but it doesn't really matter!). Remember - I don't want that whole line of code to suddenly appear - prior to the link working that should just be text!
Thanks!
Here delay is set to 3 seconds (3000 milliseconds in call to setTimeout). Change it to 15000 to make it 15 seconds
$(document).ready(function() {
setTimeout(convertTextToLink, 3000);
});
function convertTextToLink() {
$('#thanks').html('Thanks for watching. You may now proceed.');
}
Html
<h1>Hello</h1>
<p>here are your vids</p>
<div id="thanks">Thanks for watching</div>
var waiting = true;
//set waiting to false after 15 seconds
setTimeOut(function() { waiting = false },15000);
$('#automate').click(function(e) {
if(waiting === true) {
e.preventDefault(); //prevent the link from firing
}
});

Code being multiplied and all instances are running

My website works in a way so that any links clicked do not load a new page but however trigger a .load() event into a div named "content".
Everything has been nice and dandy but now I have run into a small problem.
On one of the content pages, I have the following code:
$('.count').each(function () {
$this = $(this);
countdown = setInterval(function(){
countnow = parseInt($('.remain', $this).html());
$('.remain', $this).html(countnow-1);
}, 1000);
return false;
});
The code works... it works very well. But when I load that same page again, it seems like the code is running twice because the seconds are going down by 2 at a time. Then when I load it again, it's going down by 3 seconds at a time. Another load, and it goes down by 4 seconds at a time. I load it a couple more times and it goes down faster then I can read.
I tried giving the .count divs their own unique id's (the .remain div is nested inside the .count div), even when pages are subsequently loaded the id is still entirely different and this did not fix my problem. I also tried putting clearInterval(countdown) right before the function but that just made it stop working entirely. Any suggestions?
And yes I know the countdown doesn't currently stop when it reaches 0.
Try this:
var countdown;
$('.count').each(function () {
$this = $(this);
if (!countdown)
countdown = setInterval(function(){
countnow = parseInt($('.remain', $this).html());
$('.remain', $this).html(countnow-1);
}, 1000);
return false;
});

JS Code running very slow

I am a JS novice so go easy on me here. But I wrote a simple slideshow and it seems to be running very slow. The code below takes about 2-4 seconds to load locally on my own machine. Wondering what is causing the delay. Let me know, thanks!
function slideshow(){
$("#1").animate({top: "50px",}, 500).delay(2000);
$("#1").animate({top: "400px",}, 500);
$("#2").animate({top: "50px",}, 500).delay(2000);
$("#2").animate({top: "400px",}, 500);
$("#3").animate({top: "50px",}, 500).delay(2000);
$("#3").animate({top: "400px",}, 500);
$("#4").animate({top: "50px",}, 500).delay(2000);
$("#4").animate({top: "400px",}, 500);
$("#5").animate({top: "50px",}, 500).delay(2000);
$("#5").animate({top: "400px",}, 500);
slideshow();
}
Each ID represents a different image.
The big problem with your code, since none of the other answers seem to have talked about it yet, is that the last line of slideshow() calls itself recursively, which will lead to a stack overflow. Don't do this:
function slideshow() {
// animate code
slideshow();
}
Instead, if you want it to run repeatedly, use setTimeout() to queue another execution of the function x milliseconds later:
function slideshow() {
// animate code
setTimeout(slideshow, 3500);
}
The way you had it, none of the functions ever actually finishes. With setTimeout(), each invocation of slideshow() does finish, and then a separate one runs after the specified delay. I'd make the delay big enough that the next invocation occurs after the current animations finish, otherwise you'll be queuing up more and more animations faster than they run.
UPDATE: jQuery maintains separate animation queues for each element, which means that the animations on your five elements will run simultaneously. Some of the other answers already provide ways of running the animations in sequence one at a time, but here is how I'd do it:
$(window).on("load",function() {
// cache a jQuery object containing the elements to animate
// (note you don't need their ids if you use their class)
var $imgs = $('img.slideshow-image'),
i = 0;
function slideShow() {
// start animation for "current" img
$imgs.eq(i).show(1)
.animate({top: "50px",}, 500)
.delay(2000)
.animate({top: "400px",}, 500)
.hide(1, function() {
i = (i+1) % $imgs.length;
setTimeout(slideShow, 500);
});
}
slideShow();
});
Working demo: http://jsfiddle.net/bARwb/
I've wrapped the code in a load handler both to remove the need for an inline onload= attribute and as a convenient way of keeping the code out of the global scope (if you do it this way don't forget to remove onload="slideShow()" from your body tag).
I've added .show() and .hide() calls (with a duration so that they join the animation queue) so that the img elements will have display:none in between animations because otherwise with your position:relative style you can't see any but the first (but changing to position:absolute would prevent them getting cropped by their parent's overflow:hidden).
When the animation finishes for an element, the callback from .hide() increments i to refer to the next element's index (but checks for when it goes past the last element) and then uses setTimeout() to queue the animation for that next element.
You have some duplication in there, and also some incorrect assumptions.
When you call .animate in jQuery, you can specify a callback that will be called when the animation is complete. This is the place to put your "next step".
So in this example:
animate the image
when complete, wait 2 seconds
after 2 seconds, animate the image
when complete, call the function with the next image
This is how it looks
var images = ['#1', '#2', '#3', '#4', '#5'];
function slideshow(index){
if (index >= images.length) {
index = 0;
}
var image = images[index];
$(image).animate({top: "50px",}, 500, function () {
window.setTimeout(function () {
$(image).animate({top: "400px",}, 500, function () {
slideshow(index + 1);
});
}, 2000);
});
}
my guess is that you are setting your frames to 2 seconds (2000). Try something speedier like 50 and see what you see. I'm not sure if that's the frame delay or the 500 but if either of those represents how long you are waiting between frame changes it's way too long.
Other than the intentional delays in your code, i do not see anything that would cause the slow loading. It may be the rest of the page. I would check to see how large your images are and any other files that may be downloading before the JavaScript slideshow function executes.
As a side note, it is strange that you call slideshow from within the slideshow function.
You could try something like this:
var intervalValue = setInterval( "slideshow()", 2000 );
var slideshow_imageindex = 1;
function slideshow()
{
//check if imageindex is greater than the number of images available (5 is an example)
if (slideshow_imageindex > 5)
{
slideshow_imageindex = 1;
}
//hide image below, change image src, then move image so that it is visible again
$("#1").animate({top: "400px",}, 500).attr('src','img/Slideshow-Audio-Trsfr'+slideshow_imageindex+'.png').animate({top: "50px",}, 500);
//increase image index
slideshow_imageindex++;
}
You will only need a single img (i kept your "id=#1" img), and every 2 seconds the image is hidden, it changes and the it is shown again. Only things you have to do: name the images so that only the number changes, like:
img/Slideshow-Audio-Trsfr1.png
img/Slideshow-Audio-Trsfr2.png
img/Slideshow-Audio-Trsfr3.png
img/Slideshow-Audio-Trsfr4.png
img/Slideshow-Audio-Trsfr5.png
and then use the number of images in the "if" within the function. It's late here in italy, hope i didn't forget anything :)

Categories