Smooth Javascript animation with StackBlur - javascript

http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html
If I move the slider on this page, the blurring is very smooth.
But if I try and automate the animation:
var speed = 1250;
var blur = 100;
var interval = speed/blur;
setInterval(function(){
blur--;
stackBlurImage(image, canvas, blur);
}, interval);
The steps are very obvious and it doesn't even work at high speed.
Could anyone suggest an alternative approach to this?

Pre-render the different blur levels, store them and cycle through them as frames. Its possible that whatever stackBlurImage does just can't be done fast enough to look like an animation.
Edit: I take that back, exactly what you did: http://jsfiddle.net/nwellcome/27QUM/ that looks great to me in Chrome, what browser are you using?
Edit 2: Try the second approach in this fiddle: http://jsfiddle.net/nwellcome/27QUM/4/, rather than decreasing the blur radius by 1 each time, fix the fps at something setInterval can handle and manipulate the amount you decrease the blur radius each frame.
var fps = 30;
var blur = 100;
var blurTime = 0.5; // seconds
var interval = 1000 / fps;
var step = blur/ (fps * blurTime);
var anim = setInterval(function(){
blur-= step;
if (blur < 0) {
clearInterval(anim);
}
stackBlurImage(image, canvas, blur);
}, interval);
Edit 3: just for the fun of it, with the HTML5 file API, you can upload your own image to blur: http://jsfiddle.net/nwellcome/27QUM/12/

Related

PixiJS Random Rotation & Declining Speed

I am trying to get a simple random "rotation" based on the angle property, and would like to achieve the following.
Random Rotation, say "rotate" to 500 degrees
Start with a high speed and when getting nearer to the "rotated" degrees, lower the "rotating" speed so that the stop is not instant.
I put a basic concept of what I am trying to achieve on this link:
https://www.pixiplayground.com/#/edit/yalRPEN~6tg3seIHq5hbI
In the animate function, if I put the let degrees = 2000; as a Math.Random value it screws up the animation as it seems that this animate function is called numerous times?
Also, I tried using the speed property which would start off with a high value and starts to get lower with "rotations", but it seems to do nothing? Also tried using animationSpeed since I am using the angle property to change degrees, but I see no speed difference.
Any feedback would be appreciated.
Thanks
One approach is to change the angle and not the speed. Something like this:
var angleStep = 40;
let rotateSpeed = Math.floor(Math.random() * 300)
function animate() {
bunny.angle += angleStep;
angleStep = angleStep - angleStep/rotateSpeed;
if ((angleStep.toFixed(1) <= 0.0)) {
console.log("stopped rotation")
bunny.angle = bunny.angle;
return bunny.angle;
} else {
requestAnimationFrame(animate);
}
}

Rotate wheel and stop at specific point in EaselJs

I am new to EaselJs.
I am rotating a wheel with 9x numbers and 3 (0x), the total of 12 numbers. I am able to rotate the wheel by calling function, but I want to stop it on predefined specific point/number of the wheel.
var _oContainer;
this._init = function(iXPos,iYPos){
_oWheel = s_oSpriteLibrary.getSprite("wheel_circle");
_oContainer = new createjs.Container;
_oContainer.x = CANVAS_WIDTH - 200;
_oContainer.y = CANVAS_HEIGHT - 350;
s_oStage.addChild(_oContainer);
img = createBitmap(_oWheel);
img.regX = _oWheel.width / 2;
img.regY = _oWheel.height / 2;
_oContainer.addChild(img);
}
this.spin = function(b, a){
//var h = new createjs.Bitmap(s_oSpriteLibrary.getSprite('wheel_circle'));
createjs.Tween.get(_oContainer).to({
rotation: _oContainer.rotation + a
}, 2600, createjs.Ease.quartOut).call(function() {
_oContainer.rotation %= 360;
})
}
I am calling the spin function as this.spin(5, 1131.7511808994204); on every time button is clicked.
Right now it is spinning and stopping randomly on every button click. How can stop it on a specific number/position on the wheel?
What value should I give in rotation:?
There are a lot of factors in play to do something like this. I made a quick demo to show how I would do it:
Draw the wheel (at center) with segments. It is important to know how many segments you have so you can choose a place to "end"
Start spinning. Just increment the rotation each tick depending on how fast you want it to go.
When "stopping", you have to do math to determine where to land
To get a realistic "slow down", make sure the remaining rotation in the tween is enough so it doesn't speed up or slow down too rapidly
Here is the fiddle: https://jsfiddle.net/lannymcnie/ych1qt8u/1/
// Choose an end number. In this case, its just a number between 0 and the number of segments.
var num = Math.random() * segments | 0,
// How many degrees is one segment?
// In my demo I use radians for `angle`, so I have to convert to degrees
angleR = angle * 180/Math.PI,
// Take the current rotation, add 360 to it to take it a bit further
// Note that my demo rotates backwards, so I subtract instead of add.
adjusted = c.rotation - 360,
// Determine how many rotations the wheel has already gone since it might spin for a while
// Then add the new angle to it (num*angleR)
// Then add a half-segment to center it.
numRotations = Math.ceil(adjusted/360)*360 - num*angleR - angleR/2;
Then I just run a tween to the new position. You can play with the duration and ease to get something you like.
createjs.Tween.get(c)
.to({rotation:numRotations}, 3000, createjs.Ease.cubicOut);
Technically, I should change the duration depending on the actual remaining spin, since depending on the result, it might not be super smooth. This came close enough, so I left it as-is.
Hope that helps! Let me know if I can clarify anything further.

