PDA

View Full Version : Embed Animation Within Sencha Touch App Without iFrame



rockinthesixstring
13 Dec 2011, 3:00 PM
What is the best way to embed an Animation inside a Sencha Touch app without using an iFrame?

This is what I'm trying, but unfortunately I don't see any animation.

index-debug.html

<!DOCTYPE html>
<head>
<title></title>

<!-- sencha css-->
<link rel="stylesheet" type="text/css" href="http://cdn.sencha.io/touch/sencha-touch-2.0.0-pr1/resources/css/sencha-touch.css" />
<!-- sencha library -->
<script type="text/javascript" src="/lib/sencha-touch-all-debug-w-comments.js"></script>
<!--<script type="text/javascript" src="http://cdn.sencha.io/touch/sencha-touch-2.0.0-pr1/sencha-touch-all-debug-w-comments.js"></script>-->

<!-- rpc styling -->
<link rel="stylesheet" type="text/css" href="css/site/overrides.css" />
<link rel="stylesheet" type="text/css" href="css/site/elements.css" />
<link rel="stylesheet" type="text/css" href="css/site/icons.css" />
<link rel="stylesheet" type="text/css" href="css/site/containers.css" />
<link rel="stylesheet" type="text/css" href="css/site/buttons.css" />
<link rel="stylesheet" type="text/css" href="css/site/home-banner.css" />


<!-- code -->
<!-- HERE IS THE BANNER CODE-->
<script type="text/javascript" src="app/code/home-banner.js"></script>

<!-- app start -->
<script type="text/javascript" src="app/index.js"></script>

<!-- models -->

<!-- stores -->

<!-- partial views -->
<script type="text/javascript" src="app/views/bible/_bibleInAYearView.js"></script>
<script type="text/javascript" src="app/views/bible/_chapterADayView.js"></script>

<!-- views -->
<script type="text/javascript" src="app/views/home/indexView.js"></script>
<script type="text/javascript" src="app/views/bible/indexView.js"></script>
<script type="text/javascript" src="app/views/video/index.js"></script>
<script type="text/javascript" src="app/views/contact/indexView.js"></script>
<script type="text/javascript" src="app/views/more/indexView.js"></script>

<!-- controllers -->
<script type="text/javascript" src="app/controllers/homeController.js"></script>
<script type="text/javascript" src="app/controllers/bibleController.js"></script>
<script type="text/javascript" src="app/controllers/videoController.js"></script>
<script type="text/javascript" src="app/controllers/contactController.js"></script>
<script type="text/javascript" src="app/controllers/moreController.js"></script>


</head>
<body>

</body>
</html>



HomeIndex View

Ext.define('rpc.view.home.indexView', {
extend: 'Ext.Panel',
alias: 'widget.home-indexView',
config: {
scrollable: true,
items: [{
xtype: 'toolbar',
title: 'RockPointe Mobile',
docked: 'top'
}, {
xtype: 'panel',
items: [{
xtype: 'panel',
items: [{
html: '<div><ol id="AN-sObj-parentOl"><li id="AN-sObj-scene-0"><div class="AN-sObj-stage" id="ext-gen1760"><div class="AN-Object" id="AN-sObj-34"><div id="AN-sObj-val-34"><img src="img/banner-1.jpg"></div></div><div id="AN-sObj-35"><span>Relentlessly Focused On The Lost</span></div><div id="AN-sObj-36"><span>Passionately Devoted To God</span></div><div id="AN-sObj-37"><span>Deeply Committed To One Another</span></div></div></li></ol></div>'
}]
}]
}]
},
initialize: function () {
console.log('rpc.view.home.indexView ~ initialize');
loadHomeBanner(); // Call the Banner Load Function
this.callParent();
}
});

home-banner.css (as output by Sencha Animator)

#AN-sObj-scene-0 .AN-sObj-stage {
border:0 !important;
}

.AN-sObj-stage {
position: relative;
overflow:hidden;
-webkit-perspective: 600;
}

.AN-sObj-stage div {
position: absolute;
}

.AN-sObj-stage a {
color: inherit;
text-decoration:none;
}

.AN-sObj-stage * {
margin:0;
padding:0;
-webkit-font-smoothing: antialiased;
}

.AN-sObj-stage img {
position: absolute;
top:0;
left:0;
}

body,.AN-sObj-stage,ol,li {
margin:0;
padding:0;
}

ol {
list-style:none;
position:relative;
}

li {
position:absolute;
top:0;
left:0;
}

.AN-Scene-Description {
display: none;
}

@-webkit-keyframes AN-ani-delay {
0% {
}

100% {
}

}

li {
display:none;
}

li.run {
display:block;
}

.restart * {
-webkit-animation-name: none !important;
}

