I'm currently using setInterval( () => {}, 16 ) to run my code 60fps, but this makes the code run at 62.5fps, which makes the game movements jump forward twice the speed for a few frames per second. Using interval 17 makes the game movement freeze for a frame every once in a while.
How can I run the code truly at 60fps for maximum smoothness?
use Window.requestAnimationFrame([callback])
That way your application will be called when it's time to render, wether the monitor is 30hz, 60hz or 120hz or more.
See this example from https://css-tricks.com/using-requestanimationframe/ on how to use it if the MDN documentation isn't clear enough.
var globalID;
function repeatOften() {
$("<div />").appendTo("body");
globalID = requestAnimationFrame(repeatOften);
}
globalID = requestAnimationFrame(repeatOften);
$("#stop").on("click", function() {
cancelAnimationFrame(globalID);
});
$("#start").on("click", function() {
globalID = requestAnimationFrame(repeatOften);
});
div {
width: 10px;
height: 10px;
background: orange;
float: left;
}
button {
position: absolute;
top: 20px;
left: 20px;
}
#stop {
left: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="start">start</button>
<button id="stop">stop</button>
Related
I made this something like this:
Codepen or code down.
$(document).ready(function () {
var btn1Status = 0;
$("button").click(function () {
if (btn1Status === 0) {
$(".info").slideDown();
$(".info").show("slow");
$("button").text("less");
btn1Status = 1;
} else {
$(".info").slideUp();
$(".nfo").hide("slow");
btn1Status = 0;
$("button").text("More");
}
});
});
button {
background-color: black;
color: white;
width: 50px;
height: 30px;
}
button:focus {
outline: none;
}
ul {
list-style-type: none;
margin: 10px;
padding: 0;
}
.info {
background-color: black;
color: white;
font-family: arial;
width: 400px;
display: none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<div><img src="https://img.favpng.com/22/6/0/portable-network-graphics-movie-camera-film-clip-art-computer-icons-png-favpng-qfZ7hHPN2CCxiK8sYfjS2Sti9.jpg" width="400"><button>More</button></div>
<div class="info">
<ul>
<li>Name: movie1</li>
<li>Time: 6:00PM</li>
<li>Info 3 : blablabla</li>
<li>Info 4 : blablabla</li>
</ul>
</div>
when someone clicks the button, the info div should appear. the problem is, if I click the button multiple times then lift it, it will keep showing and disappearing. How do I fix this problem. Thanks for helping.
If you want the ability to let the users click multiple times but not build a queue of animations you can use the stop function from jQuery to stop/clear the queue of any currently running animations.
if (btn1Status === 0) {
$(".info").stop(true, true).slideDown();
$(".info").show("slow");
$("button").text("less");
btn1Status = 1;
} else {
$(".info").stop(true, true).slideUp();
$(".info").hide("slow");
btn1Status = 0;
$("button").text("More");
}
This will cancel the queue of animations if the button is clicked multiple times. The two arguments of .stop() are: ( [clearQueue ] [, jumpToEnd ] ). clearQueue is needed to clear the current animation queue, jumpToEnd will either cancel the currently running animation before jumping to the next one, or begin running the next slide animation from the current animation frame.
I am downloading a file I create on the server on a button click as in the below code.
$(document).ready(function() {
$('#reportBtn').on('click', function() {
$('#loadingScreen').removeClass('hidden');
window.location = '/myApp/Home/GenerateReport';
setTimeout(function() {
$('#loadingScreen').addClass('hidden');
}, 20000);
});
});
It works fine and I know that ideally this should really be wrapped in an AJAX call and return a unique GUID and return the file that way - however I cant use that approach and I am just wondering is there a better way I should be detected when the file has downloaded so I can remove the loading gif better. I have hard coded the 20 seconds which I know isnt really correct - sometimes depending on the amount of data in the report it downloads in 10 seconds or it could take 30 seconds to download.
Is there a better approach I could use keeping the fundamental call to window.location the same - note this is an MVC call which returns a FileResult of return File(data, MediaTypeNames.Application.Octet, reportName);
Instead of this, you can try another approach for displaying a loading spinner i.e. during page load:
<script type="text/javascript">
$(function () {
$("#btnSubmit").click(function () {
var form = $("#frmCreate");
form.validate();
if (form.valid()) {
$("#loading").fadeIn();
var opts = {
lines: 12, // The number of lines to draw
length: 7, // The length of each line
width: 4, // The line thickness
radius: 10, // The radius of the inner circle
color: '#000', // #rgb or #rrggbb
speed: 1, // Rounds per second
trail: 60, // Afterglow percentage
shadow: false, // Whether to render a shadow
hwaccel: false // Whether to use hardware acceleration
};
var target = document.getElementById('loading');
var spinner = new Spinner(opts).spin(target);
}
});
});
</script>
<div id="loading">
<div id="loadingcontent">
<p id="loadingspinner">
Loading...
</p>
</div>
</div>
<style>
#loading {
display: none;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255,255,255,0.8);
z-index: 1000;
}
#loadingcontent {
display: table;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
}
#loadingspinner {
display: table-cell;
vertical-align: middle;
width: 100%;
text-align: center;
font-size: larger;
padding-top: 80px;
}
</style>
Similarly you can also use some plugin in order to display loading spinner.
Is there anyway of removing an if statement after it has been fired once?
I have a menu container that shows on page load and want it so when the user scrolls 1px it slides away. I don't though want a the browser constantly tracking a scrollTop() method because of the performance hit from this.
What's the best way to remove or cancel an if statement after it has been used once?
The code is below and I have a codepen here: http://codepen.io/emilychews/pen/evbzMQ
jQuery(document).ready(function($) {
$(window).scroll(function() {
if ($(document).scrollTop() > 1) {
$('.menubox').css('left', '-25%');
}
});
$('.mybutton').on('click', function() {
$('.menubox').css('left', '0%');
});
});
body {
margin: 0;
padding: 0;
height: 200vh;
}
.menubox {
top: 100;
position: fixed;
width: 20%;
height: 100%;
background: red;
padding: 10px;
color: white;
transition: all 1s;
}
.mybutton {
position: fixed;
left: 40%;
top: 50px;
padding: 5px 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="menubox">Menu Box</div>
<button class="mybutton">menu</button>
Sounds like you actually have two conditions. One is based on the scroll position, the other is based on some state to be tracked. So just add a variable to track that state. Maybe something like:
var scrolled = false;
$(window).scroll(function() {
if ( !scrolled && $(document).scrollTop() > 1) { // check the state
$('.menubox').css('left', '-25%');
scrolled = true; // update the state
}
});
$('.mybutton').on('click', function() {
$('.menubox').css('left', '0%');
scrolled = false; // don't forget to reset the state
});
You can call off() within the if statement to remove the event handler.
Also note that if you're concerned about performance you can debounce the event handler so that it only executes the logic once scrolling stops for N ms:
var scrollTimer;
$(window).scroll(function() {
clearTimeout(scrollTimer)
scrollTimer = setTimeout(function() {
if ($(document).scrollTop() > 1) {
$('.menubox').css('left', '-25%');
$(window).off('scroll');
}
}, 150);
});
Here is the spinet:
$('#processing .progress-bar').animate({'width':'60%'},4000);
Is it possible to display how the milliseconds are being countdown by the function?
for instance I want to be able to display:
4000
3000
2000
1000
0000
then the function stops
You can add a step function to the jquery animate, and inside calcualte how much time is left for the animation to finish:
$(function () {
var Now = 0;
var animationDuration = 4000;
var DesiredWidth = "200";
$(".test").animate({
width: DesiredWidth
}, {
easing:"linear",
duration: animationDuration,
//the argument in the step call back function will hold the
// current position of the animated property - width in this case.
step: function (currentWidth,fx) {
Now = Math.round((100/DesiredWidth)*currentWidth);
$(".ms_span").text(Now+"%");
}
});
});
div {
width: 0;
height: 100px;
display: block;
background: purple;
position: relative;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="test"></div>
<br/>Percent: <span class="ms_span">
var duration = 4000,
interval = 1000,
pbar = $('#processing .progress-bar');
pbar.text( duration );
var cd = setInterval(function() {
duration -= interval;
pbar.text( duration );
}, interval);
pbar.animate({'width':'60%'}, duration, function() {
clearInterval(cd);
pbar.text( '0000' );
});
.progress-bar {
background-color: black;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="processing">
<div class="progress-bar">pBar</div>
</div>
After looking at #Banana's solution, I realized that I had completely forgotten about the step function and the new(ish) progress function, both of which can be passed to .animate. My updated solution is below, and I have removed the other to avoid confusion.
var $steps = $("#steps");
$('#processing .progress-bar').animate({
'width': '60%'
}, {
duration: 4000,
progress: function(prom, prog, rem) {
$steps.html("Prog: " + prog + "<br/>Rem: " + rem);
}
});
#processing {
width: 80%;
margin: 5%;
border: 2px solid black;
height: 25px;
}
#processing .progress-bar {
height: 100%;
background: lime;
width: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div>
<div id="processing">
<div class="progress-bar"></div> <span id="steps"></span>
</div>
</div>
As a side-note, depending on what you are planning to use this for, the other thing that you might want to look into is jQuery's .progress method, which handles progress notifications. Note that I am fairly certain that calling .progress on animations themselves won't have any effect unless you use a solution like the above to make progress notifications at each step of the animation. This is done with calls to .notify or .notifyWith but doing this in an animation is a little extreme. Regardless, this can be useful for situations in which you have an asynchronous call running for an indeterminate amount of time.
Docs for deferred.promise.
Docs for deferred.notify.
Docs for deferred.notifyWith.
I am trying to have a event happen at a current time through an audio file. The following code currently works and successfully plays the audio file:
<html>
<head>
<style>
.titletext {
color: white;
display: block;
position: absolute;
font-size: 50px;
width: 1000px;
margin-left: 150px;
margin-right: 200px;
}
.nametext {
color: white;
display: block;
position: absolute;
font-size: 30px;
width: 600px;
margin-left: 500px;
margin-right: 200px;
margin-top: 600px;
}
.earthphoto {
display: block;
position: absolute;
margin-left: 400px;
margin-top: 150px;
}
</style>
</head>
<body onload="update()">
<script type="text/javascript">
document.body.style.background="black";
var changescene=function(){
var allvariables=Object.keys( window );
if(page===1){
console.log(allvariables);
}
page++;
update();
};
var page=1;
var playsound=function(){
if(page===1){
document.getElementById("sound1").play();
document.getElementById("sound1").addEventListener("ended",function(){changescene();});
}
};
var update=function(){
if(page===1){
document.body.innerHTML="";
var text=document.createElement("p");
var textclass = document.createAttribute("class");
textclass.value="titletext";
text.setAttributeNode(textclass);
text.appendChild(document.createTextNode("Welcome to Mikey's Google Earth Presentation!"));
document.body.appendChild(text);
var text2=document.createElement("p");
text2class=document.createAttribute("class");
text2class.value="nametext";
text2.setAttributeNode(text2class);
text2.appendChild(document.createTextNode("By Mikey Richards"));
document.body.appendChild(text2);
googleearthimage=document.createElement("img");
googleearthimage.setAttribute("src","EARTH.png");
googleearthimage.setAttribute("class","earthphoto");
document.body.appendChild(googleearthimage);
var music=document.createElement("audio");
var musiclink=document.createElement("source");
musiclink.src="Slide1.mp3";
music.appendChild(musiclink);
var musicclass=document.createAttribute("id");
musicclass.value="sound1";
music.setAttributeNode(musicclass);
document.body.appendChild(music);
playsound();
}else if(page===2){
document.body.innerHTML="";
}
};
</script>
</body>
</html>
However, although this works for playing the audio file, when I add this code to run some code when it reaches a certain point, it crashes.
while(document.getElementById("sound1").currentTime<16){
}
//insert code here
I place this code in the playsound function directly after the play function for the audio, so the audio file should be playing. Why does the file crash.
Here is a link to see the result of the file:
http://www.presentation.bugs3.com/presentation.html
You effectively have a while(true){} loop in your code. while executes synchronously, which means that there is no break in the execution loop for anything else to happen, like the audio to advance. You only want to use while if the loop itself modifies the condition while is checking. Depending on exactly what you want to do, i'd use setTimeout or setInterval. If you want to stop it after 16 seconds, I'd do
setTimeout(
function(){document.getElementById("sound1").pause()},
16000)
alternatively
var curInterval = setInterval(
function(){
if(document.getElementById("sound1").currentTime<16)
{
doSomething();
}
else
{
clearInterval(curInterval);
doSomethingElse();
}
},
200) //whatever interval makes sense to you.