zarocknz / javascript-winwheel

Create spinning prize wheels on HTML canvas with Winwheel.js
http://dougtesting.net
MIT License
527 stars 360 forks source link

animation is very laggy on android #3

Closed saqueib closed 8 years ago

saqueib commented 8 years ago

First of thanks for the amazing wheel library, it has everything anyone can imagine. :+1:

I used this in ionic app for mobile. I am facing one issue. the animation is so laggy on android & on iOS its good at lest its feels like spinning.

android version i have tested is 4.4

Is there anyway we can improve this?

zarocknz commented 8 years ago

Hi, thanks for your feedback.

I'll take a look in to this. Are you able to answer these questions to help me...

  1. Have you tested on device (actual phone) or just in the emulator for Android?
  2. Was the slowness for a code-drawn wheel (the default) or image wheel, or both?
  3. Is the version of Winwheel.js you are using >= 2.3? The older versions had some unnecessary code in the drawing methods which would have made it slower than needed.

Cheers, DouG.

zarocknz commented 8 years ago

@saqueib also can you please let me know the settings being passed to the Winwheel constructor for your wheel? It might help me focus on an area of the code. Thanks.

saqueib commented 8 years ago

Hi DouG,

  1. I have tested on Device which is running 4.4 and on iPhone 5s (which works)
  2. it was default wheel from sample provided
  3. You dont support bower installation so I pulled it from here, TweenMax version is 1.18.0 and I cant find version mentioned in doc blocks

Here is my wheel code

.controller('foodOfFortuneCtrl', function($scope, $ionicPopup) {
    // Create new wheel object specifying the parameters at creation time.
    var theWheel = new Winwheel({
        'numSegments'  : 8,     // Specify number of segments.
        'outerRadius'  : 148,   // Set outer radius so wheel fits inside the background.
        'textFontSize' : 28,    // Set font size as desired.
        'lineWidth'   : 2,
        'segments'     :        // Define segments including colour and text.
        [
           {'fillStyle' : '#f1f656', 'text' : 'Prize 1'},
           {'fillStyle' : '#29c932', 'text' : 'Prize 2'},
           {'fillStyle' : '#217dc8', 'text' : 'Prize 3'},
           {'fillStyle' : '#9d28c8', 'text' : 'Prize 4'},
           {'fillStyle' : '#f1f656', 'text' : 'Prize 5'},
           {'fillStyle' : '#29c932', 'text' : 'Prize 6'},
           {'fillStyle' : '#217dc8', 'text' : 'Prize 7'},
           {'fillStyle' : '#9d28c8', 'text' : 'Prize 8'}
        ],
        'animation' :           // Specify the animation to use.
        {
            'type'     : 'spinToStop',
            'duration' : 5,     // Duration in seconds.
            'spins'    : 10,     // Number of complete spins.
            'callbackFinished' : 'window.alertPrize()'
        }
    });

    $scope.wheelSpinning = false;

    // -------------------------------------------------------
    // Click handler for spin button.
    // -------------------------------------------------------
    function startSpin()
    {
        // Ensure that spinning can't be clicked again while already running.
        if ($scope.wheelSpinning == false)
        {
            theWheel.animation.spins = 9;

            // Begin the spin animation by calling startAnimation on the wheel object.
            theWheel.startAnimation();

            // Set to true so that power can't be changed and spin button re-enabled during
            // the current animation. The user will have to reset before spinning again.
            $scope.wheelSpinning = true;
        }
    }

    // -------------------------------------------------------
    // Function for reset button.
    // -------------------------------------------------------
    function resetWheel()
    {
        theWheel.stopAnimation(false);  // Stop the animation, false as param so does not call callback function.
        theWheel.rotationAngle = 0;     // Re-set the wheel angle to 0 degrees.
        theWheel.draw();                // Call draw to render changes to the wheel.

        $scope.wheelSpinning = false;        // Reset to false to power buttons and spin can be clicked again.
        $scope.$apply();
    }

    // -------------------------------------------------------
    // Called when the spin animation has finished by the callback feature of the wheel because I specified callback in the parameters.
    // -------------------------------------------------------
    window.alertPrize = function()
    {
        // Get the segment indicated by the pointer on the wheel background which is at 0 degrees.
        var winningSegment = theWheel.getIndicatedSegment();

        // Do basic alert of the segment text. You would probably want to do something more interesting with this information.
        $ionicPopup.alert({
            title: 'Success',
            content: "You have won " + winningSegment.text
          });

        //resetWheel();
    }

    $scope.spinIt = startSpin;
})
zarocknz commented 8 years ago