#AN-sObj-34{
-webkit-transform: translate3d(0px, 0px, 0px);
width: 600px;
height: 150px;
top:0;
left:0;
}

#AN-sObj-35{
-webkit-transform: translate3d(70px, 95px, 0px);
width: 236px;
height: 23px;
top:0;
left:0;
font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
font-size: 14px;
font-weight: bold;
text-shadow: rgba(255,255,255,0.5) 1px 1px 3px;
}

#AN-sObj-36{
-webkit-transform: translate3d(140px, 63px, 0px);
width: 211px;
height: 19px;
top:0;
left:0;
font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
font-size: 14px;
text-shadow: rgba(255,255,255,0.5) 1px 1px 3px;
font-weight: bold;
}

#AN-sObj-37{
-webkit-transform: translate3d(35px, 29px, 0px);
width: 257px;
height: 19px;
top:0;
left:0;
font-family: "Helvetica Neue", Arial, Helvetica, Geneva, sans-serif;
font-size: 14px;
font-weight: bold;
text-shadow: rgba(255,255,255,0.5) 1px 1px 3px;
}

#AN-sObj-scene-0 .AN-sObj-stage {
height: 150px;
width: 600px;
background-color: rgba(255,255,255,1);
border:1px solid rgba(10,10,10,1);
}

@-webkit-keyframes AN-ani-38 {
0% {
-webkit-transform: translate3d(70px, 95px, 0px);
opacity: 0;
}
81.9% {
-webkit-transform: translate3d(70px, 95px, 0px);
opacity: 0;
}
100% {
-webkit-transform: translate3d(70px, 95px, 0px);
opacity: 1;
}
}

.run #AN-sObj-35 {
-webkit-animation-name: AN-ani-38;
-webkit-animation-duration: 11.170238095238094s;
-webkit-animation-delay: 0s;
-webkit-animation-fill-mode: both;
}
.restart #AN-sObj-35 {
-webkit-transform: translate3d(70px, 95px, 0px);
opacity: 0;
}
@-webkit-keyframes AN-ani-39 {
0% {
-webkit-transform: translate3d(140px, 63px, 0px);
opacity: 0;
}
72.02% {
-webkit-transform: translate3d(140px, 63px, 0px);
opacity: 0;
}
100% {
-webkit-transform: translate3d(140px, 63px, 0px);
opacity: 1;
}
}

.run #AN-sObj-36 {
-webkit-animation-name: AN-ani-39;
-webkit-animation-duration: 7.166883116883118s;
-webkit-animation-delay: 0s;
-webkit-animation-fill-mode: both;
}
.restart #AN-sObj-36 {
-webkit-transform: translate3d(140px, 63px, 0px);
opacity: 0;
}
@-webkit-keyframes AN-ani-40 {
0% {
-webkit-transform: translate3d(35px, 29px, 0px);
opacity:0;
-webkit-transform-origin: 50% 50%;
}
0.01% {
-webkit-transform: translate3d(35px, 29px, 0px);
opacity: 0;
-webkit-transform-origin: 50% 50%;
}
100% {
-webkit-transform: translate3d(35px, 29px, 0px);
opacity: 1;
-webkit-transform-origin: 50% 50%;
}
}

.run #AN-sObj-37 {
-webkit-animation-name: AN-ani-40;
-webkit-animation-duration: 1.9545454545454553s;
-webkit-animation-delay: 1.2s;
-webkit-animation-fill-mode: both;
}
.restart #AN-sObj-37 {
-webkit-transform: translate3d(35px, 29px, 0px);
opacity: 0;
-webkit-transform-origin: 50% 50%;
}

home-banner.js (as output by Animator)


