janpaepke / ScrollMagic

The javascript library for magical scroll interactions.
http://ScrollMagic.io
Other
14.8k stars 2.17k forks source link

Potential Bug in plugins/animation.gsap.js #977

Open rexcheng1997 opened 3 years ago

rexcheng1997 commented 3 years ago

Version

I am using ScrollMagic with React and webpack. Tricky configurations are needed to get the code compiled with webpack but I think the main problem lies in the source code itself.

Issue

I appreciate all the efforts made by the development team to accommodate different versions of gsap in animation.gsap.js. Since the latest version of gsap wraps TweenMax, TimelineMax, TweenLite, TimelineLite, etc. into the gsap object, the current version of animation.gsap.js doesn't work with the lastest gsap@^3.5.1.

All the following code snippets are taken from scrollmagic/uncompressed/plugins/animation.gsap.js.

The error is related to the function Scene.setTween. The following is the error message shown in the console when setTween is called:

TypeError: Tween.to is not a function (animation.gsap.js: 255)

Backtracking where the variable Tween is initialized, I found the following chunk of code which caused the problem:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['ScrollMagic', 'gsap', 'TweenMax', 'TimelineMax'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        // Loads whole gsap package onto global scope.
        var gsap = require("gsap/dist/gsap") || require("gsap");

        // TweenMax/TimelineMax will be global in v2. In v3, they will be on the gsap object
        factory(require('scrollmagic'), gsap, TweenMax || gsap, TimelineMax || gsap);
    } else {
        // Browser globals
        factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic), root.gsap, root.gsap || root.TweenMax || root.TweenLite, root.gsap || root.TimelineMax || root.TimelineLite);
    }
}(this, function (ScrollMagic, Gsap, Tween, Timeline) { ... }

(lines 28-43 in animation.gsap.js)

This is basically where the gsap module is loaded. In the latest version of gsap, objects like TweenMax and TimelineMax are wrapped as a member of the gsap module so the gsap object is not equivalent to either TweenMax or TimelineMax. This is why when Tween.to is called later, it is not a function (gsap object doesn't have a key called to).

To solve the issue, I modified the above code as below:

(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define(['ScrollMagic', 'gsap', 'TweenMax', 'TimelineMax'], factory);
    } else if (typeof exports === 'object') {
        // CommonJS
        // Loads whole gsap package onto global scope.
        var gsap = require("gsap/dist/gsap") || require("gsap");

        // TweenMax/TimelineMax will be global in v2. In v3, they will be on the gsap object
        factory(require('scrollmagic'), gsap, TweenMax || gsap.TweenMax, TimelineMax || gsap.TimelineMax);
    } else {
        // Browser globals
        factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic), root.gsap, root.TweenMax || root.TweenLite || root.gsap.TweenMax || root.gsap.TweenLite, root.TimelineMax || root.TimelineLite || root.gsap.TimelineMax || root.gsap.TimelineLite);
    }
}(this, function (ScrollMagic, Gsap, Tween, Timeline) { ... }

After fixing this, there is another bug in line 275 of animation.gsap.js:

if (parseFloat(TweenLite.version) >= 1.14) { ... }

Here, TweenLite is not defined before so you will get a undefined error in the console. To solve it, just replace TweenLite with Tween.

How to reproduce the issue

  1. Load the scripts for ScrollMagic and gsap of the above version in the page.
  2. Initialize a controller, create a scene with setTween, and add the scene to the controller.
  3. Load the page in the browser (I'm using Chrome) and you should see the error.

Part of the code is pasted below for reference:

const controller = new ScrollMagic.Controller();
const scene = new ScrollMagic.Scene({
  triggerElement: '#demo',
  duration: '100%',
  reverse: true
}).setTween('#animate-element', {
  // some css properties
}).addTo(controller);
laurabennett commented 3 years ago

I'm having a similar problem. Here is the code and error msg.

Uncaught TypeError: Cannot read property 'to' of undefined at O.Scene.f.setTween (animation.gsap.js:1) at HTMLDocument. (themagic.js:1) at e (jquery-3.4.1.min.js:1) at t (jquery-3.4.1.min.js:1)

$(function() { // wait for document ready // init var controller = new ScrollMagic.Controller({ globalSceneOptions: { triggerHook: 'onEnter', } });

// get all images
var images = document.querySelectorAll(".image");

// create scene for every image
for (var i = 0; i < images.length; i++) {
  new ScrollMagic.Scene({
      triggerElement: images[i]
    })
    .setTween(images[i], 0.5, {scale: 1.1})
    .addIndicators()
    .addTo(controller);
}

});