Improving animation performance on mobile devices using AngularJS

I've reached the final stages of developing a mobile application using AngularJS wrapped in a cordova webview. However, I'm encountering some issues with the panel transition animations.

After experiencing strange behavior with ngAnimate, I decided to utilize two divs that remain in the DOM permanently to encapsulate the current and next panel content I compile. To animate them, I turned to the GSAP Framework, known for its performance. Yet, the animations are still sluggish.

To troubleshoot, I conducted a frame-by-frame profiling using Chrome Dev Tools Timeline and discovered that my scripting time was excessively long during controller initialization.

As a solution, I have come up with two ideas: either find a way to detect when the controller initialization is complete (though unsure how in Angular) or devise a method to spread out the execution across multiple frames.

Could anyone provide guidance in this matter?

Below is the structure in index.html:

<!doctype html>
<html ng-app="SparterApp" lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
        <title>MyApp</title>
        <link rel="stylesheet" href="styles/styles.css">
    </head>
    <body>

        <div id="panelCtrl" ng-controller="panelCtrl">
            <nav id="menu" ng-include="'views/menu.html'"></nav>
            <section id="currentPanel"></section>
            <section id="nextPanel"></section>
        </div>
        <script src="bower_components/angular/angular.min.js"></script>
        <script src="scripts/TweenMax.min.js"></script>
        <!-- Various vendor scripts and custom Angular scripts -->
    </body>
</html>

Here is my panel controller code:

'use strict';

angular.module('SparterApp')
    .controller('panelCtrl', function ($scope, $compile, $http, $timeout, animService) {

        nextPanelHandler = $('#nextPanel');
        currentPanelHandler = $('#currentPanel');
        var protect = false;

        $scope.callbackNextPanel = function () {
            currentPanelHandler.hide();
            nextPanelHandler.attr('id', 'currentPanel');
            currentPanelHandler.attr('id', 'nextPanel');
            var buffer = nextPanelHandler;
            nextPanelHandler = currentPanelHandler;
            currentPanelHandler = buffer;
            protect = false;
        };



        /*
        **  Load the next panel in the 'section.nextPanel' element, compile it with angular, and execute the setted animation
        **
        **  templateUrl : the desired template url relative to the views folder or 'close' for closing popup
        **  options : an object with two attributes
        **      enterClass : the initialisation class for the next panel
        **      time : the time of the animation
        **  params : an object with all the arguments you want to transfer between panels
        */

        $scope.nextPanel = function (templateUrl, options, params) {
            // Prevent multi trigger
            if (!protect) {
                protect = true;
                var tl = new TimelineLite({
                    paused: true,
                    onComplete: $scope.callbackNextPanel
                });

                // Get a initialisation in a list
                var enterAnimFrom = animService.getAnimFrom(options.enterClass);
                enterAnimFrom.onComplete = nextPanelHandler.show;
                //Prepare the animation
                tl.fromTo(
                    nextPanelHandler,
                    options.time,
                    enterAnimFrom,
                    {
                        x: 0,
                        y: 0,
                        scale: 1,
                        rotation: 0,
                        opacity: 1,
                        ease: options.ease
                    },
                    'start'
                );
                // Get the template to compile
                var newPanel = $http({method: 'GET', url: 'views/' + templateUrl})
                .success(function(data, status, headers, config) {
                    nextPanelHandler.html(data);
                    $scope.params = params;
                    $compile(nextPanelHandler.contents())($scope);
                    // Play the animation
                    tl.play();
                })
                .error(function(data, status, headers, config) {
                    alert('An error occured with the next panel loading');
                });
            }
        };

    });

Lastly, here is the structure of a panel:

<div ng-controller="loginCtrl" class="panel">
    <!-- Panel content goes here -->
</div>

If sharing the timeline would aid in resolving the issue, please let me know.

Answer №1

Sharing some personal challenges encountered while trying to implement animations reliably. I've found that GSAP struggles with full-page animations on mobile devices, requiring various optimization attempts to improve performance. Despite its dominance in comparison to CSS animations, the rendering process seems to pose a challenge for GSAP. A related discussion can be found at . Currently, I rely on CSS3 transitions for my website but still utilize GSAP for smaller animation tasks rather than full-page transitions.

Transitioning between whole pages presents varying degrees of difficulty based on page size and transition type, especially on tablets and phones. In my experience, iOS devices outperform Android counterparts, with recent improvements noted in FireFox over the past 8 months.

One major advantage of GSAP is its consistent performance across different platforms, with minimal frame rate discrepancies. On the other hand, CSS3 lacks this universal compatibility and often leads to time-consuming troubleshooting efforts. In cases where cssTransitions are not supported, I have resorted to using JQuery.animate, although it may not be as aesthetically pleasing as CSS equivalents.

Additionally, there seem to be limitations related to caching strategies for optimizing graphics acceleration, particularly when transitioning from a long scrolling page to a shorter one. Despite these challenges, I anticipate improvements in the future as technologies evolve.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilize jQuery to extract various input/select box values and compile them into an array for submission using .ajax()

I am currently facing an issue with dynamically generated forms using PHP and updated with jQuery's .appendTo() function as visitors interact with it. My main goal is to collect all input text and select box values from the current form and submit the ...