function loadHomeBanner(){
console.log('Loading Home Banner');

if (typeof(AN) === 'undefined') {
AN = {};
}
AN.Controller = {

scenes: {},
scenesArray: [],
currentSceneID: -1,
olElement: null,
clickEvents: {},
useOrmma: false,

setConfig: function(configData) {

this.clickEvents = configData.clickEvents

this.olElement = document.getElementById(configData.parentId);
var liElements = this.olElement.children;

if (configData.ormma) {
this.useOrmma = true;
}

var scene;
for (var i=0; i < configData.scenes.length; i++) {
scene = configData.scenes[i];
scene.element = liElements[i];
this.scenes[scene.id] = scene;
this.scenesArray.push(scene);
}

this.setupListeners();

this.startSceneByID(this.scenesArray[0].id);



},


runningAnimationCount: 0,

setupListeners: function() {
var me = this;

this.olElement.addEventListener('webkitAnimationStart', function() {

},false);

this.olElement.addEventListener('webkitAnimationEnd', function() {
me.onAnimationEnd();
},false);

function addMousemoveListenerTo(scene) {
scene.element.addEventListener('mousemove', function(event){
scene.mousemoveAction(me, event);
}, false);
}

var scene;
for (var i=0; i < this.scenesArray.length; i++) {
scene = this.scenesArray[i];
if (scene.mousemoveAction) {

addMousemoveListenerTo(scene);
}
}

function addListenerTo(element, event, aFunction) {
element.addEventListener(event, function(event){
aFunction(me,event);
}, false);
}

//add click events
var element, clickEvent;
for (var i=0; i < this.clickEvents.length; i++) {
clickEvent = this.clickEvents[i];
element = document.getElementById(clickEvent.id);
addListenerTo(element, 'click', clickEvent.handler);
}

},


onAnimationEnd: function() {

this.runningAnimationCount--;

if (this.runningAnimationCount === 0) {
this.onSceneFinish();
}

},

startSceneByID: function(sceneID) {

var me = this;

//restart current scene without flicker
if (sceneID === this.currentSceneID) {
this.scenes[sceneID].element.setAttribute('class','run restart');

setTimeout(function(){

me.runningAnimationCount = me.scenes[sceneID].animationCount;
me.scenes[sceneID].element.setAttribute('class','run');

if (me.scenes[sceneID].startAction) {
me.scenes[sceneID].startAction(me);
}
if (me.scenes[sceneID].animationCount === 0 ) {
me.onSceneFinish();
}

},0);
return;
} else if (this.currentSceneID !== -1) {
this.scenes[this.currentSceneID].element.setAttribute('class','');
}

this.runningAnimationCount = this.scenes[sceneID].animationCount;

this.currentSceneID = sceneID;
var nextScene = this.scenes[sceneID];
nextScene.element.setAttribute('class','run');


if (this.useOrmma) {

this.ormmaNextScene(nextScene);
}


if (nextScene.startAction) {
nextScene.startAction(this);
}
if (nextScene.animationCount === 0 ) {
this.onSceneFinish();
}


},

replayScene: function() {
this.startSceneByID(this.currentSceneID);
},

onSceneFinish: function() {

if (this.scenes[this.currentSceneID].endAction) {
this.scenes[this.currentSceneID].endAction(this);
}

},

goToNextScene: function() {
var nextIndex = this.scenesArray.indexOf(this.scenes[this.currentSceneID]) + 1;
var nextScene;
if (nextScene = this.scenesArray[nextIndex]) {
this.startSceneByID(nextScene.id);
}
},

goToURL: function(aURL) {
document.location.href = aURL;
},

ormmaNextScene: function(nextScene) {
var currentState = ormma.getState();

if (nextScene.dimensions.expanded) {
//expanded state
//check if we're expanded
var maxSize = ormma.getMaxSize()
if (currentState !== 'expanded') {
ormma.expand({
x:0,
y:0,
width: maxSize.width,
height: maxSize.height
})
}

var transform = "";
var elementHeight = nextScene.element.offsetHeight;
var elementWidth = nextScene.element.offsetWidth;
var y = (maxSize.height - elementHeight) / 2;
var x = (maxSize.width - elementWidth) / 2;
transform += " translate3d("+Math.round(x)+"px,"+Math.round(y)+"px,0)";


if (nextScene.dimensions.fit) {
var scaleFactor = Math.min(maxSize.width/elementWidth, maxSize.height/elementHeight);
transform += " scale3d("+scaleFactor+","+scaleFactor+",1)";
}
nextScene.element.style.webkitTransform = transform;

} else {

if (currentState === 'expanded') {
ormma.close();
}
ormma.resize(nextScene.dimensions.width,nextScene.dimensions.height);
}


}

}




window.addEventListener('load', function(){
var configData = {
parentId: 'AN-sObj-parentOl',
ormma: false,
scenes: [{id: 0,animationCount: 3,duration: 11170.238095238094,dimensions: {height: 150,width: 600,expanded: false,fit: false},startAction: function(controller,event) {
//set your scene dimensions
var sceneWidth = 600;
var sceneHeight = 150;

//get container for all scenes
var scenesContainer = document.querySelector('#AN-sObj-parentOl');

//get the parent of the scene container and it's size
var parentElement = scenesContainer.parentElement;
var pageWidth = parentElement.clientWidth;
var pageHeight = parentElement.clientHeight;

//calculate the scaling factor
var scaleFactor = Math.min(pageWidth/sceneWidth, pageHeight/sceneHeight);
var transform = " scale3d("+scaleFactor+", "+scaleFactor+", 1)";

//apply the scaling
scenesContainer.style.webkitTransformOrigin = "0 0";
scenesContainer.style.webkitTransform = transform;

}}],
clickEvents: []
};
AN.Controller.setConfig(configData);
}, false);
};

