Skip to content
This repository has been archived by the owner on Jan 15, 2019. It is now read-only.

Commit

Permalink
Basic implementation of GSAP animations w/ push & pop
Browse files Browse the repository at this point in the history
Signed-off-by: Jarrod Payne <[email protected]>
  • Loading branch information
paynecodes committed Jun 2, 2014
1 parent 5b2528c commit b6b7f24
Show file tree
Hide file tree
Showing 5 changed files with 290 additions and 5 deletions.
13 changes: 12 additions & 1 deletion Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,18 @@ module.exports = function (grunt) {
"underscore": "../bower_components/underscore/underscore",
"backbone": "../bower_components/backbone/backbone",
"backbone.marionette": "../bower_components/backbone.marionette/lib/backbone.marionette",
"almond": "../bower_components/almond/almond"
"almond": "../bower_components/almond/almond",
'gsap.tweenlite': '../bower_components/gsap/src/uncompressed/TweenLite',
'gsap.cssplugin': '../bower_components/gsap/src/uncompressed/plugins/CSSPlugin'
},
shim: {
'gsap.cssplugin': {
exports: 'CSSPlugin'
deps: ['gsap.tweenlite']
},
'gsap.tweenlite': {
exports: 'TweenLite'
}
},
include: ['almond', 'AnimatedRegion', 'Transitioner'],
exclude: ['jquery', 'underscore', 'backbone', 'backbone.marionette'],
Expand Down
13 changes: 9 additions & 4 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "MarionetteTransition",
"description": "Make your dancing Marionette apps transition beautifully.",
"version": "0.1.8",
"version": "0.3.1",
"private": false,
"license": "MIT",
"main": [
Expand All @@ -17,10 +17,14 @@
"transition",
"page",
"animation",
"animate"
"animate",
"gsap"
],
"authors": [
{ "name": "Jarrod Payne", "email": "[email protected]" }
{
"name": "Jarrod Payne",
"email": "[email protected]"
}
],
"ignore": [
"src/bower_components",
Expand All @@ -42,7 +46,8 @@
"dependencies": {
"modernizr": "^2.6.0",
"jquery": "1.8.0 - 1.11.0",
"backbone.marionette": "^1.5.0"
"backbone.marionette": "^1.5.0",
"gsap": "~1.11.8"
},
"devDependencies": {
"requirejs": "~2.1.11",
Expand Down
3 changes: 3 additions & 0 deletions scripts/ngrok
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#! /bin/bash
# script to run ngrok with subdomain
ngrok 9000
254 changes: 254 additions & 0 deletions src/scripts/MarionetteTransition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
define(['jquery', 'underscore', 'backbone.marionette', 'gsap.tweenlite', 'gsap.cssplugin', 'animations/horizontalSlideToPosition'], function($, _, Marionette, TweenLite, CSSPlugin, horizontalSlideToPosition) {
'use strict';

var MarionetteTransition = Marionette.Region.extend({
initialize: function(options) {
this.views = [];
this.currentViewIndex = -1;
},
showTransition: function(view, options) {
this.ensureEl();

var showOptions = options || {};
var isViewClosed = view.isClosed || _.isUndefined(view.$el);
var isDifferentView = view !== this.currentView;

this.preventClose = !!showOptions.preventClose;

// only close the view if we don't want to preventClose and the view is different
var _shouldCloseView = !this.preventClose && isDifferentView;

view.render();
this._triggerBeforeShow(view);

this.addViewToDom(view);
this._triggerRepaint();

var transition = this.transitionToView(view, this.currentView, showOptions);
transition.done(_.bind(function() {
console.log('cleaning up views');
this._cleanUpViews();
}, this));

this.currentView = view;

this._triggerShow(view);

return this;
},
push: function(view, options) {
this.ensureEl();

var pushOptions = options || {};

pushOptions.push = true;

this.preventClose = true;
var _shouldCloseView = this.preventClose;

view.render();
this._triggerBeforeShow(view);
this._triggerBeforePush(view);

this.addViewToDom(view);
this._triggerRepaint();

this.transitionToView(view, this.currentView, pushOptions);

this.currentView = view;

this._triggerShow(view);
this._triggerPush(view);

this.addView(view);

return this;
},
pop: function(options) {
if (this.currentViewIndex <= 0 || this.views.length <= 1) return this;

this.ensureEl();

var popOptions = options || {};

popOptions.pop = true;

this.preventClose = false;
var _shouldCloseView = this.preventClose;

var currentView = this.currentView;
var newView = this.views[this.currentViewIndex - 1];

this._triggerBeforeShow(newView);
this._triggerBeforePop(newView);

this.transitionToView(newView, currentView, popOptions);

this.currentView = newView;

this._triggerShow(newView);
this._triggerPop(newView);

this.removeView();

return this;
},
transitionToView: function(newView, currentView, options) {
this.prepareCommonOptions(options);
this.prepareRegionContainer();
this.prepareNewView(newView, options);
if (currentView && currentView.$el) {
this.prepareCurrentView(currentView, options);
}

var self = this;
var deferred = $.Deferred();

_.defer(function() {
_.delay(transition, 20);
});

function transition() {
var enterAnimation = self.enterAnimation(newView, options);

if (currentView && currentView.$el) {
enterAnimation.eventCallback('onStart', function() {
self.exitAnimation(currentView, options);
});
}

enterAnimation.eventCallback('onComplete', function() {
self._triggerTransitionEnd(newView);
if (currentView && !self.preventClose) currentView.close();
deferred.resolve();
});
}

return deferred;
},
prepareCommonOptions: function(options) {
options.distance = this.$el.width();
options.duration = .4;
},
prepareRegionContainer: function() {
this.$el.css({
'position': 'relative'
})
},
prepareNewView: function(view, options) {
view.$el.css({
'position': 'absolute',
'width': '100%',
'transform': 'matrix(1, 0, 0, 1,' + options.distance + ', 0)',
'-webkit-transform': 'matrix(1, 0, 0, 1,' + options.distance + ', 0)',
'-moz-transform': 'matrix(1, 0, 0, 1,' + options.distance + ', 0)',
'-ms-transform': 'matrix(1, 0, 0, 1,' + options.distance + ', 0)',
'-o-transform': 'matrix(1, 0, 0, 1,' + options.distance + ', 0)'
});
},
prepareCurrentView: function(view, options) {
view.$el.css({
'position': 'absolute',
'width': '100%'
});
},
addViewToDom: function(view) {
this.$el.append(view.el);
},
enterAnimation: function(view, options) {
return horizontalSlideToPosition(view.$el, 0, options);
},
exitAnimation: function(view, options) {
if (options.pop) {
return horizontalSlideToPosition(view.$el, options.distance, options);
} else {
return horizontalSlideToPosition(view.$el, -150, _.extend(options, { opacity: "0" }))
}
},
addView: function(view) {
this.views.push(view);
this.currentViewIndex++;
},
removeView: function(index) {
index = index || this.views.length - 1;
this.views.splice(index, 1);
this.currentViewIndex--;
},
_cleanUpViews: function() {
_.each(this.views, function(view, index) {
view.close();
});

this.views = [this.currentView];
this.currentViewIndex = 0;
},
_triggerRepaint: function() {
this.$el.get(0).offsetHeight;
},
_triggerBeforeShow: function(view) {
Marionette.triggerMethod.call(this, "before:show", view);

if (_.isFunction(view.triggerMethod)) {
view.triggerMethod("before:show");
} else {
Marionette.triggerMethod.call(view, "before:show");
}
},
_triggerShow: function(view) {
Marionette.triggerMethod.call(this, "show", view);

if (_.isFunction(view.triggerMethod)) {
view.triggerMethod("show");
} else {
Marionette.triggerMethod.call(view, "show");
}
},
_triggerBeforePush: function(view) {
Marionette.triggerMethod.call(this, "before:push", view);

if (_.isFunction(view.triggerMethod)) {
view.triggerMethod("before:push");
} else {
Marionette.triggerMethod.call(view, "before:push");
}
},
_triggerPush: function(view) {
Marionette.triggerMethod.call(this, "push", view);

if (_.isFunction(view.triggerMethod)) {
view.triggerMethod("push");
} else {
Marionette.triggerMethod.call(view, "push");
}
},
_triggerBeforePop: function(view) {
Marionette.triggerMethod.call(this, "before:pop", view);

if (_.isFunction(view.triggerMethod)) {
view.triggerMethod("before:pop");
} else {
Marionette.triggerMethod.call(view, "before:pop");
}
},
_triggerPop: function(view) {
Marionette.triggerMethod.call(this, "pop", view);

if (_.isFunction(view.triggerMethod)) {
view.triggerMethod("pop");
} else {
Marionette.triggerMethod.call(view, "pop");
}
},
_triggerTransitionEnd: function(view) {
Marionette.triggerMethod.call(this, "transition:end", view);

if (_.isFunction(view.triggerMethod)) {
view.triggerMethod("transition:end");
} else {
Marionette.triggerMethod.call(view, "transition:end");
}
}
});

return MarionetteTransition;
});
12 changes: 12 additions & 0 deletions src/scripts/animations/horizontalSlideToPosition.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
define(['gsap.tweenlite', 'gsap.cssplugin'], function(TweenLite, CSSPlugin) {
'use strict';

var horizontalSlideToPosition = function(el, position, options) {
return new TweenLite.to(el, options.duration, {
x: position + "px",
opacity: options.opacity || "1"
});
};

return horizontalSlideToPosition;
});

0 comments on commit b6b7f24

Please sign in to comment.