Smooth javascript animation - javascript

Here is some code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style>
body { margin:0; padding:0; }
#a {
position:absolute;
background:#0FF;
left:0;
height:300px;
width:120px;
}
input, #a {
margin:10px;
}
</style>
<script>
function foo() {
box = document.getElementById('a');
var computedStyle = box.currentStyle || window.getComputedStyle(box, null);
box.style.left = parseInt(computedStyle.left) + 10 + 'px';
setTimeout("foo()",20);
}
</script>
</head>
<body>
<input type="button" value="RUN, FORREST, RUN!" onClick="setTimeout('foo()',20)">
<div id="a"></div>
</body>
</html>
As you can see, it animates DIV at page, but animation isn't clear and smooth — border of DIV actually deforming.
Somebody know how i can make it work correctly?

Ditto JustLoren: it works fine on my machine. I'm not sure what you mean by the border ‘deforming’... maybe you're talking about tearing? If so, I'm afraid there is nothing you can do about it.
The traditional solution to tearing is to wait for vsync to draw your next frame, but that ability is not available in JavaScript. No framework can fix it. (Framework fans: please stop suggesting “Use my_favourite_framework! It solves all problems!” to JavaScript questions you don't understand.)
As mck89 suggests, you can certainly make the animation smoother (which can reduce the impact of tearing too) by drawing more frames, at the expense of taking more CPU power to perform. You might also prefer to keep a variable to store your x value, rather than parsing it from the currentStyle every time. It would be simpler and more widely supported by browsers.
ETA re comment: There's not a concrete minimum timeout in JS (I can get it down to 1ms sometimes), but how many fps you can get out of an animation is highly dependent on the browser and the power of the machine, which is why generally it's a good idea to base position/frame on the amount of time that has elapsed since the start of the animation (using new Date().getTime()) rather than moving/changing a fixed amount each frame.
In any case, about the fastest you can practically go is using an interval of 16ms, which corresponds to one frame on a 60Hz monitor (the usual flatscreen default).

You should increment the left coordinate by 1 px and set a lower time for the interval.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Untitled Document</title>
<style>
body { margin:0; padding:0; }
#a {
position:absolute;
background:#0FF;
left:0;
height:300px;
width:120px;
}
input, #a {
margin:10px;
}
</style>
<script>
function foo() {
box = document.getElementById('a');
var computedStyle = box.currentStyle || window.getComputedStyle(box, null);
box.style.left = parseInt(computedStyle.left) + 1 + 'px';
setTimeout("foo()",1);
}
</script>
</head>
<body>
<input type="button" value="RUN, FORREST, RUN!" onClick="setTimeout('foo()',20)">
<div id="a"></div>
</body>
</html>

JQuery and YUI and almost every other js library provides animation utility, perhaps you should look into those.

