Let is snow! – Create some winter experience for your Launchpad users

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

Winter experience in SAP Fiori

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.

 

 

Original post: https://blogs.sap.com/2019/11/26/surprise-your-users-with-a-true-x-mas-user-experience-let-it-snow/?source=social-global-sap-developers-linkedin_company-audienceengagement-developers-fiori-spr-2870577941&campaigncode=CRM-XB19-MKT-DGEALL