arnebech
13 Dec 2011, 6:34 PM
Normally the animation listens for the window load event, but since you put it into a function that your are calling after the window load event the animation will never initialize.

so you could try moving out of the load event e.g. something like this



//this is what you have at the end of your home-banner.js
window.addEventListener('load', function(){
var configData = {.....};
AN.Controller.setConfig(configData);
},false);


//try removing the listener wrapper
//so you end up with something like this
var configData = {.....};
AN.Controller.setConfig(configData);

rockinthesixstring
13 Dec 2011, 7:47 PM
Normally the animation listens for the window load event, but since you put it into a function that your are calling after the window load event the animation will never initialize.

so you could try moving out of the load event e.g. something like this



//this is what you have at the end of your home-banner.js
window.addEventListener('load', function(){
var configData = {.....};
AN.Controller.setConfig(configData);
},false);


//try removing the listener wrapper
//so you end up with something like this
var configData = {.....};
AN.Controller.setConfig(configData);


Now since I'm calling it from the `initialize` method, it's being called before the html section is rendered. What are the other methods other than initialize? I'm looking in the docs, but am not being very successful.



Ext.define('rpc.view.home.indexView', {
extend: 'Ext.Panel',
alias: 'widget.home-indexView',
config: {},
initialize: function () {
loadHomeBanner();
}
});

rockinthesixstring
13 Dec 2011, 7:59 PM
Sorry, this part of the question probably belongs in the ST2 forum.

rockinthesixstring
13 Dec 2011, 8:58 PM
Your answers worked as needed. Now all I need to do is figure out how to execute the function after the DOM is painted. Working through it in the ST2 forum.

arnebech
14 Dec 2011, 10:11 AM
Sounds good. When you figure it out, feel free to post that tidbit here so other forum users can benefit from it as well. Thanks.

rayman1900
20 Jan 2012, 7:10 AM
I was able to control the animation by doing this:



items: [ {
xtype:'panel',
id:'square',
fullscreen:true,
html:'<ol id="AN-sObj-parentOl"><li id="AN-sObj-scene-0"><div class="AN-sObj-stage" id="ext-gen3864"><div id="AN-sObj-5"></div></div></li></ol>',
listeners:{
afterRender:function(){

var configData = {
parentId: 'AN-sObj-parentOl',
ormma: false,
scenes: [{id: 0,animationCount: 1,duration: 4256.753246753247,dimensions: {height: 248,width: 300,expanded: false,fit: false}}],
clickEvents: []
};
AN.Controller.setConfig(configData);

}
},
items:[
{
xtype:'button',
listeners:{
el:{
tap:function(){
AN.Controller.replayScene();

}
}
}

}
],



----So as you can see, no need to encapsulate your export js file into a loadHomeBanner() founction.

What you can do is to implement the configData variable with all his content into a listeners that listen when the panel has finished rendering, then call your variable configData, and voila !

Then if you want, like proposed in my code, you can create inside that panel a button and listen for a tap that will trigger one of the function linked to the animation, like the replayScene() function !

Hope this code will come handy for all those people who want to insert their animations without an iframe tag !

Sincerely, I was excited to try this software, but I found so little documentation on the sencha animator help page regarding alternatives to import your animation into sencha's other products, like sencha touch or Ext.js...this is a great letdown for me...:(

Well, better share my knowledge with other sencha devs, since there is almost no documentation available on this kind of problem... Enjoy ;)

Best regards,
Ray

rockinthesixstring
20 Jan 2012, 9:33 AM
Thanks Ray
I've already got a similar bit working, however my problem lies in the fact that I cannot get the width to change properly.

If I go from portrait to landscape, then my 100% width animation expands to fill the screen properly.

If I go from landscape to portrait, then my 100% width animation stays the width of landscape mode... thus leaving all of the rest of the objects in the view to overflow off the right hand side of my screen.

rayman1900
20 Jan 2012, 10:04 AM
What kind of animation are you making? an ad or simply an animated image over some sort of panel ?

rockinthesixstring
20 Jan 2012, 10:12 AM
What kind of animation are you making? an ad or simply an animated image over some sort of panel ?

I figured out my problem. The suggestion made to me in order to dynamically adjust the width was to use


var pageHeight = parentElement.clientWidth;

After setting the smoke alarm off from my brain churning away, I changed that line to this


var pageWidth = Ext.viewport.getWidth();

Works like a champ.

rayman1900
20 Jan 2012, 10:54 AM
It's great that you figured out !

CaliLuke
27 Feb 2012, 11:26 PM
I would be very curious to see what is the final product of this. We would like to support this use case natively inside Animator pretty soon.