In my experience, mootools (http://mootools.net) provides the smoothest animation.

Related

CSS :after fails in IE8, but only after adding a reference to jQuery

It's taken me a few hours to track this issue down and I'm a bit shocked by what I am seeing.
Here's the code:
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
a:after {
content: attr(data-content);
}
</style>
</head>
<body>
<a id="targetElement" href="http://www.google.com">Hello World</a>
</body>
<script type="text/javascript">
document.getElementById("targetElement").setAttribute("data-content", "moo");
</script>
</html>
The above example works appropriately in IE8. When viewed, the word 'moo' is appended to the end of targetElement:
Now, lets spice things up a little bit by reference jQuery via the CDN. Add the following line of code:
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.8.3.min.js"></script>
such that the entire example reads as:
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
a:after {
content: attr(data-content);
}
</style>
</head>
<body>
<a id="targetElement" href="http://www.google.com">Hello World</a>
</body>
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.8.3.min.js"></script>
<script type="text/javascript">
document.getElementById("targetElement").setAttribute("data-content", "moo");
</script>
</html>
refresh IE8 and observe that the word moo has been dropped, but the element retains its data-content attribute:
I... I don't understand. I thought jQuery was supposed to be helping me out with cross-browser compatibility... but here it is wrecking shop.
Any ideas on how I can trouble shoot this? Or work around?
Alright! I spoke with Joseph Marikle in chat and we worked through a large amount of examples attempting to track down the issue.
I have good news and I have bad news. The bad news first -- I don't know exactly what the hell is going on. The good news? I've got work arounds!
So, first off, if your element is on the page at design-time (not dynamically generated) then, as long as the element's attribute exists, the css should work.
E.g.:
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<style>
a:after {
content: attr(title);
}
</style>
</head>
<body>
<a id="targetElement" title="hi" href="http://www.google.com">Hello World</a>
<script type="text/javascript">
document.getElementById("targetElement").setAttribute("title", " moo");
</script>
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
</body>
</html>
This example works because targetElement has the title attribute defined. The title is set to moo at run time and the css reflects this by showing content as 'moo.'
If you remove the code title="hi", you will not see moo. FURTHERMORE, if targetElement is not on the page when the css is ran -- you will not see moo -- even if you generate targetElement with the title attribute existing.
If you want to dynamically generate your elements and have this css still work... I have a second workaround for you and this is the one I am currently using. The issue seems to be that IE8 isn't finding the element when it applies pseudo-selectors and it doesn't re-run its logic when the element shows up.
So, if you do something like..
node.children('a').attr('data-content', '[' + usedRackUnits + '/' + rackTooltipInfo.rackModel.rows + ']');
var addRule = function (sheet, selector, styles) {
if (sheet.insertRule) return sheet.insertRule(selector + " {" + styles + "}", sheet.cssRules.length);
if (sheet.addRule) return sheet.addRule(selector, styles);
};
addRule(document.styleSheets[0], 'li[rel="rack"] > a:after', "content: attr(data-content)");
This will modify your stylesheet at runtime and add a new CSS rule. This causes IE8 to re-apply the logic and, because the dynamic elements are on the page now, it finds them and applies the css appropriately. Woohoo! Stupid IE8.

How to slide div from left to it's absolute position in the middle of the page?

I want to use jQuery or Javascript to take my logo and when the page loads, slide it from the left hand side of the page and make it stop and stay at it's resting spot about mid way through the page. (Logo div id="mylogo")
$(document).ready( function () {
$("#myLogo").animate("aCSSAttribute", "toThisValue");
});
also check:
http://api.jquery.com/animate/
If you show your effort, then I can help you out better.
You'll probably want something like this: http://jsfiddle.net/SATMY/1/
Your question is not clear at all, so it is hard to say whether it is possible that my answer is, indeed, a correct answer.
$("div#logo").animate({"marginLeft":"-50px"}, 800);​
And initial CSS:
margin-left: -900px; /* Before slide-in */
You'll need to work out just how far it needs to move, the example below makes an assumption of x% but you can do this to the pixel should you need to.
Don't forget to position your logo, and to make sure the outer element has some width/display definition.
Fiddle
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#main {width:100%;}
#mylogo{border:1px solid red;width:200px;height:100px;display:block;position:relative}
</style>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#mylogo').animate({left:'+=25%'});
});
</script>
</head>
<body>
<div id="main">
<div id="mylogo"></div>
</div>
</body>
</html>

Strange behavior Shift-Key Safari - HTML/Javascript

As requested, I simplified the problem as much as possible.
What I am trying to do is adding a onmousemove event to an HTML element, in this case the box, that will call a function. The problem I have is that not only mouse movements trigger the event, but also keys like SHIFT, CTRL, ALT... do.
So, once the mouse is passed over the box for the first time and the alert window is closed, any of the keys I mentioned previously will also make a new alert window pop up.
I am working with Safari, I also tested this on Google Chrome and the result is also a weird behavior of the browser.
Here is the code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3c.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<html xmlns="http://www.w3.org/1999/xhtml\" xml:lang="es" lang="es">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
<script>
window.onload = function() {
boxx = document.getElementById("box");
boxx.onmousemove = showMessage;
}
function showMessage() {
alert("hello");
}
</script>
</head>
<body>
<div id="box" style="width: 900px; height: 300px; border: 1px solid;"></div>
</body>
</html>
I really don't understand what is happening, hopefully someone can help me!

rendering multiple images in a browser in a video like fashion