Faster way of scaling text in browser? (help interpret test)

I need to scale lots of text nodes in the browser (support of all modern desktop and mobile browsers).
If I am right there are two options that offer good performance: scaling text objects in Canvas or scaling text nodes in the DOM using transform:matrix.
I have created a scenario to test both versions but the results are inconclusive. Uncomment testDOM() or testCanvas() function to start the test. (I am using JQuery and CreateJS framework because it was convenient. It is possible to use vanilla JS but I don't think that is the bottleneck here). (It matters what portion of the screen you actually see so please switch to full screen view in codepen).
http://codepen.io/dandare/pen/pEJyYG
var WIDTH = 500;
var HEIGHT = 500;
var COUNT = 200;
var STEP = 1.02;
var MIN = 0.1;
var MAX = 10;
var stage;
var canvas;
var bg;
var canvasTexts = [];
var domTexts = [];
var domMatrix = [];
var dom;
function testDOM() {
for (var i = 0; i < COUNT; i++) {
var text = $("<div>Hello World</div>");
var scale = MIN + Math.random() * 10;
var matrix = [scale, 0, 0, scale, Math.random() * WIDTH, Math.random() * HEIGHT];
text.css("transform", "matrix(" + matrix.join(',') + ")");
domTexts.push(text);
domMatrix.push(matrix);
}
dom = $('#dom');
dom.append(domTexts);
setTimeout(tickDOM, 1000);
}
function tickDOM() {
for (var i = 0; i < domTexts.length; i++) {
var text = domTexts[i];
var matrix = domMatrix[i];
var scale = matrix[0];
scale *= STEP;
if (scale > MAX)
scale = MIN;
matrix[0] = matrix[3] = scale;
text.css("transform", "matrix(" + matrix.join(',') + ")");
}
requestAnimationFrame(tickDOM);
}
function testCanvas() {
$('#dom').hide();
stage = new createjs.Stage('canvas');
createjs.Touch.enable(stage);
createjs.Ticker.timingMode = createjs.Ticker.RAF;
canvas = stage.canvas;
devicePixelRatio = window.devicePixelRatio || 1;
stage.scaleX = devicePixelRatio;
stage.scaleY = devicePixelRatio;
console.log('devicePixelRatio = ' + devicePixelRatio);
stage.mouseMoveOutside = true;
stage.preventSelection = false;
stage.tickEnabled = false;
stage.addChild(bg = new createjs.Shape());
bg.graphics.clear();
bg.graphics.f('#F2F2F2').drawRect(0, 0, 2 * WIDTH, HEIGHT);
canvas.width = 2 * WIDTH * devicePixelRatio;
canvas.height = HEIGHT * devicePixelRatio;
canvas.style.width = 2 * WIDTH + 'px';
canvas.style.height = HEIGHT + 'px';
stage.update();
for (var i = 0; i < COUNT; i++) {
var text = new createjs.Text("Hello World", "10px", "#333333");
text.scaleX = text.scaleY = MIN + Math.random() * 10;
text.x = Math.random() * WIDTH;
text.y = Math.random() * HEIGHT;
stage.addChild(text);
canvasTexts.push(text);
}
stage.update();
setTimeout(tickCanvas, 1000);
}
function tickCanvas() {
for (var i = 0; i < canvasTexts.length; i++) {
var text = canvasTexts[i];
text.scaleX = text.scaleY *= STEP;
if (text.scaleX > MAX)
text.scaleX = text.scaleY = MIN;
}
stage.update();
requestAnimationFrame(tickCanvas);
}
testDOM();
//testCanvas();
My questions:
Is it possible to improve the performance of my tests? Am I doing something wrong?
The first 5-10 seconds are significantly slower but I don't understand why. Does the browser somehow cashes the text objects after some time? If yes, is the test unusable for real world scenario testing where the objects don't zoom in a loop for longer period of time?
According to the Chrome Profiling tool the DOM version leaves 40% more idle time (is 40% more faster) than the Canvas version but the Canvas animation looks much smoother (after the initial 5-10 seconds of lagging), how should I interpret the Profiling tool results?
In the DOM version I am trying to hide the parent of the text nodes before I apply the transformations and then unhide it but it probably does not matter because transform:matrix on absolutely positioned element does not cause reflow, am I right?
The DOM text nodes have some advantages over the Canvas nodes like native mouse over detection with cursor: pointer or support for decorations (you can not have underlined text in Canvas). Anything else I should know?
When setting the transform:matrix I have to create a string that the compiler must to parse back to numbers, is there a more efficient way of using transform:matrix?
Q.1
Is it possible to improve the performance of my tests? Am I doing
something wrong?
Yes and no. (yes improve and no nothing inherently wrong (ignoring jQuery))
Performance is browser, and device dependent, for example Firefox handles objects better than arrays, while Chrome prefers arrays. There is a long list of differences just for the javascript.
Then the rendering is a dependent on the hardware, How much memory, what capabilities, and the particular drivers. Some hardware hates state changes, while others handle them at full speed. Limiting state changes can improve the speed on one machine while the extra code complexity will impact devices that don't need the optimisation.
The OS also plays a part.
Q.2
The first 5-10 seconds are significantly slower but I don't understand
why. Does the browser somehow cashes the text objects after some time?
If yes, is the test unusable for real world scenario testing where the
objects don't zoom in a loop for longer period of time?
Performance testing in Javascript is very complicated and as a whole application (like your test) is not at all practical.
Why slow?
Many reasons, moving memory to the display device, javascript optimising compilers that run while the codes runs and will recompile if it sees fit, this impacts the performance Un-optimised JS is SLOOOOOWWWWWWWW... and you are seeing it run unoptimised.
As well. In an environment like code pen you are also having to deal with all its code that runs in the same context as yours, it has memory, dom, cpu, GC demands in the same environment as yours and thus your code can not be said to be isolated and profiling results accurate.
Q.3
According to the Chrome Profiling tool the DOM version leaves 40% more
idle time (is 40% more faster) than the Canvas version but the Canvas
animation looks much smoother (after the initial 5-10 seconds of
lagging), how should I interpret the Profiling tool results?
That is the nature of requestAnimationFrame (rAF), it will wait till the next frame is ready before it calls your function. Thus if you run 1ms past 1/60th of a second you have missed the presentation of the current display refresh and rAF will wait till the next is due 1/60th minus 1ms before presentation and the next request is called. This will result in ~50% idle time.
There is not much that can be done than make you render function smaller and call it more often, but then you will get extra overhead with the calls.
rAF can be called many times during a frame and will present all renders during that frame at the same time. That way you will not get the overrun idle time if you keep an eye on the current time and ensure you do not overrun the 1/60th second window of opportunity.
Q.4
In the DOM version I am trying to hide the parent of the text nodes
before I apply the transformations and then unhide it but it probably
does not matter because transform:matrix on absolutely positioned
element does not cause reflow, am I right?
Reflow will not be triggered until you exit the function, hiding the parent at the start of a function and then unhiding it at the end will not make much difference. Javascript is blocking, that means nothing will happen while you are in a function.
Q.5
The DOM text nodes have some advantages over the Canvas nodes like
native mouse over detection with cursor: pointer or support for
decorations (you can not have underlined text in Canvas). Anything
else I should know?
That will depend on what the intended use is. DOM offers a full API for UI and presentation. Canvas offers rendering and pixel manipulation. The logic I use is if it takes more code to do it via DOM then canvas, then it is a canvas job and visa versa
Q.6
When setting the transform:matrix I have to create a string that the
compiler must to parse back to numbers, is there a more efficient way
of using transform:matrix?
No. That is the CSS way.

Movement slower when canvas is bigger

Using this code:
x = x + (canvas.height/250);
which happens every 1 millisecond should add an amount to x in proportion to the canvas size. x is then drawn so therefore x should move down the canvas at the same speed on different screen sizes (the canvas changes size according to the screen size). However the x moves down at different speeds on my ipod and my pc.
If you want to know the full source code and html file the html is here and the javascript file linked to it is here.
First, let's think about what this line does:
x += canvas.height / 250;
The speed of the object is canvas.height / 250. The distance is canvas.height. We can say that:
distance = speed * time
We already have distance and speed, so:
time = distance / speed = canvas.height / (canvas.height / 250) = 250 ms
So the object always reaches its destination in 2.5 seconds. In order to make that happen, you change the speed based on the screen size.
If you want the speed to be the same in all devices, it shouldn't depend on canvas.height.
The change in traversal time is due to a change in draw time.
If the device is, say, two times slower to draw, the increase
will get done two times less per second, and your object will be
in mid-screen in the slow device when it will have crossed screen in
the other.
To have consistent behavior you must handle your game time.
Then you just have to decide of your objects speed in pixels per milliseconds,
and use the classical equation :
pos = pos + speed * (time step)
the code looks like :
var x = 0;
var speed = canvas.width / 1000 ; // speed in pixels per milliseconds.
var lastTime = 0;
requestAnimationFrame(launchAnimate);
function animate() {
requestAnimationFrame(animate);
var now = Date.now();
var dt = now - lastTime ;
lastTime = now ;
// draw everything
draw();
// update everything with this frame time step.
update(dt);
}
function launchAnimate() {
lastTime = Date.now() ;
requestAnimationFrame(animate);
}
Edit : you can't draw faster than your screen, so on a 60Hz screen, you'll draw at best every 16.666 ms.
Don't be scared by RequestAnimationFrame, it just means : "when the screen is ready, draw the callback that i gave you.".
So you have to re-arm it every time to make your game live.
So for your game, it's time to organize a bit :
have an update function where you put all the code that updates all things.
have a draw function that draws everything.
do not draw in the update (remove the draw calls in moveTrees), and
do not update in the draw. SEPARATION OF CONCERNS, :-)
have each update depend on frame time (dt) for all that's related to time (position, speed, acceleration, forces).
function update( dt ) {
x = x + speed * dt ;
moveTrees(dt);
}
function draw () {
drawTrees();
drawHangGlider();
drawTrees();
}
You'll notice i changed the animate function to call draw and update, still you have a bit of work to re-organize things.
Edit 2 : RequestAnimationFrame is widely ok now :
http://caniuse.com/requestanimationframe
(Chrome for Android is ok).
Rq :
// to use rAF, call this function before your game launches
polyFillRAFNow();
// insert the function in your code.
function polyFillRAFNow() {
// requestAnimationFrame polyfill
var w = window;
var foundRequestAnimationFrame = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.msRequestAnimationFrame || w.mozRequestAnimationFrame || w.oRequestAnimationFrame || function (cb) { setTimeout(cb, 1000 / 60); };
window.requestAnimationFrame = foundRequestAnimationFrame;
}
Rq2 : you might be interested in this article i wrote on the game loop http://gamealchemist.wordpress.com/2013/03/16/thoughts-on-the-javascript-game-loop/
So basically you want a relative absolute speed depending on the screen size, which would then appear to be the same on different displays. In order to do this you should use percentages, for example:
var pixels_in_1_percent = canvas.height/100;
x += pixels_in_1_percent
That will increase the speed by 1% of canvas height, if you want more speed then you have to multiply it
x += pixels_in_1_percent * <number_of_percent_to_increase>
Hope that helps.
You said in your question that you are calling the function every 1 millisecond. However, some browsers limit the speed of window.setInterval so if you made the function call once every 50 milliseconds it would be the same on all devices.
window.setInterval(function(){
/// call your function here e.g. add1toxfunction();
}, 50);

