Category Archives: JavaScript

TensorFlow.js Image Classification with MobileNet Model

TensorFlow.js is a library for machine learning in JavaScript. Using TensorFlow.js one can,

  • Run existing model
  • Develop ML models in JavaScript
  • Use existing model and retrain it

Here in this blog post we will see first use case which is to run existing model. We will use MobileNet model to predict object through webcam.

TensorFlow.js Image Classification
tensorflow.js

TensorFlow.js Image Classification HTML

Let’s start it with basic HTML and add necessary scripts in it. First of all create one index.html file. Add following code in that file. Also create css folder and tfjs folder. Here we will out our style.css and our JS file to start image classification

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Image Classification</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <button id="webCam" class="btn webCam-button" onclick="openWebCam()">Start Web Cam</button>
    <div class="webcam-popup" id="webCamDisplay">
      <video autoplay playsinline muted id="webcam" width="224" height="224"></video>
      <button type="button" class="btn" id="predict" onclick="predictObject()">Predict</button>
      <button type="button" class="btn cancel" onclick="closeWebCamDisplay()">Close</button>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs/dist/tf.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet"></script>
    <script src="tfjs/imageClassification.js"></script>
  </body>
</html>

As you can see in above HTML, we have very simple HTML here. We have button to start web cam. There is video element to show the preview of web cam. Then we have couple of buttons to start prediction. Now let’s add CSS. Create style.css in css folder and add following styles to it.

CSS Part

html {
  font-size: 60%;
  overflow-x: hidden;
  scroll-padding-top: 5rem;
  scroll-behavior: smooth;
}

header {
  margin-bottom: 2rem;
  position: relative;
  margin-left: 70px;
  margin-top: 30px;
  font-weight: bold;
}
header h1 {
  font-size: 30px;
  margin-left: 20px;
  font-weight: bold;
}

.btn {
  margin-top: 1rem;
  display: inline-block;
  padding: 1rem 2rem !important;
  border-radius: 1rem;
  color: #fff;
  background: #189ab4;
  font-size: 1.5rem !important;
  cursor: pointer;
  font-weight: 600 !important;
  margin-right: 10px;
}

.webCam-button {
  color: white;
  padding: 16px 20px;
  border: none;
  cursor: pointer;
  position: fixed;
  bottom: 140px;
  right: 28px;
}

.webcam-popup {
  display: none;
  position: fixed;
  bottom: 0;
  right: 15px;
  border: 3px solid #f1f1f1;
  z-index: 9;
  background-color: black;
}

JavaScript Part

Now we have html and css ready. It’s time for some JavaScript logic. We will create file with name imageClassification,js in tfjs folder and add following code to it.

const webcamElement = document.getElementById('webcam');
let startPrediction =  false;

async function app() {
  console.log('Loading mobilenet..');

  net = await mobilenet.load();
  console.log('Successfully loaded model');
  
  const webcam = await tf.data.webcam(webcamElement);
  while (true) {
    const img = await webcam.capture();
    const result = await net.classify(img);

    for(var i = 0 ; i < result.length ; i++ ) {
      res = result[i];
      if(res.probability > 0.5) {
        alert(res.className);
        location.reload();
        break;
      }
    }
    img.dispose();
    await tf.nextFrame();
  }
}

function openWebCam() {
  document.getElementById("webCamDisplay").style.display = "block";
}

function closeWebCamDisplay() {
  document.getElementById("webCamDisplay").style.display = "none";
}

function predictObject() {
  app();
}

Here we have functions to open & close pop up. There is predict button. Where we will start web cam preview and load the MobileNet Model. We are using async await syntax to wait till MobileNet model is loaded and then start the prediction. Following line loads the model.

net = await mobilenet.load();

Then we set the data source which is our webcam preview with following line.

const webcam = await tf.data.webcam(webcamElement);

Then we have while loop added where we capture the image frame and try to classify it with MobileNet model.

const img = await webcam.capture();
const result = await net.classify(img);

We are checking the results with accuracy over 50% to check if the classification is correct or not. If probability is good we show the classname in alert. This class name contains the name of object. It’s coming from MobileNet trained data.

When you run the code it may take a while to predict the object. You can check it out by placing multiple objects in front of web cam and check. Following are few examples.

As you can see in few cases the prediction is correct for example, mobile phone and mouse. But in the first case it’s wrong. I am not wearing bullet proof vest.

You can read more about TenorFlow.js on Official Website

Here is the link to MobileNet Model GitHub

PDF.JS Not Working – Sencha Touch 2 PDF Panel Not Working After Build

Hello,