I have approximatively 500 images that differ very slightly one from another. They are all of the same size. They hence form a sort of video when watched one after the other very fast.
I am looking for a way to display them in a browser (html file from disk), all in the same spot, to form that video looking effect. I want to be able to play, pause, stop, play faster, play slower (and if possible even more controls, such as maybe go to specific time (ie, image 47, if there's a slider for example; if there's only play,pause,fast and slow it's okay though).
I am not a programmer but I think javascript might do that. If there's a better technology, please redirect me to it. I'm just looking for a solution that works the way I intend, but I have no javascript knowledge. This surely has been done before though, so I would gladly accept a working solution.
Although you seem to be going the conversion route, here is a solution that uses javascript, allows pausing, jump to frame, and changing speed (I didn't bother with a slider for this [or a nice UI for any of it]):
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Untitled Document</title>
</head>
<body onload="launch()">
</body>
<script>
var frames=['frame1.png','frame2.png','frame3.png','frame4.png','frame5.png','frame6.png','frame7.png','frame8.png','frame9.png','frame10.png'];
var playing=true;
var on_frame=0;
var timer;
function launch(){
document.body.innerHTML='<img id="film" src="frames/'+frames[on_frame]+'"/><br/><button id="actionbutton">Play</button><button onclick="stop()">Stop</button><br/>Milliseconds between frames:<input type="text" id="framerate" value="50"/><br/>Go to frame:<input type="text" id="gotoframe"><button onclick="goFrame(document.getElementById(\'gotoframe\').value);">Go</button>';
document.getElementById('actionbutton').addEventListener('click',play);
play();
}
function change(){
document.getElementById('film').src='frames/'+frames[on_frame]; //I have my images in a folder named frames
on_frame++;
if(on_frame==frames.length){on_frame=0;}
if(playing){
timer=setTimeout(change,document.getElementById('framerate').value?document.getElementById('framerate').value:50);
}
}
function play(){
document.getElementById('actionbutton').removeEventListener('click',play);
document.getElementById('actionbutton').addEventListener('click',pause);
document.getElementById('actionbutton').innerHTML='Pause';
clearInterval(timer);
playing=true;
change();
}
function pause(){
document.getElementById('actionbutton').removeEventListener('click',pause);
document.getElementById('actionbutton').addEventListener('click',play);
document.getElementById('actionbutton').innerHTML='Play';
playing=false;
}
function stop(){
document.getElementById('actionbutton').removeEventListener('click',pause);
document.getElementById('actionbutton').addEventListener('click',play);
document.getElementById('actionbutton').innerHTML='Play';
playing=false;
on_frame=0;
}
function goFrame(x){
if((x>-1)&&(x<=frames.length)){
on_frame=x;
if(!playing){document.getElementById('film').src='frames/'+frames[on_frame];}
}
else{
alert('Out of range');
}
}
</script>
</html>

Knowing how wide a text line will be in HTML for word wrap and other applications

Do you know a good cross-browser way of knowing how wide will be a text line so you can break it exactly to fit a fixed width?
Suppose you want to break a long text like so it doesn't overflow a fixed width container, but you want the line to break the closest to the border possible, so guessing where to insert ­s isn't a clean solution.
I want to investigate, I imagine this could be done having an invisible div then printing the line inside it and checking the div's width, or something like that, with Javascript.
Has anyone done something like this?
*(the focus is not word wrapping, that's just the application that comes to my mind now, but knowing a text's width is what I want)
Here is a complete "Heath Robinson" (does that reference travel well?) approach.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<script type="text/javascript">
function txtContent_onchange()
{
var span = document.getElementById("spanMeasure")
span.innerHTML = "";
span.appendChild(document.createTextNode(this.value));
document.getElementById("txtWidth").value = span.scrollWidth;
}
</script>
<style type="text/css">
#spanMeasure
{
position:absolute;
top:0px;
left:0px;
visibility:hidden;
width:10px;
white-space:nowrap;
overflow:hidden
}
</style>
</head>
<body>
<input id="txtContent" onchange="txtContent_onchange.call(this)" /><br />
<input id="txtWidth" />
<span id="spanMeasure"><span>
</body>
</html>
The critical thing here is the configuration of the span element. This element will not impact the visual appearance of the page. Its scrollWidth property will return the length of the text it contains. Of course you would need to set any font style attributes to get a reasonable value.
According to quirksmode site Opera may be a little flaky with this approach but I suspect its the closest you will get to a fully cross-browser solution.

Categories

Resources