Easing a sprite animation in JS

I've got my sprite sheet animating in vanilla JS by shifting the background-position at a fixed FPS, using requestAnimationFrame and setTimeout to set the framerate.
Ultimately I'd like to animate it with an easing curve, such as QuadInOut, or better still a custom curve. Most of the frameworks I've looked at have their easing built into their tween function, and not for animating a sprite sheet.
Can anyone suggest a JS framework that might help? GSAP or Enchant perhaps? Or alternatively explain the logic behind updating the fps via an easing curve?
Here's my 'linear' animation at the moment:
var theSprite= $('.sprite');
var timesRun = 0;
var shift = 0;
var fps = 20;
var anim = function() {
setTimeout(function() {
shift -= 520;
theSprite.css('background-position', shift +'px 0');
timesRun += 1;
if(timesRun === 19) {
timesRun = 0;
shift = 0;
}
animAgain = requestAnimationFrame(anim);
}, 1000 / fps);
}
anim();
Enchant.js has a few different ways sprite animation. if you look at the enchant.timeline class here http://wise9.github.io/enchant.js/doc/plugins/en/symbols/enchant.Timeline.html it has a few different functions for easing sprites in different ways.
I think you would definitely enjoy KineticJS. It works like a charm and is designed for what you are trying to do.
See: HTML5 Canvas KineticJS Sprite Tutorial

Categories