Insightful stories that revolve around technology, culture, and design

All blogs

Topics
Thank you! Your submission has been received!
Oops! Something went wrong while submitting the form.
Google Places Api integration with IONIC and the Long Press Issue
Category Items

Google Places Api integration with IONIC and the Long Press Issue

Fixing long-press issues in Google Places API integration with Ionic.
5 min read

Google Maps are changing the way we see the world. Lets change the way we look at Google Maps

Google Maps are a perfect match when you are dealing with location based apps. In this article we will learn to integrate the Google Maps api and Google Places api in our Ionic App and look at the solution to long press issue that Ionic suffers from and how to resolve that.

Get Ionic running:

  • Make sure you have node.js installed on your system
  • $ sudo npm install -g cordova
  • $ sudo npm install -g ionic

Create a new Ionic Application:

  
  ionic start googlePlacesDemo blank
  
  
  cd googlePlacesDemo/
  

Get list of all the platforms added in your application:


ionic platform

you will see the list of all the installed platforms


Example :
Installed platforms: ios 3.8.0
Available platforms: amazon-fireos, android, blackberry10, browser, firefoxos, osx, webos

Add Android and iOS platforms to you app:


ionic platform add android
ionic platform add ios

Following plugins will be installed once any platform is added:

  • cordova-plugin-console
  • cordova-plugin-device
  • cordova-plugin-splashscreen
  • cordova-plugin-statusbar
  • cordova-plugin-whitelist
  • ionic-plugin-keyboard

ng-cordova is an AngularJs Service which integrates cordova plugins into IONIC Applications. Download ng-cordova.master.zip from here and place the ng-cordova.min.js in the www/js. ngCordova depends on AngularJS  . In your index.html , place ng-cordova.min.js before cordova.js and after AngularJs/ Ionic files.


<script src="lib/ngCordova/dist/ng-cordova.js"></script><
script src="cordova.js"></script>

Inject ngCordova as an angular dependency in your angular module


angular.module('myApp', ['ngCordova'])

Test the app on the browser


ionic serve --lab

Lets add google places api in your index.html


<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?libraries=places,geometry&sensor=false"></script>

index.html


<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width" />
        <title></title>
        <link href="lib/ionic/css/ionic.css" rel="stylesheet" />
        <link href="css/style.css" rel="stylesheet" />
        <!-- google places api -->
        <script src="http://maps.googleapis.com/maps/api/js?sensor=false&libraries=places"></script>
        <!-- google places api ends -->

        <!-- ionic/angularjs js -->
        <script src="lib/ionic/js/ionic.bundle.js"></script>
        <!-- cordova script (this will be a 404 during development) -->
        <script src="js/ng-cordova.min.js"></script>
        <script src="cordova.js"></script>
        <!-- your app's js -->
        <script src="js/app.js"></script>
    </head>
    <body ng-app="starter">
        <ion-pane>
            <ion-header-bar class="bar-stable"><h1 class="title">Google Places Demo</h1></ion-header-bar>
            <ion-content ng-controller="MapCtrl">
                <div class="item item-input controls">
                    <i class="icon ion-search placeholder-icon"></i><input id="pac-input" type="text" placeholder="Search Location" data-tap-disabled="true" ng-model="search" />
                </div>
                <div id="map" data-tap-disabled="true"></div>
            </ion-content>
        </ion-pane>
    </body>
</html>


app.js



