What is the cleanest way to animate without .animate() jQuery? - javascript

I had a nice idea, namely to use the 'stroke-dasharray' CSS-attribute that can be used on SVG objects, to stroke the paths on the page, giving it a nice artistic way for shapes to appear.
It works perfectly and is supported by most modern browsers as well as phones.
A nice jsfiddle of what I've made can be found here: http://jsfiddle.net/G6ECE/
The code that makes the whole thing tick right now:
num=0;
setInterval(function(){
updateStroke(num);
num+= 0.2;
}, 1);
function updateStroke(num){
// stroke-dasharray is a list of two or more numbers. In this example, percentage values are used to make all paths fully stroked at the end of the animation, irregardless of path length.
$('svg path').css({stroke:'#00FF00','stroke-dasharray':num+'% '+(100-num)+'%'});
}
Obviously this is a very basic, ugly way to animate something.
I want to customize the animation a little: I want to be able to add a custom animation length and also use different easings. Unfortunately, the jQuery $().animate() function that I'd normally use to animate CSS attributes, does not support non-numeric values.
As stroke-dasharray uses two or more numeric(pixel or percentage) values to work, I need an alternative for .animate()
What would be the cleanest way to do this? (with using as much existing jQuery functionality as possible, and as little as possible re-inventing an animation framework)

What about CSS transitions? They also have a better performance than jQuery animations.
http://www.w3schools.com/css/css3_transitions.asp
But be sure not to use both for the same property as jQuery animations interfere with CSS transitions.

Recently, I have been working with a nice robust cross-browser javascript animation object. Once you understand the way it is used, it becomes quite seamless for all or your SVG animations. It can be attached to any svg element and control associated values.
There are some examples that show the various choices of animation performance(linear, quadratic, ease,etc) at:
http://www.svgDiscovery.com/
Below is the object:
var AnimateJS=function(options){
this.options=options
var start = new Date
var iT = setInterval(
function(){
var timePassed = new Date - start
var progress = timePassed / options.duration
if (progress > 1) progress = 1
this.progress=progress
var delta = options.delta(progress)
options.output(delta)
if (progress == 1)clearInterval(iT);
},options.delay)
}

Related

css animation fast forward and rewind

I was wondering if it was possible, using some javascript or jquery, to skip to the next, or go to the last part of a css animation. Lets say we have the following:
#keyframe effect{
0%{opacity:1;}
45%{opacity:1;}
50%{opacity:0;}
95%{opacity:0;}
100%{opacity:1;}
}
that will fade something out and then back in
so lets say I made some buttons. How would I do the following:
$('#next').click(function(){
//skip to the next animation part
});
$('#previous').click(function(){
//skip to the previous animation part
});
It's not really possible unless you break the CSS into different parts based on classes and then add/remove classes.
However, there is an absolutely fantastic javascript library called Greensock, that allows timeline-based animation - and in many cases is faster than CSS animations. It also has the benefit of being cross-browser compatible.
If you were, for example to create something similar using Greensock, it would look something like this:
var effect = new TimelineMax({paused:true});
effect.addLabel('start');
effect.to(
'#myItem',
1,
{css:{opacity:1}}
);
effect.addLabel('step1');
effect.to(
'#myItem',
1,
{css:{opacity:0}}
);
effect.addLabel('end');
effect.play();
$('#gotoEnd').on('click', function(e){
e.preventDefault();
effect.seek('end');
});
With the use of the animation-play-state Property, you can pause an animation and update the transform, then restart it.
element.style.webkitAnimationPlayState = "paused";
element.style.webkitAnimationPlayState = "running";
However you can't pause the animation, transform it, resume it, and expect it to run fluidly from the new transformed state.
At this time, there is no way to get the exact current "percentage completed" of a CSS keyframe animation. The best method to approximate it is using a setInterval or requestAnimationFrame.
This CSS tricks article explains this further, and gives an example of using setInterval. Another option is to use request animation frame
As mentioned GreenSock or Velocity are animation libraries which allow for extremely fast and smooth animations

Improving Performance on Background Parallax Scrolling