Recently in one of my project we were using following Sencha Touch 2 PDF panel to display PDF in native application build with Cordova.

I faced a strange issue here. App was working fine without any build but when I generate a production build and build the native android app PDF panel stopped working and throws following error.

Unhandled rejection: TypeError: undefined is not an object (evaluating ‘viewBox’)

I tried to find out a solution for sometime but could not get any. I was using following PDF panel.

https://github.com/SunboX/st2_pdf_panel

Suddenly I saw that there is no update since last three years and that could be probably be the reason. So what I did is downloaded latest PDF.js and built the minified files and used it and bingo it worked. So here I am going to explain the steps.

1) First of clone latest PDF.js source from it’s git.

$ git clone git://github.com/mozilla/pdf.js.git

2) Now go to the folder.

$ cd pdf.js

3) Install Node.js if its not installed.

$ npm install -g gulp-cli

4) After node.js is installed, install all the dependencies.

$ npm install

5) Build PDF.js files.

$ gulp generic

it will generate minified files in directory build/generic/build/

Copy pdf.js and pdf.worker.js files from this directory to your lib folder and that’s it now PDF will be displayed even in testing or production build.

JavaScript parseInt(’08’) Returns Zero

Recently in one of our product we faced strange issue related to date display.  We were passing date components to display like this.

1st August 2016

Everything was working fine, till we faced the issue since start of Month of August. Instead of displaying correct date it was displaying 1 year old date or any random date.

It took sometime for me to figure out issue. Issue was number system. When we parse as following

parseInt(“08”)

In some browser or some android phones, it is considered as octal number and octal number system is used to parse. So “08” is “0” in octal so it gives wrong number.

So to fix this issue you can either use radix parameter in parseInt

parseInt(“08”, 10);

Here radix 10 represent decimal number system so “08” is parsed as “8” Other solution is to use Number function to parse the string.

Number(“08”);

And it gives you correct result. Octal system is deprecated in most of the browser now but still some old browser and some android phones are still using it so we have to to use above methods to avoid any issue.

Hope this helps you.

Sencha Touch Data Store Tips and Tricks

Recently one my friend asked me for some help on Sencha Touch Data store and form our conversation I got an idea for this blog.

Tip 1

If you want to pass extra params to store there are two ways to do that.

1) Pass it in load method.

store.load({
            params: {
                param1 : value1
            }
        });

2) Set it as extra param.

store.getProxy().setExtraParams({
            ‘param1’ : value1,
            ‘param2’: value2
        });

So what’s the difference between this two and when to use which.

When you have requirement to add and use params only once. Also every time store load, you want to pass different params you have to use below method.

store.load({
            params: {
                param1 : value1
            }
        });

Params added here are only added once. Next time when you call load method of store, these params are not passed. You can use it for dynamic parameters.

When you have fixed params that you have to pass every time,  a store is loaded. You have to use following method.

store.getProxy().setExtraParams({
            ‘param1’ : value1,
            ‘param2’: value2
        });

This will permanently add those params to the store and it will be passed every time store.load() method is called.

Tip 2

How can you add callback function for store load dynamically. Again there are two ways to do that. If you want to add and use it only once, use following method. 
store.load({
       callback: function(){
              console.log(‘store is loaded’); 
       }
});
But if you want to wait for store load every time you should use following logic.
store.on({
       load: function(){
              console.log(‘store is loaded’); 
       },
       scope: this
});

Tricks

1) To reset all the extra params in store use do the following.
store.getProxy().setExtraParams({
});
Just pass the empty object in function and it will clear all previous params.
2) Reset page param in store when using list paging.
You can use currentPage config. store.currentPage = 1
3) Get raw response from of store load.
store.getProxy().getReader().rawData
This will return you all the raw data your API has returned.

JavaScript Create Date With TimeZone

Hello,

Recently in one of my project we faced lots of issues regarding in correct dates displayed to users. The problem was TimeZone. A user is in India but he don’t know that he has set timezone to USA timezone and hence we get user’s device date it was showing wrong date and time.

We asked our users to fix it but as we know end users are always unpredictable they still set the timzone to USA or others and keep complaining us about dates and times.

So here is what we did to fix this issue.

Step 1 : Get User’s Current Location

You can use HTML 5 GeoLocation.

if (navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(gotUserPosition);
}

Step 2 : From the Latitude and Longitude, get user’s current timezone using Google API.