angular
    .module('starter', ['ionic'])
    .run(function ($ionicPlatform) {
        $ionicPlatform.ready(function () {
            if (window.cordova && window.cordova.plugins.Keyboard) {
                cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
                cordova.plugins.Keyboard.disableScroll(true);
            }
            if (window.StatusBar) {
                StatusBar.styleDefault();
            }
        });
    })
    .controller('MapCtrl', [
        '$scope',
        function ($scope) {
            function initialize() {
                var mapOptions = {
                    center: { lat: 28.613939, lng: 77.209021 },
                    zoom: 13,
                    disableDefaultUI: true, // DISABLE MAP TYPE
                    scrollwheel: false,
                };
                var map = new google.maps.Map(document.getElementById('map'), mapOptions);
                var input = /** @type {HTMLInputElement} */ (document.getElementById('pac-input'));
                // Create the autocomplete helper, and associate it with
                // an HTML text input box.
                var autocomplete = new google.maps.places.Autocomplete(input);
                autocomplete.bindTo('bounds', map);
                map.controls[google.maps.ControlPosition.TOP_LEFT].push(input);
                var infowindow = new google.maps.InfoWindow();
                var marker = new google.maps.Marker({
                    map: map,
                });
                google.maps.event.addListener(marker, 'click', function () {
                    infowindow.open(map, marker);
                });
                // Get the full place details when the user selects a place from the
                // list of suggestions.
                google.maps.event.addListener(autocomplete, 'place_changed', function () {
                    infowindow.close();
                    var place = autocomplete.getPlace();
                    if (!place.geometry) {
                        return;
                    }
                    if (place.geometry.viewport) {
                        map.fitBounds(place.geometry.viewport);
                    } else {
                        map.setCenter(place.geometry.location);
                        map.setZoom(17);
                    }
                    // Set the position of the marker using the place ID and location.
                    marker.setPlace(
                        /** @type {!google.maps.Place} */ ({
                            placeId: place.place_id,
                            location: place.geometry.location,
                        })
                    );
                    marker.setVisible(true);
                    infowindow.setContent('<div><strong>' + place.name + '</strong><br>' + 'Place ID: ' + place.place_id + '<br>' + place.formatted_address + '</div>');
                    infowindow.open(map, marker);
                });
            }
            // Run the initialize function when the window has finished loading.
            google.maps.event.addDomListener(window, 'load', initialize);
        },
    ]);



style.css



#map {
    width: 100%;
    height: 100%;
}
.controls {
    border: 1px solid transparent;
    border-radius: 2px 0 0 2px;
    box-sizing: border-box;
    position: absolute;
    line-height: 22px;
}
#pac-input {
    background-color: #fff;
    font-family: Roboto;
    font-size: 15px;
    font-weight: 300;
    padding: 0 11px 0 13px;
    text-overflow: ellipsis;
    width: 90%;
    margin-bottom: 0;
    line-height: 15px;
    font-weight: bold;
    margin-left: 10%;
}
#pac-input:focus {
    border-color: #4d90fe;
}
.pac-container {
    font-family: Roboto;
}
#type-selector {
    color: #fff;
    background-color: #4d90fe;
    padding: 5px 11px 0px 11px;
}
#type-selector label {
    font-family: Roboto;
    font-size: 13px;
    font-weight: 300;
}



Now run the app on the browser:


ionic serve --lab

You will see it work as expected in the browser.

Now run the app on Android Device:


ionic run android

Issue with Selecting Auto Complete suggestions

All Set, you might assume. There is a problem though, you will have to long press the autocomplete option to actually get it selected. The issue is that Gmap dynamically adds elements that need the data-tap-disabled property, so you'll have to manually add the property after google has added these elements to the dom.

To get it working on the Android device you need to add the following function in your controller:


$scope.disableTap = function () {
    var container = document.getElementsByClassName('pac-container');
    angular.element(container).attr('data-tap-disabled', 'true');
    var backdrop = document.getElementsByClassName('backdrop');
    angular.element(backdrop).attr('data-tap-disabled', 'true');
    angular.element(container).on('click', function () {
        document.getElementById('pac-input').blur();
    });
};


add disableTap() function in the input type


<input id="pac-input" type="text" placeholder="Search Location" data-tap-disabled="true" ng-change='disableTap()' ng-model="search">


Now run the App on the Android Phone. Voila!

For live demo please visit this github link.

Initialise Google Map

Google Places Api
Place marker on Map

Weekend Hack - 'Balloon Burst Game' using jQuery
Category Items

Weekend Hack - 'Balloon Burst Game' using jQuery

jQuery is often used on websites to enhance the user experience and to make the page interactive. Recently, I was trying to integrate gravitational equations to the DIV elements of the DOM and ended up the rabbit hole which resulted in this simple game Balloon Burst game. The game is simple! you click on balloons to increase your score from a heap of randomly moving balloons and bombs. High speed balloons gives more points and clicking a bomb will result in GAME OVER! Number of balloons increase with time and you can also configure things like speed etc before staring the game. I thought, why not write about my experience -- below is a rundown of creating the game.
5 min read

jQuery is often used on websites to enhance the user experience and to make the page interactive. Recently, I was trying to integrate gravitational equations to the DIV elements of the DOM and ended up the rabbit hole which resulted in this simple game Balloon Burst game. The game is simple! you click on balloons to increase your score from a heap of randomly moving balloons and bombs. High speed balloons gives more points and clicking a bomb will result in GAME OVER! Number of balloons increase with time and you can also configure things like speed etc before staring the game. I thought, why not write about my experience -- below is a rundown of creating the game.

