Our Thoughts

Full-Stack JavaScript

Earlier this month, we received an interesting requirement from one of our existing customers. The requirement was to build a fairly simple web application, with one catch “The solution should not use IIS or Apache but use a custom web server”. After further discussions with the customer we understood that the customer had bad experiences in terms of performance and resource usage when deploying solutions hosted on IIS / Apache. The root cause was that the hardware being used to host these web servers were closer to the Minimum Hardware Requirements, resulting in High CPU & Memory usage and a perceived performance issue. These slow performing applications resulted in low adoption rates with the application users, which is why the explicitly stated “custom web server”.

Fair enough, the customer had a limitation where the hardware could not be scaled up and needed a solution which can be hosted on the existing hardware. In most cases, we would give up the case, inferring budget constraints for hardware would mean no budget for software. However, we took this as an opportunity to look beyond the .NET, Java & PHP world to meet the customer’s requirements. We needed a solution that would have a low memory footprint on the server and judiciously use the CPU. We had heard a lot about Node.JS and its performance capabilities and decided to explore the Full-Stack further. The most popular stack seemed to be MEAN (Mongo DB, Express, Angular & Node). Well the customer, wanted the database to be on MySQL, so we looked at creating a proof of concept on MySQL, Express, Angular & Node. The objective of the proof of concept was to see how the Full-Stack performs in terms of Page Load Times & Server Resource Usage (CPU & Memory). The results were very promising and more importantly did not take more than two days to setup & develop.

During the study phase, there were other supporting technologies that were used to speed up the development. The components and the system architecture are shown below.

 mean_full_stack

Angular JS – A JavaScript Client Side framework.

Node JS – Event Driven I/O Server Side JavaScript environment based on V8.

Express – A Node JS web application server framework to build web applications & API.

Sequelize – A Node JS ORM for MySQL

MySQL – A Relational Database Management System

The example chosen for the proof-of-concept was a basic application with Create & Read operations for a list of users. The steps followed to complete the example are detailed below:

Step 1: Install Node.js on your machine.
Step 2: Create table using following script on your MySQL database.