The .each method is failing to iterate over the next object

Currently, I have been working with JSON data retrieved from the web. After successfully receiving the data, I proceed to create a JavaScript object to work with it. However, there seems to be an issue with retrieving the values of fname and lname from th ...

Unable to proceed due to lint errors; after conducting research, the issue still remains

I'm still getting the hang of tslint and typescript. The error I'm encountering has me stumped. Can someone guide me on resolving it? I've searched extensively but haven't been able to find a solution. Sharing my code snippet below. (n ...

The method this.$refs.myProperty.refresh cannot be invoked as it is not a valid

I have added a reference value 'callingTable' to a vue-data-table (using vuetify) like so: <v-data-table :headers="callingTableHeaders" :items="getCallingDetails" class="elevation-1" ref="callingTable&quo ...

Executing a Java program within a Docker container with the help of dockerode

I'm looking to send Java code as a string to an API for execution in a Docker container and then retrieve the console output. While I have successfully done this with Python, the process is different for Java since it needs to be compiled before runni ...

What is the process for updating button text upon clicking in Angular?

To toggle the text based on whether this.isDisabled is set to false or true, you can implement a function that changes it when the button is clicked. I attempted to use this.btn.value, but encountered an error. import { Component } from '@angular/core ...

Creating a JavaScript array in Rails 4 based on current data without the need to reload the webpage

Currently in my rails 4 app, I am working on a unique tags validation using jquery validate to ensure that tags are not duplicated before they can be added to an item. The tag list structure is as follows: <div id="taglist"> <span class="label ...

Using router.get with a redirect in Express

Can you directly invoke a router.get(...) function in Express? Let's say I have a router.get('/my-route', function(req, res) { ... });, is it feasible to then, within another part of my code, use res.redirect('my-route'); with the ...

Odd behavior of the "for in" loop in Node.js

It seems like I'm struggling with the use of the "for in" statement. When working with a JSON document retrieved from a mongodb query (using nodejs + mongoose), its structure looks something like this: [{ "_id":"596f2f2ffbf8ab12bc8e5ee7", "da ...

When running `aws-cdk yarn synth -o /tmp/artifacts`, an error is thrown stating "ENOENT: no such file or directory, open '/tmp/artifacts/manifest.json'"

Starting a new aws-cdk project with the structure outlined below src └── cdk ├── config ├── index.ts ├── pipeline.ts └── stacks node_modules cdk.json package.json The package.json file looks like this: " ...

Could a personalized "exit page" confirmation be created?

I am looking for a solution that will allow me to pause the execution of my code, display a dialog box, and then resume execution only after a specific button is pressed. For example, if a user navigates from one page to another on my website, I want a di ...

What could be causing the $httpProvider.interceptors to unexpectedly return an 'undefined' value?

Having some trouble parsing the response of my basic AngularJS app that consumes Yelp's API using $httpProvider.interceptors. This is the structure of my app: var app = angular.module("restaurantList", []); The yelpAPI service handles authenticatio ...

Adjust the svg rate using jQuery or JavaScript

Seeking help with a gauge I found on CodePen - struggling to adjust bubble values... <path id="Fill-13" fill="#F8B50F" d="M3.7 88.532h26.535v-#.795H3.7z"/> Can change the bars in JS, but not the bubbles using jq/js. Adjust the gauge with values be ...

There seems to be a problem with the output when trying to display the message "You said ${reply}"

In the following code snippet, vanilla.js is being used with ATOM as the text editor and running on nodejs via terminal: 'use strict'; const Readline = require('readline'); const rl = Readline.createInterface({ input:process.stdin, ...

Delay loading external JavaScript within an AngularJS controller by utilizing lazy loading

For certain routes, I need functionality from external JS files but I don't want to load them all at once. Each route requires different JS (e.g. /upload needs photo uploading JS, /photos needs lightbox JS, /funny needs animation JS, etc). What is th ...

Passing a single item from a list as a prop in Vue.js

Imagine having the following set of information in data: data: { todos: [ { id: 1, title: "Learn Python" }, { id: 2, title: "Learn JS" }, { id: 3, title: "Create WebApp" } ] } Now, I aim to send only the item with an id of 2 t ...

Conceal / reveal with jQuery

I am attempting to hide all divs and only display those connected with the "button" class. However, I'm encountering an issue where only the last div is visible, regardless of which div/button was clicked. EDIT: Here is the complete HTML code: < ...

Perform simple arithmetic operations between a number and a string using Angular within an HTML context

I'm stuck trying to find a straightforward solution to this problem. The array of objects I have contains two values: team.seed: number, team.placement: string In the team.placement, there are simple strings like 7 to indicate 7th place or something ...

Tips for triggering several functions with a single onClick event in React?

I am currently working on a React Project where I have defined several functions to set conditions for rendering components on the page. However, I now need to be able to call all these functions again within the components when a button is clicked, in ord ...

Restricting Checkbox Choices with JavaScript by Leveraging the forEach Function

I am developing a checklist application that limits the user to selecting a maximum of three checkboxes. I have implemented a function to prevent users from checking more than three boxes, but it is not working as expected. The function detects when an ite ...