I started with setting up the initial DOM structure and give some styling to it. In the document.ready() function initialize the global variables for configuring the movement.

    
      var marks_factor = 5; // Marks multiplying factor 
var max_limit_items = 40; // Max limit for items to render on page
var max_diameter = 90; // Max limit for balloon diameter
var diameter = 50, // Setting up default value
  max_items = 10,
  probability = 80,
  max_speed_limit = 10,
  min_speed_limit = 3;
    

To get a random number we will simply use Math.random() function which is predefined in jQuery and to have a random number between a range of values, we will play with this function a little bit 

    
function getRandomNumber(min, max) { // To generate random speed between between max and min rage of speed for the created balloons

      return Math.floor(Math.random() * (max - min) + min); // Get difference of max and min and select a random number and add the lower bound to get the result

    }
    

This function will return a random integer between min and max values. Another simple function using Math.random() which will return a random direction string

    
  function getRandomDirection() { // To generate random direction for the created balloons
  var decidingUnit = Math.floor(Math.random() * 100) % 4;
  if (decidingUnit === 0) {
    return 'top-left'; // 45 deg
  } else if (decidingUnit === 1) { 
    return 'top-right';
  } else if (decidingUnit === 2) {
    return 'bottom-left';
  } else if (decidingUnit === 3) {
    return 'bottom-right';
  }
}
    

createItem() function to create a random number based on the probability variable

    
        var createItems = function () {
    //Creating a balloon at random positions
    var left = getRandomNumber(0, $(window).width() - diameter); // Random left position
    var top = getRandomNumber(0, $(window).height() - diameter); // Random top position
    var $newObj;
    var speed = getRandomNumber(min_speed_limit, max_speed_limit);
    if (getRandomNumber(0, 100) < probability) {
        $newObj = $('<div>', {
            class: 'ball gravity-enabled',
            style:
                'width : ' +
                diameter +
                'px; height: ' +
                diameter +
                'px; top : ' +
                top +
                'px ; left : ' +
                left +
                'px; background-color : rgb(' +
                getRandomNumber(0, 255) +
                ', ' +
                getRandomNumber(0, 255) +
                ' ,' +
                getRandomNumber(0, 255) +
                ');',
            'data-speed': speed,
        }); // Creating a DOM object and assigning random css values to it
    } else {
        if ($('.bomb').length < Math.floor(max_items / 5)) {
            // Render bombs only when screen has less than 20% (1/5) of bombs
            $newObj = $('<div>', {
                class: 'bomb gravity-enabled',
                style: 'width : ' + diameter + 'px; height: ' + diameter + 'px; top : ' + top + 'px ; left : ' + left + 'px',
                'data-speed': speed,
            });
        } else {
            $newObj = $('<div>', {
                class: 'ball gravity-enabled',
                style:
                    'width : ' +
                    diameter +
                    'px; height: ' +
                    diameter +
                    'px; top : ' +
                    top +
                    'px ; left : ' +
                    left +
                    'px; background-color : rgb(' +
                    getRandomNumber(0, 255) +
                    ', ' +
                    getRandomNumber(0, 255) +
                    ' ,' +
                    getRandomNumber(0, 255) +
                    ');',
                'data-speed': speed,
            });
        }
    }
    $('body').append($newObj);
    updatePosition($newObj, getRandomDirection(), speed); // binding random speed and direction to the newly created object
};

        
    

Considering only 4 directions for now. createItems() function will create a random item (balloon or a bomb according to the probability given by the user). The reason of storing the speed of the div in the markup is to calculate the score when the balloon bursts( click event). Since the newly created element will be a jQuery object, so creating a jQuery object variable using '$'.  That means every time createItem() will get called, a new DIV element will be appended to the body with a random position through css. Note here, balloons need to have position absolute to get rendered at the random positions on the screen. Don't worry about the global variables values that will be fetched from the user from the initial screen. Fetching and setting variables for the functions through input screen-


$('.form-action .action').click(function() { // On click of Start New Game button.
  var complexity = $('.radio-button[type="radio"][name="complexity"]:checked').val();
  if (complexity === 'easy') {
    max_speed_limit = 10;
    min_speed_limit = 3;
    probability = 80;
  } else if (complexity === 'normal') {
    max_speed_limit = 25;
    min_speed_limit = 7;
    probability = 70;
  } else if (complexity === 'expert') {
    max_speed_limit = 40;
    min_speed_limit = 15;
    probability = 55;
  }
  $('.initial-screen').addClass('hidden');
  generateContiniousItems(1000, max_items); // this function will initiate the generation of items after certain time interval. (We will see its implementation later)
});

