patternjavascriptMinor
Scroll Magic Multiple Scenes
Viewed 0 times
magicscrollscenesmultiple
Problem
I am using Scroll Magic for the first time and I am in general very new to JavaScript/jQuery. I got it to work but it is very messy and repetitive code.
Here is the fiddle. This is the messy code (I just gave this as an example, in my project there is about 50 scenes after each other in this manner!):
Is there any way I can make this code more DRY?
Here is the fiddle. This is the messy code (I just gave this as an example, in my project there is about 50 scenes after each other in this manner!):
var controller = new ScrollMagic.Controller();
var tween1 = TweenMax.to('#animation1', 0.7, {
opacity: 0
});
var scene1 = new ScrollMagic.Scene({
offset: 200,
reverse: true
})
.setTween(tween1)
.addTo(controller)
.addIndicators();
var tween2 = TweenMax.to('#animation2', 0.7, {
opacity: 1
});
var scene2 = new ScrollMagic.Scene({
triggerHook: 'onEnter',
offset: 500,
reverse: true
})
.setTween(tween2)
.addTo(controller)
.addIndicators();Is there any way I can make this code more DRY?
Solution
I'm posting this with an assumption that the JsFiddle is missing something since it throws a "setTween is not a function" error. But given your code...
What you really want is a factory object, which gets provided some config data. Perhaps something in this format:
Let's just call this "animation factory"
Then to use it:
Not you've got a nice clean API to use. But you said there are 50 of them on the page, and I imagine that number could change. Additionally, you have a disconnect between the animations and the elements that require them. Why not marry the two in wedded bliss using HTML5 custom data attributes?
And to use this:
And a little HTML for good measure:
This gives you unlimited potential. The configs for creating the animations are embedded right in the markup. If different pages had different animations, no need to keep different JavaScript files around. Every page can be different.
Since the
If you AJAX in some HTML, then insert it into a DIV after page load, the
What you really want is a factory object, which gets provided some config data. Perhaps something in this format:
{
"tween": {
"duration": 0.7,
"options": {
"opacity": 0
}
},
"scene": {
"options": {
"triggerHook": "onEnter",
"offset": 500,
"reverse": true
}
}
}Let's just call this "animation factory"
AnimationFactory:function AnimationFactory() {
this.controller = new ScrollMagic.Controller();
this.scenes = [];
}
AnimationFactory.prototype = {
controller: null,
scenes: null,
constructor: AnimationFactory,
createAnimation: function(element, args) {
element = typeof element === "string"
? document.getElementById(element)
: element;
var tween = TweenMax.to(element, args.tween.duration, args.tween.options),
scene = new ScrollMagic.Scene(args.scene.options);
scene.setTween(tween)
scene.addTo(this.controller)
scene.addIndicators();
this.scenes.push(scene);
return this;
}
};Then to use it:
var animationFactory = new AnimationFactory();
window.onload = function() {
animationFactory
.createAnimation("animation1", {
tween: {
duration: 0.7,
options: {
opacity: 1
}
},
scene: {
options: {
offset: 200,
reverse: true
}
}
})
.createAnimation( ... );
};Not you've got a nice clean API to use. But you said there are 50 of them on the page, and I imagine that number could change. Additionally, you have a disconnect between the animations and the elements that require them. Why not marry the two in wedded bliss using HTML5 custom data attributes?
function AnimationFactory() {
this.controller = new ScrollMagic.Controller();
this.scenes = [];
}
AnimationFactory.prototype = {
controller: null,
scenes: null,
constructor: AnimationFactory,
createAnimation: function(element, args) {
...
},
createAnimations: function(element) {
var tween = null,
scene = null,
elements = element.querySelectorAll("[data-animation]"),
i = 0,
args;
for (i; i < elements.length; i++) {
args = JSON.parse(elements[i].getAttribute("data-animation"));
this.createAnimation(elements[i], args);
}
}
};And to use this:
var animationFactory = new AnimationFactory();
window.onload = function() {
animationFactory.createAnimations(document.body);
};And a little HTML for good measure:
Animation 1
Animation 2This gives you unlimited potential. The configs for creating the animations are embedded right in the markup. If different pages had different animations, no need to keep different JavaScript files around. Every page can be different.
Since the
AnimationFactory encapsulates all of the animations, you can tweak the work flow behind the scenes if you run into performance problems, like staggering the creation of the Tweens so you don't have 50 opacity tweens run all at once on the page (which I image might draw enough electricity from the CPU to power a small Tesla).If you AJAX in some HTML, then insert it into a DIV after page load, the
AnimationFactory#createAnimations method can be called, and pass in the HTML element that just had its innerHTML replaced and you'll get animations after AJAX, not just on page load.// xhr is an XMLHttpRequest object that just got some HTML from the server
var div = $("#someDiv").html(xhr.responseText);
animationFactory.createAnimations(div[0]);Code Snippets
{
"tween": {
"duration": 0.7,
"options": {
"opacity": 0
}
},
"scene": {
"options": {
"triggerHook": "onEnter",
"offset": 500,
"reverse": true
}
}
}function AnimationFactory() {
this.controller = new ScrollMagic.Controller();
this.scenes = [];
}
AnimationFactory.prototype = {
controller: null,
scenes: null,
constructor: AnimationFactory,
createAnimation: function(element, args) {
element = typeof element === "string"
? document.getElementById(element)
: element;
var tween = TweenMax.to(element, args.tween.duration, args.tween.options),
scene = new ScrollMagic.Scene(args.scene.options);
scene.setTween(tween)
scene.addTo(this.controller)
scene.addIndicators();
this.scenes.push(scene);
return this;
}
};var animationFactory = new AnimationFactory();
window.onload = function() {
animationFactory
.createAnimation("animation1", {
tween: {
duration: 0.7,
options: {
opacity: 1
}
},
scene: {
options: {
offset: 200,
reverse: true
}
}
})
.createAnimation( ... );
};function AnimationFactory() {
this.controller = new ScrollMagic.Controller();
this.scenes = [];
}
AnimationFactory.prototype = {
controller: null,
scenes: null,
constructor: AnimationFactory,
createAnimation: function(element, args) {
...
},
createAnimations: function(element) {
var tween = null,
scene = null,
elements = element.querySelectorAll("[data-animation]"),
i = 0,
args;
for (i; i < elements.length; i++) {
args = JSON.parse(elements[i].getAttribute("data-animation"));
this.createAnimation(elements[i], args);
}
}
};var animationFactory = new AnimationFactory();
window.onload = function() {
animationFactory.createAnimations(document.body);
};Context
StackExchange Code Review Q#92144, answer score: 6
Revisions (0)
No revisions yet.