Hi, been looking in to this for most of this morning.

After some googling see that the JavaScript performance on some Android phones is not that great. What is the make and model of the Android device you are testing with please?

When I run the example wheel up on my site on my Android 4.3 device in the Chrome browser it runs pretty OK, not silky smooth but is useable.

Also what browser and version is being used on the Android device you are testing with?

Some android browsers did not support requestAnimationFrame which is used for the animation loop until recently. http://caniuse.com/#feat=requestanimationframe I believe the GreenSock animation platform falls back to setTimeout to do the animation loop in this case which would result in quite bad performance.

I have added a Frames Per Second (FPS) display and logging to the console feature to the wheel in this branch https://github.com/zarocknz/javascript-winwheel/tree/fps-counter. And also created an example on my site which uses it http://dougtesting.net/winwheel/experimental.

To use the fps display feature pass either 'displayFps' : true and/or 'logFps' : true in to the winwheel constructor. If you want to log the fps to the content of a div on the screen rather than the console specify the id of the dom element setting the fpsLogElementId property of the wheel (the logFps has to be true as well).

Can you please either change your code to point to the Winwheel.js in the fps-counter branch and try turning the fps display or logger on and let me know what frame rate you are getting on your Android device? Or can you please visit http://dougtesting.net/winwheel/experimental on your Android device and let me know what FPS you are getting there (note the on-screen log does degrade the FPS somewhat - could not figure out how to get access to the console on my mobile browser working which is why I logged it onscreen there instead).

Also: I did think of one thing which might speed up the animation a wee bit as it removes one operation each frame of the spinning. Try setting clearTheCanvas : false in the animation properties and please let me know if any real difference.

And: does your wheel need to be code drawn? Could you create a png image of the wheel face instead as I believe this would be a lot less intensive during animation as the code does not have to draw all the segments and text each frame. See this tutorial for creating a wheel using an image http://dougtesting.net/winwheel/docs/tut9_creating_with_an_image. Please let me know if you try this and if the FPS is any better or worse.

I'll keep thinking on this.

Thanks, DouG.

saqueib commented 8 years ago

Thanks for detailed explanation, I am using Redmi Note 3G to test it

Some android browsers did not support requestAnimationFrame which is used for the animation loop until recently. http://caniuse.com/#feat=requestanimationframe I believe the GreenSock animation platform falls back to setTimeout to do the animation loop in this case which would result in quite bad performance.

I think this is the reason, I used another device with android 5.5 and animation is improved.

I have added a Frames Per Second (FPS) display and logging to the console feature to the wheel in this branch https://github.com/zarocknz/javascript-winwheel/tree/fps-counter. And also created an example on my site which uses it http://dougtesting.net/winwheel/experimental.

Tested this, its giving me 16-20 fps

Also: I did think of one thing which might speed up the animation a wee bit as it removes one operation each frame of the spinning. Try setting clearTheCanvas : false in the animation properties and please let me know if any real difference.

adding this doesn't feels anything changed, same animation

'animation' :           // Specify the animation to use.
 {
    'type'     : 'spinToStop',
    'duration' : 5,     // Duration in seconds.
    'spins'    : 10,     // Number of complete spins.
    'clearTheCanvas' : false,
    'callbackFinished' : 'window.alertPrize()'
}

And: does your wheel need to be code drawn? Could you create a png image of the wheel face instead as I believe this would be a lot less intensive during animation as the code does not have to draw all the segments and text each frame. See this tutorial for creating a wheel using an image http://dougtesting.net/winwheel/docs/tut9_creating_with_an_image. Please let me know if you try this and if the FPS is any better or worse.

This is the winner, using PNG it is running smooth, I will be using this

Thanks for the help :smile: