Createjs: Adding mouseover to containers slowsdown FPS - javascript

Link 1 - http://horebmultimedia.com/Sam3/
Link 2 - http://horebmultimedia.com/Sam5/
In the above links, i have added a set of numbers added in separate containers in each file and u can find the FPS on the top right. The issue is when i mouse over in this Link 1 and click any numbers, as u see the FPS is getting slower & slower, making the world to rotate slower on the left side.
While on this link, Link 2, I added only one mouse over and 5 mouse over, but there is not much difference in FPS, why it lags so much when i have 37 containers. I can give my code if u need to resolve.

I had a rough look at your code, but digging through an entire project is not a fantastic way to debug an optimization problem.
The first thing to consider is if you have mouseOver enabled on your stage, I would recommend a liberal use of mouseChildren=false on interactive elements, and mouseEnabled=mouseChildren=false on anything not interactive. The rollover could be a big cause, as it requires everything to be drawn 20 times per second (in your usage). Text and vectors can be expensive to redraw.
// Non-interactive elements (block all mouse interactions)
element.mouseEnabled = element.mouseChildren = false;
// Interactive elements (reduce mouse-checking children individually)
element.mouseChildren = false;
If they don't change, you might consider caching text elements, or button graphics. I think I saw some caching in the source - but its generally a good thing to consider.
--
With that said, debugging optimization can be tough.. If removing all the buttons brings your performance up, consider how your buttons are being constructed, and what their cost is.
* Mouse over is expensive
* Vectors and text can be expensive
* Caching can help when used right, but can be expensive if it happens too often.
* Review what is happening on tick(). Sometimes, code is running constantly, which doesn't need to.
--
A few other notes:
This does not do what you think: _oButton.off("mousedown"); -- You need to pass the result of the on() call. If you are just cleaning up, call _oButton.removeAllEventListeners().
You don't need to set the cursor on mouseover. The cursor will only change when it rolls over -- so just set it once, and then get rid of your buttonover stuff.
It might make sense to just extend EventDispatcher for your custom classes, which gives you things like the on() method, which supports a data param. I might recommend this in place of your addEventListener stuff in CTextButton
Note that RAF does not support a framerate property (it just uses the browser's RAF rate, which is usually 60fps). Use createjs.Ticker.timingMode instead of the deprecated useRAF.
Hope that helps a little.

Related

Counting how many layers exist at a specific position on the screen

My page is running a touchmove event which captures the position of the user's finger on the screen via:
xPos = e.originalEvent.touches[0].pageX;
yPos = e.originalEvent.touches[0].pageY;
The page has many layers (created with position:absolute divs) and at this point, I want to calculte how many such layers exist below the user's current position on the screen.
The only method I can think of is to have an array of all the layers' positions and loop through that. However that seems rather processor intensive when there may be hundreds of layers on screen at once.
Is there a simple way in js or JQuery to count the items that exist in a position, or a better practise way to do it than my array suggestion.
As far as I know, there is no such way. My approach would be to give all layers a certain class, select them all and iterate through them. Depending on what you are trying to achieve with this and how often you'll have to perform this calculation, it may be possible to use caching and approximation (e.g. not checking a certain pixel but an area of x^2 pixels and caching the result, etc) to make things run faster.
That being said, I encourage you to first try the solution that you've thought of and see how fast it actually runs. Browsers are pretty fast for such standard operations (think layer drag & drop with boundary checks), so I'm pretty confident that it won't be as slow as you think it will be :)

How to control the framerate in KineticJS?

How can I control the rendering loop frame rate in KineticJS? The docs for Kinetic.Animation show a frame rate being passed to the render callback, and Kinetic.Tween seems to have no frame rate logic, but I don't see anyway to force, say, a 30fps when 60fps is possible.
Loads of context for the curious follows, but the question is that simple. If anyone reads on, other advice is welcome. If you already know the answer, don't waste your time reading on!
I'm developing a music app that combines some DOM-based GUI controls (current iteration using jQuery Mobile) and Canvas-based GUI controls (using KineticJS). The latter involve some animation. Because the animated elements are triggered by music playback, I'm using Kinetic.Tween to avoid the complexity of remembering how long a given note has been playing (which Kinetic.Animation would require doing).
This approach works great at 60fps in Chrome (on a fast machine) but is just slow enough on iOS 6.1 Safari (iPad 2) that manipulating controls while animations are happening gets a little janky. I'm not using WebGL (unless KineticJS or Chrome does this by default for canvas?), and that's not an option when I package for native UIWebView.
As I'm getting beyond prototype into wanting to make more committed tech decisions, I see the following options, in order of perceived goodness:
Figure out how to cap the frame rate. Because my animations heavily use alpha fades but do not involve motion, I believe I could get away with 20-30fps and look fine. Could also scale this up on faster devices.
Don't respond immediately to touch inputs, but add them to a queue which I poll at a constant interval and only use the freshest for things like touchmove. This has no impact on my non-interactive animated elements, but tackles the problem from the other direction, trying to reduce the load of user interaction. This would require making Kinetic controls static and manually tracking touch coordinates (not terrible effort if it actually helped).
Rewrite DOM-based GUI to canvas-based (KineticJS); rewrite WebAudio-based engine to HTML5 audio; leverage CocoonJS or Ejecta for GPU-acceleration. This means having to hand-code stuff like file choosers and nav menus and such (bad). Losing WebAudio is pretty serious as it eliminates features like DSP effects and very fine-grained, low-latency timing (which is working just fine on an iPad 2).
Rewrite the app to separate DOM based GUI and WebAudio from Canvas-based elements, leverage CocoonJS. I'm not sure if/how well this works out, but the fact that CocoonJS passes JavaScript code as strings between the 2 components makes me very skittish about how solid this idea is. It's probably doable, but best case I'm very tied to CocoonJS moving forwards. I don't like architecting this way, but maybe it's not as bad as it sounds?
Make animations less juicy. This is least good not because of its design impact but because, as it is, I'm only animating ~20 simple shapes at any time in my central view component, however they include transparency and span an area ~1000x300. Other components like sliders are similarly bare-bones. In other words, it's not very juicy right now.
Overcome severe allergy to Objective-C; forget about the browser, Android, and that other mobile OS. Have a fast app that performs natively and has shiny Apple-approved widgets. My biggest problem with this approach is not wanting to be stuck in Objective-C reality for years, skillset-wise. I just don't like it.
Buy an iPad 3 or later. Since I already am pretending Android doesn't exist (I don't have any devices to test), why not pretend no one still has iPad 2? I think this is passing the buck -- if I can get acceptable performance on iPad 2, I will feel confident about the app's performance as I add more features.
I may be overlooking options or otherwise naive about how to tackle this. Some would say what I'm trying to build is just silly. But it's working pretty well just not ready for prime time on the iPad 2.
Yes, you can control the Kinetic.Animation framerate
The Kinetic.Animation sends in a frame object which has a frame.time property.
That .time is a running timer that you can use to throttle your animation speed.
Here's an example that throttles the Kinetic.Animation: http://jsfiddle.net/m1erickson/Hn3cC/
var lastTime;
var frameDelay=1000;
var loop = new Kinetic.Animation(function(frame) {
var time = frame.time
if(!lastTime){lastTime=time;}
var elapsed = time-lastTime;
if(elapsed>=frameDelay){
// frameDelay has expired, so animate stuff now
// set lastTime for the next loop
lastTime=time;
}
}, layer);
loop.start();
Working from #markE's suggestions, I tried a few things and found a solution. It's ultimately not rocket science, but sharing what I figured out:
First, tried the hack of doubling Tween durations and targets, using a timer to stop them at 50%. This kinda sorta worked but was hard to get to look good and was pretty error prone in coding bogus targets like negative opacity or height or whatnot.
Second, having read the source to Tween and looked at docs again for Animation, decided I could locally use Animation instances instead of Tween instances, and allow the closure scope to hang onto the relevant note properties. Eventually got this working smoothly and finally realized a big Duh! which is that throttling the frame rate of several independently animating things does not in any way throttle the overall frame rate.
Lastly, decided to give my component a render() method that calls itself in a loop with requestAnimationFrame, exits immediately if called before my clamp time, and inside render() I update all objects in the Kinetic canvas and call layer.drawScene(). Because there is now only one animation, this drops frame rate to whatever I need and the app is fast on iPad 2 (looks exactly the same to my eyes too).
So Kinetic is still helping for its higher level canvas API, and so far my other control widgets are still easy code using Kinetic to handle user input and dragging, now performing much better as the big beast component is not eating up the CPU.
The short answer to my original question is that no, you can't lock the overall frame rate for very complex animations, but as Mark said, you can for anything that fits in a single Animation instance.
Note that I could have still used Animation without giving it a layer or explicitly calling any draw() methods, but since I'd still have to write all the logic to determine individual element's current visual state, there was no gain to doing this. What would be very useful would be if Tween could accept a parameter to not automatically render. This would simplify code like mine, as I could shorthand the animation on individual objects but still choose when to actually do the heavy lifting of rendering everything. Seeing how much this whole exercise gained in performance on the iPad 2, might be worth adding this option to the framework.

How to avoid redrawing evey objects at each frame in paper.js

How to avoid redrawing eveything at each frame in paper.js?
I suppose I have to detach the frame event from the view view.detach('frame');, and then call draw manually every time I want to update something ?
This is very usefull to make drawing applications.
EDIT
Here is an example of what I want to avoid (click to toggle copies visibility):
the framerate decreases drastically when I show many other shapes (since everything is redrawn at each frame) but the copies could be drawn only on click and then let untouched (the framerate would be always high).
Just in case:
Symbols are not a solutions here, this is maybe a better example of what I want to achieve. The trails are fading away since the canvas is not cleared at each frame, just darkened.
I found some infos about here, it seems redraw optimizations are not implemented yet.
Ok, I implemented the persistence request here, but I didn't pull it yet.
You can check two examples: the tail effect and the performance benchmark (click to toggle visibility of modified clones, press 'space' to toggle persistence).
You can find the example code here, under drawings.

Animating multiple DIV-Elements with JS and the DOM results in a low Framerate

Preface
I just started programming with javascript and I am currently working on this hobby web-site project of mine. The site is supposed to display pages filled with product images than can be "panned" to either the left or right. Each "page" containing about 24 medium sized pictures, one page almost completely fills out an entire screen. When the user chooses to look at the next page he needs to click'n'drag to the left (for example) to let a new page (dynamically loaded through an AJAX script) slides into the view.
The Issue
This requires for my javascript to "slide" two of these mentioned pages synchronously by the width of a screen. This results in a really low framerate. Firefox and Opera lag a bit, Chrome has it especially bad: 1 frame of animation takes approx. 100 milliseconds, thus making the animation look very "laggy".
I do not use jQuery, nor do I want to use it or any other library to "do the work for me". At least not until I know for sure that what I am trying to do can not be done with a couple of lines of self-written code.
So far I have figured out that the specific way I manipulate the DOM is causing the performance-drop. The routine looks like this:
function slide() {
this.t = new Date().getTime() - this.msBase;
if( this.t > this.msDura ) {
this.callB.call(this.ref,this.nFrames);
return false;
}
//calculating the displacement of both elements
this.pxProg = this.tRatio * this.t;
this.eA.style.left = ( this.pxBaseA + this.pxProg ) + 'px';
this.eB.style.left = (this.pxBaseB + this.pxProg) + 'px';
if ( bRequestAnimationStatus )
requestAnimationFrame( slide.bind(this) );
else
window.setTimeout( slide.bind(this), 16 );
this.nFrames++;
}
//starting an animation
slide.call({
eA: theMiddlePage,
eB: neighboorPage,
callB: theCallback,
msBase: new Date().getTime(),
msDura: 400,
tRatio: ((0-pxScreenWidth)/400),
nFrames: 0,
ref: myObject,
pxBaseA: theMiddlePage.offsetLeft,
pxBaseB: neighboorPage.offsetLeft
});
Question
I noticed that when I let the AJAX script load less images into each page, the animation becomes much faster. The separate images seem to create more overhead than I have expected.
Is there another way to do this?
THE JAVASCRIPT SOLUTION
OK, there are two possible things for you to try to speed this up.
First of all, when you modify the style of an element, you force the browser to rerender the page. This is called a repaint. Certain changes also force a recalculation of the page's geometry. This is called a reflow. A reflow always triggers a repaint immediately after it. I think why you're experiencing worse performance with more elements is that each update to each one triggers at least a repaint. What is normally recommended in the case of modifying multiple styles on a single element is to either do them all at once by adding or removing a class, or hide the element, do your manipulations, and then show it, which means only two repaints (and possibly reflows).
It appears that in this particular case, you're probably already doing just fine, as you're only manipulating each item once per iteration.
Second of all, requestAnimationFrame() is good for doing animations on a canvas element, but seems to have somewhat dodgy performance on DOM elements. Open your page in Chrome's profiler to see exactly where it hangs up. Try JUST using setTimeout() to see if that ends up being the case. Again, the profiler will tell you where the hang-ups are. requestAnimationFrame() should be better, but validate this. I've had it backfire on me, before.
THE REAL SOLUTION
Don't do this in JavaScript, if you can at all avoid it. Use CSS transitions and translation to do the animation with a JavaScript function registered as the onTransitionEnd event handler for each animated element. Letting the browser do this stuff natively is almost always faster than any JS code anyone can write.
The only catch is that CSS3 animations are only supported by the newer browers. For your own edification, do it this way. For real, practical applications, delegate to a library. A good library will do it natively, if possible, and fall back to the best way of doing it in JS for the older browsers.
Good link to read regarding this stuff: http://www.html5rocks.com/en/tutorials/speed/html5/