So far so good ! Items creation function has been created, the DOM has been created and variables has been fetched. Now the main challenge comes ! How to update the positions of all the objects simultaneously and dynamically and have a rebound effect when balloon touches the screen boundaries. JQuery doesn't support classes and OOPS so we cannot create objects instances of class. Then ? In jQuery we can declare a function (here updatePosition() ) once and call it with different parameters thereby creating a new unique instance for each function call. That mean for every newly created item updatePosition() function will have a different instance with different parameters. The function should take three parameters viz. the newly created object as a parameter (to update its css), a random direction and random speed.

We have to update the position in specific time intervals so this fact is clear that position should be updated using setTimeInterval() function. The speed logic can be induced to the div elements using two methods.

  • Having dynamic time interval and fixed distance update factor The random speed of the div can be set by having speed variable as a time interval parameter. In this case the magnitude of positioning factor will be static but the time interval will be different for different div elements.
  • Having dynamic distance update factor and fixed time interval The random speed of the div will be set by having static time interval for each element and speed variable as the distance update factor for each of them. In this case time interval will not change but the magnitude of positioning factor will differ. 

Both approach are right but in first approach the maximum speed is limited from coding end as the max speed according to it will be when the time interval will be 1ms, whereas in second approach the magnitude of positioning factor can exceed to any positive number. So we will use second approach here.

According to the second approach  -

    
        var updatePosition = function ($obj, direction, speed) {
            var down_direc, up_direc, left_direc, right_direc, speedUnit;
            // Setting up the local variables for setting up the left right directions
            // Splitting up the variables to smaller ones to enhance the code readbility
            if (direction === 'top-left') {
                down_direc = false;
                up_direc = true;
                right_direc = false;
                left_direc = true;
            } else if (direction === 'top-right') {
                down_direc = false;
                up_direc = true;
                right_direc = true;
                left_direc = false;
            } else if (direction === 'bottom-right') {
                down_direc = true;
                up_direc = false;
                right_direc = true;
                left_direc = false;
            } else if (direction === 'bottom-left') {
                down_direc = true;
                up_direc = false;
                right_direc = false;
                left_direc = true;
            } else {
                down_direc = false;
                up_direc = true;
                right_direc = false;
                left_direc = true;
            }
            // Conditioning and massaging the speed variable to have sensible speed
            speedUnit = speed / 10;
            // Setting up the boundaries for rebound effect
            var max_bottom_limit = $(window).height() - $obj.height(); // (-) because boundary collision will occur when lower part of the balloon touches the window boundary
            var max_left_limit = $(window).width() - $obj.width(); // (-) because boundary collision will occur when right part of the balloon touches the window boundary
        
            var init_left = $obj.offset().left; // Getting the current position of the div element
            var init_top = $obj.offset().top;
            setInterval(function () {
                // Main logic
                $obj.css({
                    top: init_top, // Updating the position of the div element (starts from the second iteration)
                    left: init_left,
                });
                if (down_direc) {
                    // If the ball vertical movement is down
                    if (init_top < max_bottom_limit) {
                        init_top = init_top + speedUnit; // Update the top position
                        if (init_top >= max_bottom_limit) {
                            // If the element bottom position exceeds the max lower boundary limit
                            init_top = max_bottom_limit; //set the element position to the max bottom boundary limit
                        }
                    }
                    if (init_top === max_bottom_limit) {
                        // If the element has reached to the bottom of the page update the direction variables.
                        down_direc = false; // Direction to top
                        up_direc = true;
                    }
                }
                if (up_direc) {
                    // If the ball vertical movement is up
                    if (init_top > 0) {
                        init_top = init_top - speedUnit; // Update the top position
                        if (init_top <= 0) {
                            // If the element bottom position exceeds the max upper boundary limit
                            init_top = 0; //set the element position to the upper max boundary limit
                        }
                    }
                    if (init_top === 0) {
                        // If the element has reached to the bottom of the page update the direction variables.
                        down_direc = true; // Direction to bottom
                        up_direc = false;
                    }
                }
                if (right_direc) {
                    // If the ball horizontal movement is right
                    if (init_left < max_left_limit) {
                        init_left = init_left + speedUnit; // Update the left position
                        if (init_left >= max_left_limit) {
                            // If the element left position exceeds the max right boundary limit
                            init_left = max_left_limit; //set the element position to the max right boundary limit
                        }
                    }
                    if (init_left === max_left_limit) {
                        // If the element has reached to the bottom of the page update the direction variables.
                        right_direc = false; // Direction to left
                        left_direc = true;
                    }
                }
                if (left_direc) {
                    // If the ball horizontal movement is left
                    if (init_left > 0) {
                        init_left = init_left - speedUnit; // Update the left position
                        if (init_left <= 0) {
                            // If the element left position exceeds the max left boundary limit
                            init_left = 0; //set the element position to the max left boundary limit
                        }
                    }
                    if (init_left === 0) {
                        right_direc = true; // Direction to right
                        left_direc = false;
                    }
                }
            }, 1); // Updating the position on every ms
        };
        
    