function gotUserPosition(position){

     Ext.Ajax.request({
            url: ‘https://maps.googleapis.com/maps/api/timezone/json?       location=’+ position.coords.latitude +’,’+position.coords.longitude+’&timestamp=’+parseInt(Date.now()/10)+’&key=YOUR_KEY’,
            method: ‘GET’,
            disableCaching: false,
            success: function(response) {
                var result = Ext.decode(response.responseText);
                if(result.status == ‘OK’){
                    localStorage.setItem(‘time_offset’,result.rawOffset);
                    localStorage.setItem(‘timeZoneId’,result.timeZoneId);
                }
            },
            failure: function(response) {
             
            },
            scope: this
     });

}

For this you have to create a Google API project and enable timezone API and add your key in stead of YOUR_KEY

As you can see above we are sending user’s latitude and longitude to google maps api and getting the result. If result is OK. then we are saving time offset to local storage.

Now this time offset is the offset in number of seconds from UTC time. For example Indian Standard Time is ahead of UTC for 5 hours and 30 minutes. So here my offset will be 19800 seconds which is 5 hours and 30 minutes.

Now use the following logic to create date object.

var utcDate = (new Date()).toISOString();
var offsetHours = parseInt(Number(localStorage.getItem(‘time_offset’))/60/60);
var offsetMinutes = parseInt(Number(localStorage.getItem(‘time_offset’))/60%60);

var currentDate = new Date(Date.UTC(Number(utcDate.split(‘T’)[0].split(‘-‘)[0]), Number(utcDate.split(‘T’)[0].split(‘-‘)[1]) – 1, Number(utcDate.split(‘T’)[0].split(‘-‘)[2]), (Number(utcDate.split(‘T’)[1].split(‘:’)[0]) + Number(offsetHours)), (Number(utcDate.split(‘T’)[1].split(‘:’)[1]) + Number(offsetMinutes)),0));

function z(n){return (n < 10? ‘0’ : ”) + n;};

var currentDateString = currentDate.getUTCFullYear() + ‘-‘ + z(currentDate.getUTCMonth() + 1) + ‘-‘ + z(currentDate.getUTCDate());

So above logic about creating UTC date and then adding number of hours and minutes to it to get desired date and time in UTC timezone. So virtually it’s UTC date and time but since we added offset it will show you local date and time.

Hope this helps you.

CSS Border Radius Not Working in Android WebView or Chrome

Recently while working on mobile app project which was cross platform application we were creating pie shaped menu where we faced a very strange issue.

Actually I was trying to create following menu and I created that successfully while I was working in Xcode and iPhone simulator.

And it worked fine but as soon as I checked it in Android phone it came up like following.

Now that was so embarrassing. Off course, after spending couple of days to make such menu and it came up like this, that is so disappointing. How ever after spending some time over it I found out a solution, in this blog I am going to explain this. There more than one solutions so I posting each one. 
1) Some older version does not support percentage value. 
Some older version of chrome does not support percentage values for border radius. So instead of percentage give pixel values.

Use border-radius : 50px in stead of border-radius : 10%

2) Specify top, left right and bottom property separately. 
some Chrome does understand single value like border-radius : 50px. So here you have to specify each border radius saperately.


Use 
border-top-left-radius: 50px;border-top-right-radius: 50px;border-bottom-right-radius: 50px;border-bottom-left-radius: 50px;


In stead of 

border-radius : 50px

3) Now here comes the issue which I have faced,  background-color “leaking” outside of a border when border-radius is present. In my case there were few div tags which was having background color and was going out side of main container because of transformation.  So here are the two solutions you can do.

Apply overflow: hidden property to main container

If that does not work apply following CSS property to main container.

-webkit-background-clip: padding-box; -moz-background-clip: padding; background-clip: padding-box;

This should solve your all border radius related problem in all the versions of Chrome. Hope this helps you.

Sencha Touch 2.2 Scrolling Issue in Android 5.1

Hello,

If your application is created with Sencha Touch 2.2 it must be having scroll issue for forms, list and carousels in android 5.1 on words.

The reason is some chrome updates have broken Sencha Touch scrolling logic and that’s why it’s not working so what is the solution, well the simple solution is to update your sencha touch version in the app. But what if the app is not created with Sencha CMD. Yes in my case previous developer have created app with loading sencha-touch-all,js and css. So I can not simply modify it with new version y sencha cmd and there were lots of CSS overrides. So what to do. In this blog I am going to explain.

First of all create folder with name util in your app folder. Now create new JS file in util folder and name it “PaintMonitor.js” and add following code to it.

/**
 * Created by hirendave on 3/7/16.
 */