Regarding a JavaScript mouse event anomaly I'm having trouble with

I'm in the process of designing a small RPG-like interface where the user will be given the freedom to create the items and weapons they use. Rest assured, that particular system is thought deeply through and is not the cause of my concern. : )
No, it is something related to the mechanism I have set up for the actual drawing of the user's items. I could try to put the design in words, but it would probably be most beneficial if I just took you there, so click here before continuing.
Not bad, eh? It works practically without flaw in everything but IE (haven't coded for it in years), except for one minor issue; it is, in fact, so minor, that I'm quite certain almost all players would use the interface without ever paying it any attention. I, however, am something of a nitpicker with my own designs, and toiling over this one for hours has, alas, led me here.
So, Stack Overflow JavaScript gurus, a bit of help regarding this issue:
At the moment, there are two ways by which you can inject color into the canvas; you can just click squares individually, or you can drag the mouse and fill in tiles as you go along. Well, give that second option a go. Now, did you notice that, while the dragging most definitely occured, your drag didn't actually initiate until you'd moved out of the square you began in.
Sure, no big deal, just go back and single-click the spot that got missed. And that is definitely something that I wouldn't mind settling with; at this point, though, it's just a matter of understanding why it is the code isn't working exactly as it should. Any help would be greatly appreciated.
Also, a run-down of the algorithm if you aren't able to decipher my code:
global variable md (mouse down) set to 0 at start
document.onmousedown sets md to 1; conversely, onmouseup puts it back at 0
user's currently selected color is stored as an index in cur_color
palette of user's colors stored in palette array
palette[cur_color] references the user's currently selected color
upon moving over a tile, if the mouse is being held down, toggle() function initiates
toggle() compares the backgroundColor of the tile in question with the user's cur_color
if they are different, cur_color overwrites, effectively "painting" that portion of the canvas
this continues until the user has let go of their mouse button
Overall a pretty basic method, but that whole mouse-being-pressed-not-registering-until-one-square-late thing is killing me. Again, assistance with getting to the bottom of this matter would most definitely be appreciated.
It's because you don't call tile_over when mousing down initially. Reading through the steps above you can see that.
Here's a fix, add this to the onmousedown function:
var target = e.target || e.srcElement;
if (target.tagName == 'DIV' && target.className == 'tile') {
tile_over(target);
}
Obviously having a framework to handle getting the targets of mouse events and so forth would make this easier.
You'll need to remove the toggle that occurs when you mouseup without having triggered a mouseover, I didn't bother tracking that down as it should be obvious.

Categories