The function will update the position of the passed jQuery object through 'init_left' and 'init_top' variables in every 1ms. This will generate the animation effect and on having these values greater than the boundary values the directions are changed. This logic will update left and top both position simultaneously.

Not that hard! Right? You can add new implementations to this project by cloning or forking the code base from https://github.com/swastikpareek/jq_ballon_game or you can create your own jQuery effects or create your own custom game. In this way you will get to learn about new features and new functions in jQuery.

Potential of location based services
Category Items

Potential of location based services

How location-based services power personalization, logistics, and mobile innovation across industries.
5 min read

Its almost paradoxical that the internet, that helped in making the world a smaller place has local as its next major focus area, but there has been a spate of activity in the local internet space in the last year which seems to suggest so. While this space has seen a lot of new services coming up, even the established players are trying to a get a piece of the local pie.

One of the most talked about startup of last year was foursquare. It is a hybrid between a social game and a city guide. You discover interesting places in your city and share it with your friends. It adds the gaming aspect by awarding you points and badges for going to your favorite hangout spots. It already has the early adopters hooked and bloggers like robert scobletechcrunch and mashablevouching for it. Initially it was limited to some cities but very recently they removedthis restriction. Although they do not have a business model as of yet,they already are encouraging interesting discussions about how they can monetize their service. Very similar in the mode of foursquare are other apps like gowalla andmytown

Even some of the established players are venturing into this space. Twitter announced last november that tweets can now be geo-tagged, which will allow people to know where you tweeted from. Google launched their Google Latitudeservice which allows you to share with your friends where you are. There is also another interesting service called Glympse which is competing with Goggle Latitude in this space. Also the portals like msn, yahoo and aol also have turned their attentions towards getting a bigger share of the local advertising share.

Turning our attentions closer to India, while they may not be apps or truly internet based services, I personally think JustDial is doing a very good job of solving the problem of a local business listing in India. They have very cleverly used the intersection of phone,sms and internet to make giant strides and are an indispensable service for me.

What i would love to have though is a service which gives me a good listing of the events happening around me. Do you have an idea for a location based service that you would like to bring to life ? Tell us about it.

Publishing MEAN packages
Category Items

Publishing MEAN packages

Discover the process of contributing to the MEAN ecosystem by registering, writing clean code, and publishing your package for others to use.
5 min read

This is a follow-up blog post from Our Jounrey with MEAN. For those who are not familiar with MEAN, you must go through the previous blog post before proceeding here.

Contrary to Mean core, which is hosted on github, mean packages are hosted on gitlab at https://git.mean.io that fits in the larger vision of MEAN packages. To contribute a packge, an account on gitlab is required. This can be done right from the MEAN cli 


mean register

mean register

 This is very similar to your usual scaffolding command and generates a skeleton structure for your mean package.

Next step for you would be to go ahead and write code in the respective files. Review the code and unit test it thoroughly. Now comes the stage wherein you push the code to the mean repo. All you need to do to publish the mean package is:


cd packages/test
mean publish

To see your module, goto https://git.mean.io/u/<username> and you can see your package listed there. Couple of things you should take care of while contributing a package:

1> Make sure you write an extensive README file.
2> Create an example page to demo the functionality that the package provides.
3> Write clean code.
4> Collaborate rather than compete. 

Higher-Ed
Healthcare
Non-Profits
DXP
Podcast
BizTech
Open Source
Events
Quality Engineering
Design Process
JavaScript
AI
Drupal
Culture