Ext.define(‘SEOshop.util.PaintMonitor’, {
    override: ‘Ext.util.PaintMonitor’,

    uses: [
        ‘Ext.env.Browser’,
        ‘Ext.env.OS’,
        ‘Ext.util.paintmonitor.CssAnimation’,
        ‘Ext.util.paintmonitor.OverflowChange’
    ],

    constructor: function(config) {
        return new Ext.util.paintmonitor.CssAnimation(config);
    }

}, function () {
    //
    console.info(“Ext.util.PaintMonitor temp. fix is active”);
    //

});

Crete one more file with name “SizeMonitor.js” and add following code to it.

/**
 * Created by hirendave on 3/7/16.
 */
Ext.define(‘SEOshop.util.SizeMonitor’, {
    override: ‘Ext.util.SizeMonitor’,

    uses: [
        ‘Ext.env.Browser’,
        ‘Ext.util.sizemonitor.Default’,
        ‘Ext.util.sizemonitor.Scroll’,
        ‘Ext.util.sizemonitor.OverflowChange’
    ],
    constructor: function (config) {
        var namespace = Ext.util.sizemonitor;

        if (Ext.browser.is.Firefox) {
            return new namespace.OverflowChange(config);
        } else if (Ext.browser.is.WebKit) {
            if (!Ext.browser.is.Silk && Ext.browser.engineVersion.gtEq(‘535’) && !Ext.browser.engineVersion.ltEq(‘537.36’)) {
                return new namespace.OverflowChange(config);
            } else {
                return new namespace.Scroll(config);
            }
        } else if (Ext.browser.is.IE11) {
            return new namespace.Scroll(config);
        } else {
            return new namespace.Scroll(config);
        }
    }
}, function () {
    //
    console.info(“Ext.util.SizeMonitor temp. fix is active”);
    //
});

Now go to your app.js file and add following code to your application object.

requires: [
        ‘YOUR_APP.util.SizeMonitor’,
        ‘YOUR_APP.util.PaintMonitor’
    ]

That’s it and it should solve all the scrolling and rendering issue in Android 5.1 and above version.

Hope this helps you.

jQuery JSTree Tips and Tricks Like Expand All Nodes, Get Selected Node, Get Extra Information

Hello,

Recently in one my project I used jQuery JSTree for display data in tree format and while working with I faced certain issues so here I am sharing some tips and tricks you can use with JSTree.

1) Expand All Nodes on Page Load

If you have dynamic dataset in JSTree and you want to expand it when tree is created here is what you can do. First call AJAX service to get data.

$.ajax({
            url: “cat-tree”,
            cache: false
        }).done(function( json ) {
            //init js tree here
         
        });

For example in above service I am calling url cat-tree and get my JSON data. Now add following code to initialize JSTree.

$(‘#categoryTree’).jstree({
                ‘plugins’: [“wholerow”, “types”],
                ‘core’: {
                    “themes” : {
                        “responsive”: false
                    },
                    ‘data’: json
                },
                “types” : {
                    “default” : {
                        “icon” : “fa fa-folder icon-state-warning icon-lg”
                    },
                    “file” : {
                        “icon” : “fa fa-file icon-state-warning icon-lg”
                    }
                }
            });

That’s it now wait for sometime to get it rendered in DOM and then expand it.

setTimeout(function(){
                $(‘#categoryTree’).jstree(“open_all”);
            },500);

2) Add select event and get Selected Node in JSTree

Add following code to add select event.
$(‘#categoryTree’).on(‘select_node.jstree’, function(e,data) {
                    //Your code here
                });

Use following code to get single selected node of JSTree.

