An Interest In:
Web News this Week
- March 27, 2024
- March 26, 2024
- March 25, 2024
- March 24, 2024
- March 23, 2024
- March 22, 2024
- March 21, 2024
Create a Mobile App Using Famo.us and Angular
I love
high-performance JavaScript, and I love sharing what I believe is its true
potential. In this tutorial, I want to focus on Famo.us, which can allow you to
maintain a silky-smooth 60 frames per second while having fluid animations on
screen.
Famo.us does this by utilizing the CSS3 primitive -webkit-transform:
, which lets the framework compute the composite matrix and skip the
matrix3d
browser’s renderer. No plug-in, no download, no hack. By appending this to each
DIV, developers can render the composite matrix and go straight to the GPU.
I go
more in-depth when discussing the ins and outs of Famo.us in this blogpost. Thanks to Zack Brown for all of his assistance with this! Let’s get started.
By the
end of this project you will be able to:
- understand
how Angular works within the context of a Famo.us application - harness
the true power of JavaScript and the good parts of HTML5 - create
smooth animations
My goal
for this project is to illustrate how easily you can create HTML5 and JavaScript projects
that work at near-native speeds on mobile applications.
Features
- The
mobile application runs on iOS and Android via Cordova. - The
Windows 10 universal app runs natively on, well, Windows 10. - This
project can also be run as a hosted website, although I have it scaled which is best for mobile devices.
Requirements
- PC
or Mac - Web
server - Cross-platform
test matrix (like a BrowserStack, IDE, or free virtual machines for EdgeHTML, the rendering
engine for Microsoft Edge and hosted web app content on Windows 10)
Setup
- Download
the source from GitHub. - Download
and install a web server (I use MAMP on OS X, or the built-in IIS server with Visual Studio on Windows).
Open the Project
- Start
your web server. - Navigate
to famous-angular-Pokemon/app/.
The
project is designed to work on mobile devices, so use the mobile emulator in
your browser to get the correct view. Here's what it would look like on an
iPhone 6 inside the emulator via the Chrome desktop browser (375x667):
How It
Works
Hitting
the Database
I pull
all of the information from the PokeAPI, which
has a well-documented API, but it's missing images for each of the Pokémon. For
the images, I just pull the name of the currently chosen Pokémon and append it to the end of this URL: https://img.pokemondb.net/artwork/. For
example: https://img.pokemondb.net/artwork/venusaur.jpg will lead you to an image
of Vanosaur. Nifty, right? Sadly, they do not have an API available.
Each
time the user presses the Next button, a random number
is generated between a min/max value that I've defined (say, 1 to 20), and it
pulls a Pokémon from the database that matches that number. Here's what it
looks like:
https://pokeapi.co/api/v1/pokemon/1/ returns a JSON object for
Bulbasaur. You can play with their API.
Looping
Through the Data
I then
loop through that JSON object and set the properties I find to variables
in Angular, using the $Scope
object.
Here's
an example:
/*
* Grab Pokemon from the DB
*/
$scope.getPokemon = function () {
// Generate a random num and use it for the next pokemon
getRandomInt($scope.minVal, $scope.maxVal);
// Retrieve data from DB and draw it to screen
$http.get($scope.dbURL + $scope.pokemonNum + "/")
.success(function(data) {
$scope.name = data.name;
$scope.imageUrl = $scope.imgDbURL + $scope.name.toLowerCase() + '.jpg';
/* 1) Empty out the current array to store the new items in there
* 2) Capitalize the first character for each ability from the database
* 3) Store that ability in a new abilityObj & add it into the abilities array
*/
$scope.abilities.length = 0;
for (var i = 0; i < data.abilities.length; i++){
var capitalizedString = capitalizeFirstLetter(data.abilities[i].name);
var abilityObj = {name: capitalizedString };
$scope.abilities.push(abilityObj);
}
$scope.hitPoints = data. hp;
var firstType = data.types[0].name;
$scope.types.name = capitalizeFirstLetter(firstType);
determineNewBgColor();
})
.error(function(status){
console.log(status);
$scope.name = "Couldn't get Pokemon from the DB";
});
};
You may
notice that I also have a few other functions here, such as capitalizeFirstLetter
, which
does exactly that. I wanted the abilities and type (e.g. poison, grass, flying)
to have the first letter capitalized, since they come back from the database in
all lowercase characters.
I also
loop through the abilities and push them to an ability object, which looks like this:
$scope.abilities = [
{ name: "Sleep"},
{ name: "Eat" }
];
The database
also returns multiple types for certain Pokémon, such as Charizard, who is
flying as well as fire. To keep things simple, though, I only wanted to return
one from the database.
$scope.types = { name: "Grass" };
var firstType = data.types[0].name;
Drawing It to the Screen
Famo.us
has two waves of drawing content to the screen by creating surfaces, which are the elements that contain your text, images,
etc.:
- JavaScript
- FA-Directives
(HTML)
I
didn't use JavaScript to draw the surfaces in this app. Instead I chose to use only FA (Famous-Angular) Directives, such as:
<!-- Name-->
<fa-modifier
fa-origin ="origin.center"
fa-align ="align.frontName"
fa-size ="size.frontName"
fa-translate ="trans.topLayer">
<fa-surface
class ="front-name-text">
{{name}}
</fa-surface>
</fa-modifier>
This is for the
name above the Pokémon on the front screen.
You'll
notice that the surface is wrapped by a fa-modifier
. You can read about those in the Famo.us documentation, but
they essentially adjust the properties of a surface, such as alignment, size,
and origin. It took me a while to wrap my head around the difference between
alignment and origin, so here's how I came to understand it.
Origin
This is the reference point on
any surface. If I want to draw a rectangle and move it around the screen, I
need to decide which point on that rectangle will be my starting point. The Famo.us docs explain it well. The
values are laid out as follows:
$scope.origin = {
// X Y
topLeft: [0, 0 ],
topRight: [1, 0 ],
center: [0.5, 0.5],
bottomLeft: [0, 1 ],
bottomRight: [1, 1 ]
};
Alignment
This is a surface's location on
the screen. When you make changes to the alignment, it is using the origin as
the reference point to start from.
$scope.align = {
// X Y
frontName: [0.50, 0.10],
frontImg: [0.50, 0.40],
backImg: [0.5, 0.38],
center: [0.50, 0.50]
};
Where
Angular Finally Comes In
Now
here's where you can put all of your Angular skills and data binding to work
with the Angular implementation. If you're already experienced with
Angular, then it's not radically different here.
<!-- Next button -->
<fa-modifier
fa-origin ="origin.center"
fa-align ="align.nextBtn"
fa-size ="size.btn"
fa-scale ="scale.nextBtn.get()"
fa-translate ="trans.topLayer">
<fa-surface
class ="one-edge-shadow center-align next-btn"
ng-click ="getPokemon(); nextBtnPressAnim(); frontImgAnim()">
{{nextBtn}}
</fa-surface>
</fa-modifier>
This
button appears on the first screen and simply pulls another Pokémon from the
database. All of the ng
(Angular) directives you are familiar with are here,
such as ng-click
. I have multiple functions
here. Notice that they are not comma-separated.
I am
also binding the value of $scope.nextBtn
to {{nextBTn}}
in HTML.
To
allow Famo.us and Angular to work together, we need to include $Famo.us
at the
top of our JavaScript file. Here's how you do it:
angular.module('famousAngularStarter')
.controller('PokemonCtrl', ['$scope', '$http', '$famous', function ($scope, $http, $famous) {
/* Inject famo.us to DOM */
var View = $famous['famous/core/View' ];
var Modifier = $famous['famous/core/Modifier' ];
var Surface = $famous['famous/core/Surface' ];
var Transform = $famous['famous/core/Transform' ];
var Transitionable = $famous['famous/transitions/Transitionable'];
var Timer = $famous['famous/utilities/Timer' ];
Animations
What
would a high-performance app be without animations? Famo.us is packed with
them, which makes it easy to get started. Here's one for animating the image on
the front.
/*
* @OnClick: Sets the opacity and scale for the front image when user clicks "Next" btn
* 1) Turns opacity invisible quickly before returning to original opacity, revealing new Pokemon
* 2) Turns scale down before quickly turning it back up to original size
*/
$scope.frontImgAnim = function() {
var hideDuration = 200;
var returnDuration = 1300;
$scope.opac.imgFront. set(0, {duration: hideDuration, curve: "easeIn"},
function returnToOrigOpacity() {
$scope.opac.imgFront.set(1, {duration: returnDuration, curve: "easeIn"})
}
);
$scope.scale.imgFront .set([0.5, 0.5], {duration: hideDuration, curve: "easeIn"},
function returnToOrigSize() {
$scope.scale.imgFront.set([0.8, 0.8], {duration: returnDuration, curve: "easeIn"})
}
)
};
There
are several curve types you can use here. Checkout the docs for more info. I'm
also using a callback function, returnToOrigSize
, to have the image grow
and then shrink back to the original size.
Points
of Frustration
I ran
into a few issues along the way.
FA-Directives Have Their Properties Set as Strings
fa-origin ="origin.center"
If you
have a spelling error, the app will just use the default values for that
property. This snagged me several times, which is why you see I set all of my
properties as an object, such as align.frontName
, to
make it easier to read.
Adding
Classes
In
FA-Directives you add multiple classes as strings and they are not comma-separated.
<fa-surface
class ="one-edge-shadow center-align next-btn"
ng-click ="infoBtnPressAnim(); flip()">
{{infoBtnText}}
</fa-surface>
If you
try to add classes by creating surfaces in JavaScript, you pass in an array of
strings.
var logo = new Surface({
properties: {
...
},
classes: ['backfaceVisibility, class-two']
});
It took
me a while to understand that, as I only found the solution in thisthread.
Famo.us
+ Angular Seems to Be Deprecated (For Now)
Midway
through this project, I saw that Famo.us was working on an improved version of
the framework that includes Mixed Mode. Famo.us + Angular doesn't
take advantage of these additions (yet) at least. That doesn't mean FA is going
anywhere, as it works perfectly fine—it's just that you won't be getting the
latest features.
Resources
- Famo.us
Slackchat - BizSpark,
for free MSFT dev licenses and web hosting - E-mail me with questions
- Learn
how to turn this into a Cordova app for mobile platforms
More Hands-On With JavaScript
This article is
part of the web development series from Microsoft tech evangelists on practical
JavaScript learning, open-source projects, and interoperability best practices, including Microsoft
Edge browser and the new EdgeHTML rendering engine.
We encourage
you to test across browsers and devices including Microsoft Edge—the default
browser for Windows 10—with free tools on dev.modern.IE:
- Scan
your site for out-of-date libraries, layout issues, and accessibility - Use
virtual machines for Mac, Linux, and Windows - Remotely
test for Microsoft Edge on your own device - Coding
Lab on GitHub: Cross-browser testing and best practices
In-depth tech
learning on Microsoft Edge and the Web Platform from our engineers and
evangelists:
Microsoft
Edge Web Summit 2015 (what to expect with the new browser, new supported web platform standards,
and guest speakers from the JavaScript community)
Woah,
I Can Test Edge & IE on a Mac & Linux! (from Rey Bango)
Advancing
JavaScript Without Breaking the Web (from Christian Heilmann)
The
Edge Rendering Engine That Makes the Web Just Work (from Jacob Rossi)
Unleash
3D Rendering With WebGL (from David Catuhe including the Vorlon.js and Babylon.js projects)
Hosted
Web Apps and Web Platform Innovations (from Kevin Hill and Kiril Seksenov including the manifoldJS project)
More free
cross-platform tools and resources for the web platform:
Original Link:
TutsPlus - Code
Tuts+ is a site aimed at web developers and designers offering tutorials and articles on technologies, skills and techniques to improve how you design and build websites.More About this Source Visit TutsPlus - Code