CREATE TABLE `users` (
  `Id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `UserName` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
  `password` varchar(20) COLLATE utf8_unicode_ci NOT NULL,
  `Address` varchar(150) COLLATE utf8_unicode_ci DEFAULT NULL,
  `PhoneNo` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
  `MobileNo` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
  `EmailID` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
  `Designation` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
  `Company` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`Id`)
) 

Step 3: Create a root folder for your project files and create the package.json file
This file allows Node.js to know the project dependencies. Once created, execute the Node Package Manager(npm) Install command to fetch and install the modules.


{	"name": "node-api",
	"main": "server.js",
	"dependencies": {
		"express": "~4.0.0",
		"body-parser": "~1.0.1",
		"mysql": "~2.5.0",
		"sequelize": "~1.7.0",
		 "cors":"~2.7.1"
	}
}

Step 4: Navigate to your root folder using Node.js command prompt and execute the command.


> npm install

step 5: Create database.json file for database configuration.


{
  "dev": {
    "driver": "mysql",
   "host":"localhost",
   "port":"3306",
    "user": "root",
    "database": "CRM",
    "password": "dbpassword"
  }
} 

Step 6 : Create a new file server.js in your root folder and initialize the modules ‘express’, ‘body-parser’ & ‘cors’. You also need to set your environment variables and port.


var express = require('express'),
bodyParser = require('body-parser');
var app = express();
app.use(bodyParser());
var cors = require('cors');
app.use(cors());
var env = app.get('env') == 'development' ? 'dev' : app.get('env');
var port = 8080;

Step 7: Sequelize is used as the ORM in this example. The below section reads configurations from the database.json file to establish a connection to the database.

var Sequelize = require('sequelize');
// db config
var env = "dev";
var config = require('./database.json')[env];
var password = config.password ? config.password : null;
// initialize database connection
var sequelize = new Sequelize(
	config.database,
	config.user,
	config.password,
	{
	host:config.host, 	
	port:config.port,
    dialect: config.driver,
    logging: console.log,
		define: {
			timestamps: false
		}
	}
);

Step 8: Define a model User and a few methods for CRUD operations.


var User = sequelize.define('users', {
    UserName: DataTypes.STRING,
    Password: DataTypes.STRING,
	Address: DataTypes.STRING,
	PhoneNo:DataTypes.STRING ,
	MobileNo:DataTypes.STRING,
	EmailID:DataTypes.STRING ,
	Designation:DataTypes.STRING,
	Company:DataTypes.STRING
  }, {
    instanceMethods: {
      retrieveAll: function(onSuccess, onError) {
			User.findAll({ }, {raw: true}).success(onSuccess).error(onError);
	  },
	    retrievePage: function(record_count,onSuccess, onError) {
			User.findAll({ limit: record_count }, {raw: true}).success(onSuccess).error(onError);
	  },
      retrieveById: function(user_id, onSuccess, onError) {
			User.find({where: {id: user_id}}, {raw: true}).success(onSuccess).error(onError);
	  },
      add: function(onSuccess, onError) {
			var username = this.username;
			var password = this.password;
			  this.save().success(onSuccess).error(onError);
	   },
	  updateById: function(user_id, onSuccess, onError) {
			var id = user_id;			
			User.update({ username: username,password: password},{where: {id: id} }).success(onSuccess).error(onError);
	   },
      removeById: function(user_id, onSuccess, onError) {
			User.destroy({where: {id: user_id}}).success(onSuccess).error(onError);
	  }
    }
  });

Step 9: Now define routes for Url Routing and register the routes.


var router = express.Router();
// on routes that end in /users
router.route('/users')
// create a user (accessed at POST http://localhost:8080/api/users)
.post(function(req, res) {
	var username = req.body.username; //bodyParser does the magic
	var password = req.body.password;
	var address = req.body.Address;
	var mobileno = req.body.MobileNo;
	var emailID = req.body.EmailID;
	var designation = req.body.Designation;
	var company = req.body.Company;
	var user = User.build({ UserName: username, Password: password, Address:address, MobileNo:mobileno, EmailID:emailID, Designation:designation, Company:company });
	user.add(function(success){
		res.json({ message: 'User created!' });
	},
	function(err) {
		res.send(err);
	});
})
// get all the users (accessed at GET http://localhost:8080/api/users)
.get(cors(),function(req, res) {
	var user = User.build();
	user.retrieveAll(function(users) {
		if (users) {
		  res.json(users);
		} else {
		  res.send(401, "User not found");
		}
	  }, function(error) {
		res.send("User not found");
	  });
});
//get all the users by rowcount
router.route('/users/:count')
.get(cors(),function(req, res) {
	var user = User.build();
	user.retrievePage(req.params.count,function(users) {
		
		if (users) {
		  res.json(users);
		} else {
		  res.send(401, "User not found");
		}
	  }, function(error) {
		res.send("User not found");
	  });
});
// on routes that end in /users/:user_id
// ----------------------------------------------------
router.route('/user/:user_id')
// update a user (accessed at PUT http://localhost:8080/api/users/:user_id)
.put(function(req, res) {
	//Code to update User
	  }, function(error) {
		res.send("User not found");
	  });
})

// get a user by id(accessed at GET http://localhost:8080/api/users/:user_id)
.get(function(req, res) {
	var user = User.build();

	user.retrieveById(req.params.user_id, function(users) {
		if (users) {
		  res.json(users);
		} else
 {		  res.send(401, "User not found");
		}
	  }, function(error) {
		res.send("User not found");
	  });
})
// delete a user by id (accessed at DELETE http://localhost:8080/api/users/:user_id)
.delete(function(req, res) {
	//Code to delete
		}
	  }, function(error) {
		res.send("User not found");
	  });
});
// Middleware to use for all requests
router.use(function(req, res, next) {
	console.log('Something is happening.');
	next();
});
app.use(function (req, res, next) { 
    next();
});
// REGISTER OUR ROUTES
app.use('/api', router);
app.listen(port);
console.log('server started on port ' + port);

Step 10: Our REST API with CRUD capabilities is ready and the following command will make it available over the defined port.

> node server.js

Step 11: In order to retrieve data and show it in a grid we will use HTML with AngularJS


<html lang="en-US">
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<body>
<Head> Create New User </Head>
<form ng-app="myApp" ng-controller="userCtrl" ng-submit="processForm()" >
<div > 
<style>
table, td, tr {
    border: 1px solid black;
}
tr {
    background-color: gray;
    color: white;
}
</style>
<table style="widtr:90%;">
<tr><td><Label>USER NAME</Label></td><td><input type="text" ng-model="formData.username" ></input><td></tr>
<tr><td><Label>Password</Label></td><td><input type="text" ng-model="formData.password" ></input><td></tr>
<tr><td><Label>Address</Label></td><td><input type="text" ng-model="formData.Address" ></input><td></tr>
<tr><td><Label>MobileNo</Label></td><td><input type="text" ng-model="formData.MobileNo" ></input><td></tr>
<tr><td><Label>Email ID</Label></td><td><input type="text" ng-model="formData.EmailID" ></input><td></tr>
<tr><td><Label>Designation</Label></td><td><input type="text" ng-model="formData.Designation" ></input><td></tr>
<tr><td><Label>Company</Label></td><td><input type="text" ng-model="formData.Company" ></input><td></tr>              
<tr><td></td><td><button type="submit" style="width:50%; align:right;"  >Save</button><td></tr>
<tr><td></td><td><label type="submit" style="width:50%; align:right;"  >{{message.message}}</label><td></tr>   
</table>
<label></label>
</div>
<script>
var app = angular.module('myApp', []);
app.config(['$httpProvider', function($httpProvider) {
        $httpProvider.defaults.useXDomain = true;
        delete $httpProvider.defaults.headers.common['X-Requested-With'];
    }
]);
app.controller('userCtrl', function($scope, $http) {
	   
	 $scope.formData = {};

    // process the form
    $scope.processForm = function() {
	$http.post("http://[server]:8080/api/users",$scope.formData)
    .success(function(response) {
	console.log(response);

	$scope.message = response;
});
}
});
</script>
</body>
</html>

You can host the HTML page by adding the following lines of code to server.js


var connect = require('connect');
var serveStatic = require('serve-static');
connect().use(serveStatic(__dirname)).listen(8081);
console.log('html started on port ' + 8081);

To get a limited no. of rows you can change the API request URL to include the count parameter
$http.get(“http://[server]:8080/api/users/[count]”)

This completes the Client Side code and you can now benchmark the performance. For a machine with 4 GB RAM, AMD Athlon 3.4 Ghz processor and Windows 8 it takes an average of 160 ms for 100 records. This timing includes data fetch and page rendering.


3D Graphics with HTML5 and Three.js

The 3D graphic capabilities introduced in HTML5 are being used to build creative User Experiences that are highly interactive in nature. Previous versions of HTML and JavaScript engines were not capable of rendering graphics fast enough to run 3D graphics, resulting in developers using Adobe Flash to render animations on the browser. With the introduction of enhanced features like WebGL, Canvas, SVG & 3D CSS Transforms in HTML5, building a web application with 3D graphic capabilities in the browser has become a reality. A User Interface with visual representations & interactivity could be an important differentiator in today’s competitive world.

However, it is a lot of hard work to build a 3D graphic in HTML5 and JavaScript. Fortunately, most of the native code to render 3D using WebGL has been abstracted into a simple library Three.js. Three.js is a library that makes WebGL – 3D in the browser – easy to use. While a simple cube in raw WebGL would turn out hundreds of lines of JavaScript, a Three.js equivalent is only a fraction of that.

Before we get into an example of how to build a rotating cube wireframe using Three.js, let us understand 3D. In a 3D world, you would need the following

  1. A Scene
  2. A Camera
  3. A Renderer

This allows us to render a scene with a camera. Once the scene is setup, you can add objects to the scene to build your 3D world. A step by step guide to build a rotating cube is shown below.

//initialize attributes
var WIDTH = 400, HEIGHT = 300;
var VIEW_ANGLE = 75, ASPECT = WIDTH / HEIGHT, NEAR = 1, FAR = 10000;
var $canvas = $('#canvas'); 

// create a WebGL renderer, camera and a scene 
var renderer = new THREE.WebGLRenderer({ alpha: true }); 
var camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR ); 
var scene = new THREE.Scene(); 

camera.position.z = 150; 

// start the renderer 
renderer.setSize(WIDTH, HEIGHT); 
$canvas.append(renderer.domElement);

In the above lines we initialize a few attributes, which are used to create the renderer, the camera and the scene. We then create a cube (object) to place in the scene and set its material to be a mesh grid.

// create the sphere's material
var material = new THREE.MeshBasicMaterial(
{
    color: 0x3498db,
    wireframe: true
});

var cube = new THREE.Mesh( new THREE.BoxGeometry( 100, 100, 100, 5, 5, 5 ), material );

We then add the camera and cube to the scene.

scene.add(cube);
scene.add(camera);

and finally render the scene.

function render() {
    requestAnimationFrame(render);

    //rotate the cube
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;

    renderer.render(scene, camera);
};

We have added a rotate animation to add some visual delight. That’s all! Your first 3D graphic animation in HTML5 is ready. View CODE and DEMO in JSFiddle.

Achieving 3D animations in browsers natively is a lot of fun and opens the doors for a lot of cool user interfaces, which were not possible earlier. Interactive maps, navigation apps, visual reporting are just some of the use cases where a delightful and meaningful User Experience can be given. Applications that differentiate themselves by providing non-traditional user interfaces are gaining traction much faster than competition.


Indoor Map using Magnetic Fields

Location Based Services are increasingly being used to present contextual information to the user. With Google Maps charting the entire globe, it is trivial to add geo capabilities to your application. In today’s world, many apps & services use maps as the primary interface to interact with users. Services like taxi booking or house rental have seen significant increase in application usage, when using maps as their primary interface.

The primary technology used in accurately locating a device is GPS (Global Positioning System). However this technology only works well when outdoors, limiting the usage to outdoor map based services. There is immense scope to build innovative apps & services, if a user location can be tracked to an accuracy of a couple of metres within a mall or a building. This has led to technology companies trying to find a feasible solution for Indoor Mapping.

Various technologies like Bluetooth, Wi-Fi, Inertial Measurements have been applied to find a solution. iBeacon from Apple, Cisco Wireless Location Appliance are products attempting to dominate this space. Another very interesting technology that is being applied to solve this last frontier of digital cartography is Geo-Magnetism.

Magnetic Field Models are used for navigation by various government agencies and can be measured by a sensor on or above the surface of Earth. Of the various sources that generate magnetic fields, it is the Earth’s main magnetic field that accounts for 95% of the field strength at the Earth’s surface. The World Magnetic Model maintains such a Magnetic Field Map and updates it every 5 years (last released in 2015). The magnetic field components X (northward), Y (eastward), Z (downward), F (field strength), D (declination), I (inclination), and H (horizontal strength) are measured in geodetic co-ordinates.

Magnetic positioning can offer pedestrians with smart phones an indoor accuracy of 1–2 meters with 90% confidence level, without using the additional wireless infrastructure for positioning. Magnetic positioning is based on the iron inside buildings that create local variations in the Earth’s magnetic field. Un-optimized compass chips inside smart phones can sense and record these magnetic variations to map indoor locations. This technology is independent from external infrastructures such as radio access points and can provide scalability without large infrastructure investments.

The Android OS through Geomagnetic Field provides support to retrieve the magnetic field co-ordinates from hardware components. Similar support is provided by the Magnetometer in iOS. App developers can leverage this technology to provide fairly accurate Indoor Mapping, opening up a world of new business opportunities. Indoor Mapping can be applied to various use cases like Location-Based Mobile Marketing & Indoor Navigation in Shopping Malls, Airport, Academic Buildings, Train Stations, Stadiums, Parking Spaces, Hospitals, Cruise Ships or Business Parks.


Categories