var selectedNode = $(‘#categoryTree’).jstree().get_selected(true)[0];

Use following code to get single multiple selected nodes of JSTree.

var selectedNode = $(‘#categoryTree’).jstree().get_selected(true);

3) Deselect all the Nodes in JSTree

Use following code to deselect all the nodes in JSTree.
$(‘#categoryTree’).jstree(“deselect_all”);

4) Access Additional Data of Selected Node

We know that there is a standard format of data used with JSTree. For example.
[
       ‘Simple root node’,
       {
         ‘text’ : ‘Root node 2’,
         ‘state’ : {
           ‘opened’ : true,
           ‘selected’ : true
         },
         ‘children’ : [
           { ‘text’ : ‘Child 1’ },
           ‘Child 2’
         ]
      }
    ]
What if you want to have extra data like this.
[
       ‘Simple root node’,
       {
         ‘text’ : ‘Root node 2’,
         ‘key1’: ‘value1’,
         ‘key2’: ‘value2’
         ‘state’ : {
           ‘opened’ : true,
           ‘selected’ : true
         },
         ‘children’ : [
           { ‘text’ : ‘Child 1’ , ‘key1’: ‘value1’, ‘key2’: ‘value2’},
           ‘Child 2’
         ]
      }
    ]
You can pass any number of extra data buy how will you access it. Check the following code.
First get selected node.
var selectedNode = $(‘#categoryTree’).jstree().get_selected(true)[0];
Extra data is available in key  called original.
var value1 = selectedNode.original.key1;
var value2 = selectedNode.original.key2;
Hope this helps you.

Passing and Retrieving Data from Booststrap Modal

Recently in one my project I was using a theme which is using boostrap modal. Basically I was using modal for confirmation of delete and once user click on confirm process the delete action. I was using laravel REST API so we have to pass the id of object to be destroyed. So I have to pass id of object to modal and confirmation call API to delete. In this blog I will explain how to do this.

First of all add following modal code to your HTML.

<div class=”modal-dialog”>
        <div class=”modal-content”>
            <div class=”modal-header”>
                <button type=”button” class=”close” data-dismiss=”modal” aria-hidden=”true”></button>
                <h4 class=”modal-title”>Confirmation</h4>
            </div>
            <div class=”modal-body”>
                <p> Are you sure you want to delete? </p>
                <input type=”hidden” id=”objectId”/>
            </div>
            <div class=”modal-footer”>
                <button type=”button” data-dismiss=”modal” class=”btn dark btn-outline”>Cancel</button>
                <button id=”confirmDelete” type=”button” data-dismiss=”modal” class=”btn green”>Continue</button>
            </div>
        </div>
    </div>

As you can in above code I have added one hidden field in modal where we will store object id.

Now following will your code of delete button.

<a id=”deleteButton” data-id=”{{$object->id}}” data-toggle=”modal” href=”#deleteConfirmation” class=”btn btn-danger btn-sm”>

As soon as you click on delete button modal will be displayed.

Now add following code to your JavaScript.

    $(document).on(“click”, “#deleteButton”, function () {
        var id = $(this).data(‘id’);
        jQuery(‘#deleteConfirmation .modal-body #objectId’).val( id );
    });

    $(‘#deleteConfirmation .modal-footer button’).on(‘click’, function (e) {
        var $target = $(e.target); // Clicked button element
        $(this).closest(‘.modal’).on(‘hidden.bs.modal’, function () {
            if($target[0].id == ‘confirmDelete’){
                $id = $(‘#deleteConfirmation .modal-body #objectId’).val();
            }
        });
    });

As you can in above code we have added click event on delete button and setting id in modal hidden field.

Then we are adding event for confirm button in modal window and getting value stored in hidden field and then you can call the APIs or submit form whatever you want.

Hope this helps you.

HTML Fit Content to Available Space – Dynamic Font Size

Hello,

Recently in one of my project we have to fit content to available screen height. Basically it was cross platform mobile application built in HTML 5 and JavaScript. On screen there was a card with content. Card height and width as set to screen height and width. Now the problem was content can big or small and there should not be scrollbar. So what I did is I reduced the size of font till the content fits available width and height. This I did in JavaScript. So here in blog I am going to explain how to do this.

First of all add onload method to your body tag.

<body onload=”resizeFontSizeInit()”>

   <div id=”contentContainer” style=”width:100%;height:100%;overflow:hidden;”>
       <div id=”content”>
        Dynamic Content Here
       </div>
   </div>

</body>

Now add following function to JavaScript

function resizeFontSizeInit(){
   resizeFont(0.1);
}

function resizeFont(emSize){
      //first get the screen height
      var screenHeight = document.documentElement.clientHeight;
   
      //Now set the font size to content div
      var contentDiv = document.getElementById(‘content’);
      contentDiv.style.fontSize = String(emSize)+”em”;

      //Now check the height of screen to height of content div
      var contentHeight = contentDiv.clientHeight;

      //Check if content height is less than screen height.
      if(contentHeight < screenHeight){
           //Increase font size and call the same function recursively.
           emSize = emSize + 0.1;
           resizeFont(emSize);
      }else{
           //content height is greater than screen size so time to stop recursion.
          //set fontsize to previous size.
          revertFontSizeToPreviousSize(emSize);
      }
}

function revertFontSizeToPreviousSize(emSize){
      emSize = emSize – 0.1;
      var contentDiv = document.getElementById(‘content’);
      contentDiv.style.fontSize = String(emSize)+”em”;
}

So basically we start with 0.1 em font size and keep increasing it till the content height is greater than screen height. As soon as it’s bigger we have to stop and reset it to previous size. This way no matter what your content is, it will fit to screen without scroll bar.