It's getting colder and colder and Christmas is nearing. While we keep our bodies warm with winter jackets, hats and scarves, we warm our hearts with that special, warm Christmas feeling. That feeling however, is rarely related to anything IT.
But what if I tell you, you may surprise
your Fiori users with just that; they login, and the Fiori Launchpad is snowing...
Snowing Effect Credit
First of I'd like to point out that the snowing effect itself has not been created by me and was just found by me via
codepen.io. Please see the original snow effect javascript and author here:
snowing effect @ codepen.
Developing a "special" Fiori Launchpad Plugin
You may guessed it; I'm talking about a plugin for the Fiori Launchpad. To develop a plugin in Fiori is very similar to developing an app, with a few differences. Let's go through all the steps.
Prerequisite
First of, as a prerequisite, in your SAP Web IDE you must enable following extension:
SAP Fiori Launchpad Extensibility
Step 1: Create a project for the plugin
Create a new project from template and choose the now available "
SAP Fiori Launchpad Plugin" template. More details can be found at
SAP Help. This will generate all necessary files for the plugin, the most important one being
Component.js, similar to an app.
I called my project
Snow with namespace
snow.
Step 2: "Convert" codepen original to Fiori
Now we don't just have access to direct HTML files and especially the plugin, is something that is loaded into the Fiori Launchpad shell - so we can't just copy-n-paste what we have in codepen. Instead we need to turn the snowing effect (or rather all the snowflakes) into an object we can call. I solved it the following way:
I created a new folder in the project called
controller and a file
Flake.js - my snowflake controller. Flake.js gets most of the javascript code from codepen, but "fiorified", like below:
sap.ui.define([
"sap/ui/base/Object"
], function(Object) {
"use strict";
return Object.extend("snow.controller.Flake", {
init: function(x,y) {
var maxWeight = 5,
maxSpeed = 3;
this.x = x;
this.y = y;
this.r = this.randomBetween(0, 1);
this.a = this.randomBetween(0, Math.PI);
this.aStep = 0.01;
this.weight = this.randomBetween(2, maxWeight);
this.alpha = (this.weight / maxWeight);
this.speed = (this.weight / maxWeight) * maxSpeed;
},
randomBetween: function(min, max, round) {
var num = Math.random() * (max - min + 1) + min;
if (round) {
return Math.floor(num);
} else {
return num;
}
},
distanceBetween: function(vector1, vector2) {
var dx = vector2.x - vector1.x,
dy = vector2.y - vector1.y;
return Math.sqrt(dx * dx + dy * dy);
},
update: function() {
this.x += Math.cos(this.a) * this.r;
this.a += this.aStep;
this.y += this.speed;
}
});
});
Simply put: what we had in codepen as
functions are now instead
methods of our Flake object and
global variables are instead
object properties.
Please note: you won't find the
init or the
loop function from the original in above code: init creates all the snowflakes and loop displays and animates them: both we cannot do from the controller directly.
Step 3: Create Flake objects to create snowing effect
So far we just have a controller that can simulate snowflakes. Now we need to use this object and display the snowflakes in our Fiori Launchpad. For this we have to modify the existing
Component.js file.
3.1 Import Flake controller
sap.ui.define([
"sap/ui/core/Component",
"sap/ui/Device",
"snow/controller/Flake"
], function (Component, Device, Flake) {
return Component.extend("snow.Component", {
First step: we need access to our Flake controller (line 4 and 5 above) as well as the Device object.
3.2 Create all snowflakes for the snowing effect:
Inside the init() lifecycle method of our Component, we can now do what the original did in its init function (more or less):
init: function () {
//var rendererPromise = this._getRenderer();
// define snow variables
this._numFlakes = 200;
this._windowW = Device.resize.width; //window.innerWidth;
this._windowH = Device.resize.height; //window.innerHeight;
this._flakes = [];
// get canvas to paint in: there seems to be only one in
// in the Fiori Launchpad so this should always work
var canvas = $("canvas").get(0);
if(!canvas) {
// stop processing in case we don't have a canvas!
return;
}
this._ctx = canvas.getContext("2d");
// first loop to create all Flake objects
var i = this._numFlakes, flake, x, y;
while (i--) {
// create new flake
flake = new Flake();
// get random location
x = flake.randomBetween(0, this._windowW, true);
y = flake.randomBetween(0, this._windowH, true);
flake.init(x, y);
// add flake
this._flakes.push(flake);
}
// start looping all flakes to move them
this.loop();
},
You may noticed that the code now deviates quite a bit from the original. The main reason -as said- is that we don't just have an HTML file to enhance but instead we work with our plugin's lifecycle methods. Reading the comments provided in the code above should explain how the code changed and why it needs to be in this order.
One important thing to understand is the jQuery code to get the canvas:
var canvas = $("canvas").get(0);
What the above simply does, is searching the rendered HTML for any canvas tags:
<canvas>. Luckily for us, the Fiori Launchpad indeed uses a canvas and that
is in fact the only reason, why we can convert this codepen example into a Fiori plugin. The Flake controller we created gives the snowflakes a position and can change it and the loop function (next step) draws them into the canvas. Without the canvas we cannot draw nor animate the snowflakes, to create the snowing effect. That's why the plugin will not do anything, if no canvas object in the rendered HTML code was found!
3.3 Let it snow: display and move the snowflakes
The very last code bit above calls
this.loop() which is an equivalent to the loop function in the original, for us, added as a method to the Component.js:
loop: function() {
var i = this._flakes.length,
flakeA;
// clear canvas
this._ctx.save();
this._ctx.setTransform(1, 0, 0, 1, 0, 0);
this._ctx.clearRect(0, 0, this._windowW, this._windowH);
this._ctx.restore();
// loop through the flakes and "animate" them
while (i--) {
flakeA = this._flakes[i];
flakeA.update();
this._ctx.beginPath();
this._ctx.arc(flakeA.x, flakeA.y, flakeA.weight, 0, 2 * Math.PI, false);
this._ctx.fillStyle = "rgba(255, 255, 255, " + flakeA.alpha + ")";
this._ctx.fill();
if (flakeA.y >= this._windowH) {
flakeA.y = -flakeA.weight;
}
}
// continue animation...
requestAnimationFrame( this.loop.bind(this) );
},
And here we are: a snowing effect drawn onto the Fiori Launchpad canvas.
Step 4: Test the plugin!
Before we fully leave development, we of course should test the plugin and make sure it's running and -most importantly- doesn't cause any errors. Testing a plugin is a bit different from an app: we have to run a sandbox launchpad (which the template wizard already took care of), which will load our plugin: please find a detailed guide here at
SAP Help.
Use your Plugin
Once you tested the plugin and everything works fine, you can deploy your plugin and add it to your Fiori Lauchpad. Depending on your system landscape you may need to do different steps, but find below an example for using SAP Cloud Platform.
Deploy the Plugin to SAP Cloud Platform
This
blog post also has a guide (at the very end) on how to add a plugin to a SAP Cloud Platform Fiori Launchpad Portal site.