-->

Improving slow canvas animation on Retina iPad - K

2020-03-25 06:51发布

问题:

I am using KineticJS to perform HTML Canvas animations. Animations work perfectly on all desktop browsers, and non retina iDevices (including iPad mini). However, from a retina device (browser or in-app webview using appcelerator) these animations are very sluggish. I have seen similar issues with canvas animations on retina display, but have not found any true solution.

My Stage constructor is 1024w x 768h. All images are preloaded. And animations are constructed using the preloader's callback function.

If I reduce my stage size by half (and scale inner contents accordingly), the animation will play almost normally (still a little choppier than other ipads). My only justification for trying this was my very poor understanding that a retina display is two 'points'/pixel.

Any insight or ideas are welcome. My next attempt is to start changing image resolutions, rather than scaling dynamically.

回答1:

This is due to a feature added four months ago. KineticJS will recognize if the pixelratio of the device is over 1 and try to make it as sharp as with pixelratio 1. The problem is, like you have found out, that it kills the performance to the point that it's useless. We have found this to be the case for our use cases.

Our solution: We commented out the pixel ratio part in KineticJS and hard coded it to always be one.

Pros:

The performance goes back up to normal

Cons:

Image is not as sharp

This is the part where we have made the change:

Kinetic.Canvas = function(width, height, pixelRatio) {
// eduplus change to fix pixel ratio performance problems
this.pixelRatio = 1; //pixelRatio || _pixelRatio;

When discussing this with Eric, he made comments to investigate pixel ratio performance, but I don't think he has had the time to do that yet. Hope this helps!



回答2:

Using KineticJS 5 or above (I am not sure when exactly this global setting was introduced), the simplest and least intrusive way to do this is to set Kinetic.pixelRation to your desired value before instantiating your stage:

Kinetic.pixelRatio = 1;
var stage = new Kinetic.Stage({
    ...
});


回答3:

I use this before instantiating my Stage to overload pixelRatio without modifying KineticJS's source file. (Saves you from having to update the source file after any updates.)

https://gist.github.com/echong/6107722

CoffeeScript:

# Adjust device pixel ratio
for className in ["HitCanvas", "SceneCanvas", "Canvas"]
    Kinetic[className].prototype.init = ((p_method) -> (p_config={}) ->
        p_config.pixelRatio = 1
        p_method.call @, p_config
    ) Kinetic[className].prototype.init

JavaScript:

_ref = ["HitCanvas", "SceneCanvas", "Canvas"];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
  className = _ref[_i];
  Kinetic[className].prototype.init = (function(p_method) {
    return function(p_config) {
      if (p_config == null) {
        p_config = {};
      }
      p_config.pixelRatio = 1;
      return p_method.call(this, p_config);
    };
  })(Kinetic[className].prototype.init);
}