Hello StackOverflow Community,
what I am trying to achieve is a header that can be moved with the mouse.
You klick into the header and drag the mouse and the elements inside the header will move with different speeds.
I achieved the parallaxing part but the performance is not really good. It is partially a bit laggy while dragging the backgrounds.
My question now is: what can be changed in the code to get a performance boost?
That's the part of the code that takes care of parallaxing. On every mousemove a each loop is executed which I think is the reason for the performance beeing so laggy:
var dragging = false;
var clickMouseX;
//Our object for the layers
//each layer has a different scrolling speed
var movingObjects = {
'#header-l1' : {'speed': 1},
'#header-l2' : {'speed': 1.4},
'#header-l3' : {'speed': 1.85},
'#header-l4' : {'speed': 2.2},
};
$('#header-wrapper').mousedown(function(e){
dragging = true;
//Get initial mouse position when clicked
clickMouseX = e.pageX;
$(this).mousemove(function(mme){
//execute only if mousedown
if(dragging){
//iterate through all layers which have to be parallaxed
$.each(movingObjects, function(el, opt){
var element = $(el);
//get difference of initial mouse position and current mouse position
var diff = clickMouseX - mme.pageX;
//scroll-position left speed 1
if(diff < 0) diff = -1;
//scroll position right speed 1
if(diff >= 0) diff = 1;
//get current position of layer
currLeft = parseInt(element.css('left'));
//get current layer width
elWidth = element.width();
//if right border is reached don't scroll further
if(currLeft < -(elWidth - 810)){
element.css('left', -(elWidth - 810));
}
//so do with left border
if(currLeft > 0){
element.css('left', 0);
}
//parallax it! Subtract the scroll position speed multiplied by the speed of the desired
//layer from the current left property
element.css('left', parseInt(element.css('left')) - diff*opt.speed);
});
}
});
/* Cursor */
$(this).css('cursor', 'pointer');
return false;
});
I also put a fiddle up:
http://jsfiddle.net/yWGDz/
Thanks in advance,
Thomas
P.S. maybe someone even finds out why layer two and three have the same scroll speed while having different speeds defined.
I worked at this a bit, and came up with this: http://jsfiddle.net/amqER/2/
This works a lot faster than the original (especially in firefox, where it performs a whole lot better, chrome it's still pretty slow). I also changed up some of the logic in your code, to make it make more sense.
A list of things that I did:
Minify your pngs
2 of your png files were over 2 megs, so I threw them into a png compressor (tinypng) and that reduced the size a lot. This helps with loading time and overall snappiness.
Re-use values as much as possible
In your original code, you wrote to and then subsequently read from the css left property a couple times in your code. Doing this is going to make it a lot slower. Instead, I kept an left property, and would only touch $.css when I absolutely needed to. Likewise for reading each element's width each update.
Also, like I said, I modified your logic to (I think) make more sense, given what you were trying to accomplish. It calculates a new diff each update, and tries to move according to that. Also, it doesn't try to keep moving once one of the images falls off (which yours does if you move all the way to the right, and it looks really weird). You can also look at this: http://jsfiddle.net/amqER/5/, which maybe is more like the control scheme you wanted.
Just some quick performance tips.
Try not to use $(this).mousemove instead save $(this) into a variable and use that.
var th = $(this);
th.mousemove...
Try to avoid using $.each. This is probably the part that's slowing your code down.
You can replace it with a for loop, but I would suggest, in this case, sending in each element one by one.
var parallax = function(img){
};
parallax(img1);
parallax(img2);
instantly-increase-your-jquery-performance
Whilst Xymostech's answer does greatly improve upon the original poster's original code; the performance is hardly improved for me in Chrome.
Whilst inspecting the page FPS, the solution posted here runs at 15FPS for me on a Retina MacBook Pro.
I made a very simple change to the code, altering it to use translate3d properties instead of left. Now, it runs at 55-60 FPS for me. I'd call that a massive performance boost.
If 'show paint rectangles' are turned on in Chrome, you'll see the previously posted solution is continually painting changes to the dom whilst the parallax is in motion. With the translate3d solution, there's simply zero painting done the whole time the parallax is in motion.
http://jsfiddle.net/LG47e/

HTML5 Canvas Image Filter Lags (JavaScript)

I'm attempting to load a full-screen background image onto a canvas, then apply an image filter to it, but have a few questions. I'm running into severe performance issues, but only when resizing the window. Basically, my code attempts to keep the canvas/image matching the screen dimensions (which works well).
UPDATE CANVAS METHOD:
The updateCanvas method is called on load to initially create/load the image object and place it on the canvas. If a filter is selected, it calls the filter method. It accepts the onResize argument, which is passed on window resize to scale the canvas/image. MAIN refers to an object used for referencing elements.
updateCanvas:function(onResize){
// SETUP VARIABLES
var img=new Image(),
$this=Main.currentOBJ, // REFERENCE FOR .DATA
objData=$this.data,
canvas=Main.OBJ.$Canvas[0],
ctx=canvas.getContext("2d"),
winW=$(window).width(), winH=$(window).height();
// SOURCE CAN BE SET IN .DATA OR DEFAULT
img.src=(objData.bg_pic_src!=='') ? objData.bg_pic_src : Main.ConSRC;
// LOAD THE IMAGE OBJECT
img.onload=function(){
var imgW=img.width, imgH=img.height,
ratio=imgW/imgH, newW=winW, newH=Math.round(newW/ratio);
// SETUP IMAGE PROPORTIONS
if(newH < winH){ var newH=winH, newW=Math.round(newH*ratio); };
// WHEN RESIZING THE BROWSER
if(!onResize){ // INTIAL DRAW
Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'});
ctx.drawImage(img,0,0,newW,newH);
// APPLY FILTERS
if(objData.bg_pic_filter > 0){
Main.canvasFilter(ctx,newW,newH); // FILTER METHOD
}else{
Main.OBJ.$OverlayPic.animate({opacity:parseFloat(objData.bg_pic_opacity,10)},
{duration:objData.bg_pic_speed_in,queue:false});
};
}else{ // RESIZING
Main.OBJ.$Canvas.attr({'width':newW+'px', 'height':newH+'px'});
ctx.drawImage(img,0,0,newW,newH);
if(objData.bg_pic_filter > 0){
Main.canvasFilter(ctx,newW,newH); // FILTER METHOD
};
};
};
The Canvas Filter Method:
If an image filter is to be applied to the background image, the canvasFilter method is called from the canvasUpdate method.
canvasFilter:function(ctx,width,height){
// SETUP VARIABLES
var objData=Main.currentOBJ.data,
canvasWidth=width, canvasHeight=height,
imgdata=ctx.getImageData(0, 0, canvasWidth, canvasHeight),
pix=imgdata.data, l=pix.length;
// APPLY THE CORRECT LOOP DEPENDING UPON THE FILTER NUMBER
switch(objData.bg_pic_filter){
case 1: ... break;
case 2:
for(var i=l; i>0; i-=4){
var cacher=pix[i+2];
pix[i]=pix[i+1];
pix[i+1]=cacher;
pix[i+2]=cacher;
pix[i+3]=cacher;
};
break;
};
// APPLY THE FILER & FADE IN THE BACKGROUND
ctx.putImageData(imgdata, 0, 0);
Main.OBJ.$OverlayPic.fadeTo(parseInt(objData.bg_pic_speed_in,10),
parseFloat(objData.bg_pic_opacity,10));
};
All of this works, and the initial draw/filter are quite fast. However, when I resize the window it's very sluggish. I've temporarily gotten around this by putting in a throttler, which just sets a timer to avoid firing the above functions too quickly. This helps slightly, but will keep the background image in place (displaying open solid background areas around the image) until the throttler timer kicks in and fires the methods - resizing the canvas/image and applying the filter.
Questions:
Is there a faster way? I've read about using Typed Arrays/Bitwise for pixel manipulation loops, but it seems that support is horrible for this. I've also looked into CSS3 filters to accomplish the same thing, but again, support is horrible. So, would this be the only approach to full-screen background image filters with "modern browser" compatibility?
The updateCanvas method is creating a new image object each time, I'm thinking that this might be a bottleneck, but am unsure, and also unsure of how to get around it?
I've read others using a separate canvas as a buffer? Would this actually increase performance in my situation?
I'm really thinking there's a major logic issue in my code somewhere. It just doesn't make sense to me that I would need to loop through all of the pixel information more than once, but this is the only way I've gotten it to work. Isn't there a way I can draw it/apply the filter once, then on resize, just adjust the dimensions without having to redraw/reloop/reapply the filter? I would think that it would maintain the filtered image, but if I remove the call to the canvasFilter method on window resize, it completely removes the filter effect.
I've yet to use memoization techniques as I've never quite understood it, and never quite understand where/when to use it. But, essentially, if I have a function that is returning the same results again and again (such as the canvasFilter method) can I memoize to increase performance - or would it be difference because it's pulling different pixel information after the window has resized?
I've also heard that a webGL render might help with this? Might be way off as I don't know anything about webGL.
So sorry for the loooonng question, but hopefully this covers some topics that others can benefit from as well. Any suggestions/tips would be much appreciated. Thanks! :)
Since it sounds like your image is mostly static, an approach you might want to try is using good old css.
The key trick here is using background-size:cover. See: http://css-tricks.com/perfect-full-page-background-image/
So in broad terms:
Load your image
Apply your filter in a canvas. (The canvas doesn't even need to be attached to the page).
Export your canvas data as a url via: ctx.toDataUrl("image/png");
Add the style to your container element or the body:
background-size:cover;background:url('data:image/png;yourcanvasdata');
Animate the opacity of the container element/body via js or the css transition property

Make lines blink inside a canvas

I'm currently working on a HTML5 and Javascript project using Kinetic Js and canvas.
I need my lines (Kinetic.Line) to blink.
I've tried something consisting of an infinite loop with setTimeout function inside, but I can't use javascript then (such a drawback because then I can't select points!).
Does somebody have an idea that can help me?
while (1) {
setTimeout("stage.load(myjson[0])", 1000);
setTimeout("stage.load(myjson[1])", 1000);
}
(sorry for my poor english)
Here's one way of making a line blink using KineticJS. Rather than using setTimeout, I think it's better to use the KineticJS onFrame event which is built into the stage object. You can then use setAlpha to set the opacity of the line, and getAlpha to get the current opacity of the line. setAlpha('0') will make the line transparent, setAlpha('1') will make the line visible.
I've set up a fiddle here:
JSFiddle
Here's the relevant bit that actually flashes the line:
var flashTime = 0;
stage.onFrame(function(frame){
if(frame.time > (flashTime + 250)){;
flashTime = frame.time;
redLine.setAlpha(redLine.getAlpha() == 1 ? '0' : '1');
layer.draw();
};
});

Fx on JavaScript: How to fade stuff, etc without frameworks?

I would like to learn how to do fade, and similar effects on JavaScript. I often get answers, like why not use jQuery, Mootools, etc ? Well, I want to learn how stuff works, then I won't mind using any of these frameworks.
I'm currently learning about making changes on the DOM, so, I've read a lot of stuff on this theme. Also, I've read about Reflow, still, I didn't find any cool stuff on Repaint, but, I'll keep searching.
From seeing source files etc, I see a few methods, that I don't know if they've created or are Core methods of JS.
My question is, is there any resource where I can learn all this neat stuff like smooth position change, fading elements trough opacity or whatever, etc?
Take a look at emile.js. It's brand-spanking new. Great way to learn how to do your own.
Introduced at the recent jsconf conference. Written by Thomas Fuchs (script.aculo.us).
http://github.com/madrobby/emile
Émile Stand-alone CSS animation
JavaScript mini-framework
Doesn't need
a JavaScript framework
Full set of CSS
properties for animation (length-based
and colors)
Easing and callbacks
Less
than 50 lines of code
Get updates on
Twitter: http://twitter.com/emilejs
here's an example that works in firefox and chrome. ie doesn't respect the opacity style.
var ELEMENT;
var STEPS;
var INTERVAL;
var COUNT;
var TIMERID;
// 5 * 200ms = 1 second
STEPS = 5;
INTERVAL = 200;
function Button1_onclick() {
ELEMENT = document.getElementById("foo");
COUNT = STEPS - 1;
TIMERID = setInterval(Fade, INTERVAL);
}
function Fade() {
ELEMENT.style.opacity = String(COUNT / STEPS);
COUNT--;
if (COUNT < 0) {
clearInterval(TIMERID);
TIMERID = 0;
}
}
setInterval and clearInterval are standard js functions. they will execute the given function every x milliseconds. in our case we kill it when we've hit 0 opacity.
sliding a window is a similar process. you'd set the left/right/top/bottom style instead of opacity.
Fading using javascript is basically modifying opacity of an element programmatically. The "smoothness" is done by using timers. Same for position/size changes. You need to read up on css to understand what style properties of an element you have to control using javascript for the effect you want.
If you are really curious, you can dive into the source of yui in github: http://github.com/yui

Categories

Resources