This question already has answers here:
JS function named `animate` doesn't work in Chrome, but works in IE
(3 answers)
Closed 6 years ago.
This is really simple code that I wanted to try and get running because I wanted to learn some JavaScript basics. The code works in Internet Explorer and Firefox but not on chrome. I feel like I must be missing something really stupid.
var frame = 2;
function animate(){
if(frame == 1){
frame = frame + 1;
document.getElementById("animate").src = "walking1.png";
}
else if (frame == 2){
frame = frame + 1;
document.getElementById("animate").src = "walking2.png";
}
else{
frame = 1;
document.getElementById("animate").src = "walking3.png";
}
}
<p> clicking the button will change the image.</p>
<img id="animate" src="walking1.png">
<button onclick="animate()">click me to animate</button>
the pictures used are saved in the same folder.
animate is used both as a function name and an id, which cause it to not work in Chrome.
Also, mentioned in this post, a function alone with the name animate might also not work in Chrome, based on how it is implemented. (see notes below)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script type="text/javascript">
var frame = 2;
function animatee(){
if(frame == 1){
frame = frame + 1;
document.getElementById("animate").src = "http://placehold.it/100";
}
else if (frame == 2){
frame = frame + 1;
document.getElementById("animate").src = "http://placehold.it/100/f00";
}
else{
frame = 1;
document.getElementById("animate").src = "http://placehold.it/100/00f";
}
}
</script>
</head>
<body>
<p> clicking the button will change the image.</p>
<img id="animate" src="http://placehold.it/100/0f0">
<button onclick="animatee();">click me to animate</button>
</body>
</html>
Notes:
An observation made by guest271314 shows that if the onclick handler is not attached inline, the issue is not present
window.onload = function() {
var frame = 2;
function animate() {
console.log("animate called")
if (frame == 1) {
frame = frame + 1;
document.getElementById("animatee").src = "http://placehold.it/100x100";
} else if (frame == 2) {
frame = frame + 1;
document.getElementById("animatee").src = "http://placehold.it/200x200";
} else {
frame = 1;
document.getElementById("animatee").src = "http://placehold.it/100/00f";
}
}
document.querySelector("button").onclick = animate;
}
<p> clicking the button will change the image.</p>
<img id="animatee" src="http://placehold.it/100/0f0">
<button>click me to animate</button>
To their defense Kaiido contributed with the specs: https://html.spec.whatwg.org/#named-access-on-the-window-object
Knu contributed with this bug report:https://www.w3.org/Bugs/Public/show_bug.cgi?id=11960
Related
I am busy making a memory game, where an image is to be displayed to the user, and after some 10 seconds of the image flashing, it should hide and four options are to be shown for the user to choose either the correct or incorrect answer.
So far, all I have accomplished is to load the images and cycle through all the puzzles that my code can find.
What I'm trying to do now is to make the image flash and hide after some time, while also just refreshing that section of the page, and not the entire page.
I am using C# and a user control on my page.
What I have tried so far is only
<script>
var x;
function BlinkImage() {
x = 1;
setInterval(change, 2000);
}
function change() {
if (x === 1) {
var image = document.getElementById('<%=imgMain.ClientID %>');
image.visible = false;
x = 2;
}
else {
var image = document.getElementById('<%=imgMain.ClientID %>');
image.visible = true;
x = 1;
}
}
</script>
And on loading my puzzle for that instance (in code behind)
Page.ClientScript.RegisterStartupScript(typeof(game), "Start", "<script language=javascript> BlinkImage(); </script>");
Which does fire, as I can step through the code in debugging on Firefox. But my image does not flash or blink. I understand I am just using visiblity as my "blinker". I don't know what else to use exactly.
What can I do to make the image flash or blink for, say 20 seconds, then hide the image after that time has passed? Then repeat the process once the user has made a choice.
You can try the following (comments in code):
var blinkInterval = setInterval(change, 2000), // set the interval into a variable
image = document.getElementById('test'), // replace test with your client id: <%=imgMain.ClientID %>
x = 1;
function change() {
if (x % 2 === 1) { // see if it is odd or even by modding by 2 and getting remainder
image.style.display = 'none';
} else {
image.style.display = 'block';
}
x++; // increment x
if (x === 10) { // should have happened 10 times (which is 20 seconds with your intervals being at 2 seconds)
clearInterval(blinkInterval); // clear the interval (should end hidden as odd is display none and we clear beforethe 20th is run)
}
}
<div id="test">test</div>
After the code has finished, wherever the user is making their selection, you just need to reset the blinkInterval variable:
blinkInterval = setInterval(change, 2000); // notice no need for the var declaration when you reset this
Use style attribute and change if visible/hidden
function change() {
var image = document.getElementById('<%=imgMain.ClientID %>');
//check if visible
if (image.style.visibility=="visible") {
image.style.visibility="hidden";
}
else {
image.style.visibility="visible";
}
}
;
Try this:
function flashAndHide(img_id){
var img = $("#"+img_id);
var x = 0;
var inter = setInterval(function(){
if(x % 2 == 0){
img.hide();
}else{
img.show();
}
x += 1;
}
},1000);
if(x === 20){
img.hide();
clearInterval(inter);
}
}
Haven't tested this, but it should work,
I am trying to clone the following site:
https://www.apple.com/mac-pro/
I am still in the prototyping phase and the big ticket item I am trying to figure out is how they are playing their MP4 file backwards when you scroll up the page. If you scroll down the page a few steps and then back up, you will see what I mean.
So far I have tried the following techniques:
Tweening currentTime property of video element
Using requestAnimationFrame and using the timestamp in the callback to update the currentTime property to the desired value
Using the requestAnimationFrame technique, I am now getting a partially usable result in every browser other than Chrome. Chrome is ok if you want to rewind maybe .5 seconds, but any more than that and it will get jumpy.
I have also made the following discoveries:
Chrome hates trying to rewind an MP4 file
As much as Chrome hates rewinding MP4 files, also make sure that you don't have an audio track on your video file. It will make it even slower.
So I feel I have a pretty good understanding of the options available to me, but the one thing that makes me think I am missing something is that the Apple website functions ok in Chrome.
I have started debugging their code which is located at:
https://images.apple.com/v/mac-pro/home/b/scripts/overview.js
And from what I can tell they seem to be using requestAnimationFrame, but I can't understand why they are getting a better result.. Does anyone have any ideas on how to achieve this effect?
BTW - I understand that videos are not really meant to be played backwards and they will never play predictably backwards. I have even had occasions on the Apple website where the rewinding can be jerky. But they still have good 2-3 second rewind transitions and the result is definitely acceptable.
Here is my relevant javascript and HTML so far..
var envyVideo, currentVideoTrigger = 0,
currentIndicator, startTime, vid, playTimestamp, playTo, playAmount, triggeredTime, rewindInterval;
$(function() {
vid = document.getElementById("envy-video");
$("#play-button").click(function() {
vid.play();
});
$("#rewind-button").click(function() {
vid.pause();
playTo = parseFloat($("#play-to-time").val());
playAmount = playTo - vid.currentTime;
triggeredTime = vid.currentTime;
requestAnimationFrame(rewindToPointInTime);
});
});
function rewindToPointInTime(timestamp) {
if (!playTimestamp) playTimestamp = timestamp;
var timeDifference = (timestamp - playTimestamp) / 1000;
vid.currentTime = triggeredTime + (playAmount * (timeDifference / Math.abs(playAmount)));
if (vid.currentTime > playTo) {
requestAnimationFrame(rewindToPointInTime);
} else {
playTimestamp = null;
playAmount = null;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rhino Envy</title>
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
<script src="./js/envy.js"></script>
<link rel="stylesheet" href="./css/envy.css">
</head>
<body;
<div id="envy-video-container">
<video id="envy-video" src="./videos/prototype_animation.mp4"></video>
</div>
<div id="video-controls">
<p id="video-current-time"></p>
<div class="video-control"><button id="rewind-button">rewind to</button><input type="text" id="play-to-time" placeholder="forward time" value="0"></div>
<button id="play-button">play</button>
</div>
<ul id="envy-steps">
<li id="envy-step-indicator-1"></li>
<li id="envy-step-indicator-2"></li>
<li id="envy-step-indicator-3"></li>
</ul>
<section id="envy-full-range">
<div id="envy-1-door-link"></div>
<div id="envy-2-door-link"></div>
<div id="envy-3-door-link"></div>
</section>
</body>
</html>
One solid way I can think of, would be to use two videos : one in normal direction, and the other one reversed.
You could then simply switch between which video is to be played, and only update the currentTime of the hidden one in the background.
With this solution, you can even rewind audio !
To reverse a video, you can use ffmpeg's command
ffmpeg -i input.mp4 -vf reverse -af areverse reversed.mp4
Note: You may feel some gaps at the switch, which could probably be leveraged by using a single visible video element, fed from the other's element streams, but I'll leave it for an update, I'm short on time r.n.
const vids = document.querySelectorAll('video');
vids.forEach(v => {
v.addEventListener('loadedmetadata', canplay);
v.addEventListener('timeupdate', timeupdate);
});
let visible = 0;
function timeupdate(evt) {
if (this !== vids[visible]) return;
let other = (visible + 1) % 2;
vids[other].currentTime = this.duration - this.currentTime;
}
document.getElementById('switch').onclick = e => {
visible = (visible + 1) % 2;
show(vids[visible]);
}
// waith both vids have loaded a bit
let loaded = 0;
function canplay() {
if (++loaded < vids.length) return;
hide(vids[1]);
show(vids[0]);
}
function show(el) {
el.muted = false;
const p = el.play();
el.style.display = 'block';
const other = vids[(visible + 1) % 2];
// only newest chrome and FF...
if (p && p.then) {
p.then(_ => hide(other));
} else {
hide(other);
}
}
function hide(el) {
el.muted = true;
el.pause();
el.style.display = 'none';
}
document.getElementById('pause').onclick = function(e) {
if (vids[visible].paused) {
this.textContent = 'pause';
vids[visible].play();
} else {
this.textContent = 'play';
vids[visible].pause();
}
}
<button id="switch">switch playing direction</button>
<button id="pause">pause</button>
<div id="vidcontainer">
<video id="normal" src="https://dl.dropboxusercontent.com/s/m2htty4a8a9fel1/tst.mp4?dl=0" loop="true"></video>
<video id="reversed" src="https://dl.dropboxusercontent.com/s/lz85k8tftj2j8x6/tst-reversed.mp4?dl=0" loop="true"></video>
</div>
I was looking in other posts for the answer, but the answers never seem to work in my favor. I'm trying to make an image fade when the page finishes loading. I've figured out I can loop until the counter reaches 0 (when image is invisible) and fade the image slowly.
The problem is, the setTimeout() function doesn't seem to be working.
Here's the code:
function timeout() {
setTimeout(function () {
//A comment said something about looping,
//but it was confusing to understand...
}, 50);
}
function setup() {
var load = document.getElementById('img');
load.style.opacity = 0 //Start at being visible
for (var i = 10; i > 0; i = i - 0.1) { //For loop
load.style.opacity = i; //Use the index variable and use that to set the opacity
setTimeout(); //Set the timeout, but this function does not pause the program for some reason...
//I need to pause for 0.05 seconds.
}
}
window.addEventListener('load', setup, true); //Add event listener for when the page is done loading
<!DOCTYPE html>
<html>
<head>
<title>Webpage</title>
</head>
<body>
<div id="img">
<img src="http://www.downgraf.com/wp-content/uploads/2014/09/01-progress.gif" width="200" height="150">
</div>
</body>
</html>
I put the javascript in a seperate file, I just can't access it from Stack Overflow...
Can someone help? And also, sometimes the image can be finicky at times as well, like sometimes it won't hide like it's supposed to do. Thanks!
You declared a setTimeout without arguments, hence the error:
'Window': 1 argument required, but only 0 present."
Give it the appropriate amount of arguments:
for (var i = 10; i > 0; i = i - 0.1) { //For the loop
load.style.opacity = i;
setTimeout(functionName, milliseconds);
}
If you intended to use your timeout() function instead, call it. You're just instantiating a new setTimeout from the one you already created in the timeout() function.
You can use a recursive function instead of a loop
var load = document.getElementById('img');
function setup() {
load.style.opacity = "1"; //Start at being visible
timeout(1);
}
function timeout(i) {
setTimeout(function() {
i -= 0.1;
if(i<=0)
return;
load.style.opacity = i.toString();
timeout(i);
}, 200);
}
window.addEventListener('load', setup, true); //Add event listener for when the page is done loading
<!DOCTYPE html>
<html>
<head>
<title>Webpage</title>
</head>
<body>
<div>
<img src="http://www.downgraf.com/wp-content/uploads/2014/09/01-progress.gif" width="200" height="150" id="img">
</div>
</body>
</html>
Basically you want to countdown the opacity with a recursive call. Here we are going from 1 down to 0 in 0.01 increments. The setTimeout will trigger the next recursive call after pausing for 50 msecs. These values, can of course, be adjusted as needed but the opacity needs to be a number from 1 (visible) to 0 (invisible).
function setOpacity(el, lvl) {
el.style.opacity = lvl;
}
function countDown(el, lvl) {
function action(el, lvl) {
return function () {
countDown(el, lvl);
}
}
setOpacity(el, lvl);
if (lvl > 0) {
lvl -= 0.01
setTimeout(action(el, lvl), 50);
}
}
function setup() {
var load = document.getElementById('img');
load.style.opacity = 1; //Start at being visible
countDown(load, 1);
}
window.addEventListener('load', setup, true);
<!DOCTYPE html>
<html>
<head>
<title>Webpage</title>
</head>
<body>
<div id="img">
<img src="http://www.downgraf.com/wp-content/uploads/2014/09/01-progress.gif" width="200" height="150">
</div>
</body>
</html>
function setup() {
var load = document.getElementById('img');
(function(){
var i = 1;
setTimeout(function () {
i -= 0.1;
load.style.opacity = i;
if (i > 0) {
setTimeout(arguments.callee, 100);
}
}, 100);
})();
}
window.addEventListener('load', setup, true); //Add event listener for when the page is done loading
<div id="img">
<img src="http://www.downgraf.com/wp-content/uploads/2014/09/01-progress.gif" width="200" height="150">
</div>
Here is a small part of a website that I'm experimenting with. Anyway I'm learning Javascript and I decided to experiment by making an extremely simple "slideshow", but whenever I run this in the browser (Mozilla Firefox 42), the browser crashes. I'm wondering if anyone could tell me whats wrong or possibly give me a better way of making this(I'm sure there is but I couldn't find one). Also I know I can make this in jQuery but I want to try this out with pure Javascript.
I have also tried this on Chrome and Opera.
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">
//I will use javascript to make the "slideshow" on mainSection
function loop() {
var BACKGROUND = document.getElementById("Introduction");
var SECTION1 = document.getElementById("mainSection");
var SECTION2 = document.getElementById("section2");
var SECTION3 = document.getElementById("section3");
var i = 1;
while (i <= 3) {
i = i + 0.0001;
SECTION1.style.display="block";
SECTION2.style.display="none";
SECTION3.style.display="none";
}
while (i <= 6) {
i = i + 0.0001;
SECTION1.style.display="none";
SECTION2.style.display="block";
SECTION3.style.display="none";
}
while (i <= 9) {
i = i + 0.0001;
SECTION1.style.display="none";
SECTION2.style.display="none";
SECTION3.style.display="block";
}
while (i = 9) {
i = 1;
}
}
</script>
</head>
<body onload="loop();">
<header id="Introduction">
<section id="mainSection">
<h1>Welcome to the Ipsum Hotel.</h1>
<p>This is where thought and precision goes<br />
towards the comfort of our customers.<br /></p>
</section>
<!--This will be used to make a slideshow-->
<section id="section2">
<p><strong>Free Wifi!</strong></p>
<p>Free wifi is included in all of our guest<br />
packages from Economy to Deluxe<br /></p>
</section>
<section id="section3">
<p><strong>Free Hot Breakfast</strong></p>
<p>Included with any of our guest packages is<br />
a hearty breakfast. You can also get a personalized<br />
omelet at our omelet bar.<br /></p>
</section>
</header>
</body>
</html>
Try using setInterval. As mentioned in the comments, a while loop will block all page operations and tax your CPU. setInterval is designed specifically for handling timing operations in a more resource-friendly manner.
var SECTION1 = document.getElementById("mainSection");
var SECTION2 = document.getElementById("section2");
var SECTION3 = document.getElementById("section3");
var sections = [SECTION1, SECTION2, SECTION3];
var activeSection = 0;
setInterval(function() {
// If we are past the end of list, reset to first element
if (activeSection >= sections.length) {
activeSection = 0;
}
// Mark only the activeSection as visible
sections.forEach(function(section, idx) {
section.style.display = activeSection === idx ? 'block' : 'none';
});
activeSection += 1;
}, 3000);
This will loop over each section every three seconds (at the least, see https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval for more info about how timers work in the browser). Once the last section is reached, it resets to the first section.
I am using javascript to periodically replace a .png picture, which ist viewed fullscreen as the only content of a site. No matter how I try, in Firefox, after being loaded (as seen via firebug), the new image is always drawn from top to bottom. This takes some seconds. Is there any way to prevent this and show the picture all at once?
This is my current javascript code:
function preloadScreenshotPeriodically(){
var new_screenshot = new Image();
new_screenshot.src = "screenshot.png?defeat_firefox_caching=" + counter;
new_screenshot.id = "screenshot";
counter = counter + 1;
new_screenshot.onload = function(){
loadScreenshot(new_screenshot);
setTimeout("preloadScreenshotPeriodically();", 5000);
};
}
function loadScreenshot(new_screenshot){
document.getElementById("screenshot").parentNode.replaceChild(new_screenshot, document.screenshot);
}
I also tried to use two images, one of them hidden. Then loading the picture in the hidden one and swapping them. Same results :/
In an other version, I fetched the image with Ajax and after loading is complete, changed the url of the img-tag. My hope was, that the browser would recognize the picture had already been loaded and fetch it from the browsercache rather than loading it. But this didn't happen and I ended up with two requests to the server for one picture and the same slow drawing of it as in my other trys.
edit:
Now I tried it like suggested in answer 1. While it works just fine if I switch the picture when I load the next one (I don't want this), trying to switch it as soon as it is loaded (what I want) results in a blank window (very short) and visible loading of the picture as described above.
this works:
<body>
<style type="text/css">
#loaderWin { display:block; height:1px; width:1px; overflow:hidden; }
</style>
<div id="imagewin"></div>
<div id="loaderWin"></div>
<script type="text/javascript">
var screenshotCount=0;
function showFirstImage() {
loadNextImage();
}
function showNewImage() {
loadNextImage();
}
function nextImageLoaded() {
// swapImage();
}
function loadNextImage() {
swapImage();
screenshotCount = screenshotCount +1;
var nextImage = "<img id='loaderWinImg' src='screenshot.png?x="+screenshotCount+"' onload='nextImageLoaded()' />";
document.getElementById('loaderWin').innerHTML = nextImage;
}
function swapImage() {
document.getElementById("loaderWinImg").onload = '';
var newimage=document.getElementById('loaderWin').innerHTML;
document.getElementById('imagewin').innerHTML = newimage;
}
var showImages = setInterval("showNewImage()",15000);
showFirstImage();
</script>
</div>
</body>
</html>
this doesn't work:
<body>
<style type="text/css">
#loaderWin { display:block; height:1px; width:1px; overflow:hidden; }
</style>
<div id="imagewin"></div>
<div id="loaderWin"></div>
<script type="text/javascript">
var screenshotCount=0;
function showFirstImage() {
loadNextImage();
}
function showNewImage() {
loadNextImage();
}
function nextImageLoaded() {
swapImage();
}
function loadNextImage() {
screenshotCount = screenshotCount +1;
var nextImage = "<img id='loaderWinImg' src='screenshot.png?x="+screenshotCount+"' onload='nextImageLoaded()' />";
document.getElementById('loaderWin').innerHTML = nextImage;
}
function swapImage() {
// loadNextImage();
document.getElementById("loaderWinImg").onload = '';
var newimage=document.getElementById('loaderWin').innerHTML;
document.getElementById('imagewin').innerHTML = newimage;
}
var showImages = setInterval("showNewImage()",15000);
showFirstImage();
</script>
</div>
</body>
</html>
The problem can be seen here (in firefox problem like described above, in chrome there are no pauses between pictureloads and there is a blank window in between picture changes): http://sabine-schneider.silbe.org:1666/test.html
And here, what Rob suggested in answer 1 without any changes (displays the picture fine in firefox, but not in chrome - there I get a blank window in between picture changes): http://sabine-schneider.silbe.org:1666/test0.html
sounds like the image is "progressive" ( interlaced) and the preload needs more time for it to complete download.
You can set a width and height to the image also for a more stable presentation
( poss )
using
?defeat_firefox_caching=" + counter;
means you never cache the image ( which has confused me about your question ) - remove that line( unless you need it for something you haven't mentioned)
update: Can you try ...
<style type="text/css">
#loaderWin { display:block; height:1px; width:1px; overflow:hidden; }
</style>
<div id="imagewin"></div>
<div id="loaderWin"></div>
<script type="text/javascript">
var screenshotCount=0;
function showNewImage() {
screenshotCount = screenshotCount +1;
var newimage=document.getElementById('loaderWin').innerHTML;
document.getElementById('imagewin').innerHTML = newimage;
var nextImage = "<img src='screenshot.png?defeat_firefox_caching="+screenshotCoun+"'/>";
document.getElementById('loaderWin').innerHTML = nextImage;
}
var showImages = setInterval("showNewImage()",5000);
</script>