Sunday 31 May 2015

Using Google Map Geolocation API with AngularJS..

When I first start working on google map  for Angular JS, excitement went through my nerves and started realizing how angular js made everything so simple. This is probably the second one on google map and I came to learn about this from one of JSFiddle. So I have tried to make a little modification and finally came out with this.
This module contains two utilities. 1. Finding your current location 2. Searching a particular location. Markers are also added with hard-coded array elements containing name of cities and it's coordinates. Filters are also applied to convert decimal coordinated to degree minutes and seconds. I hope you find this angularjs tutorial helpful.

<!-- HTML module -->

<!DOCTYPE html>
<html>
<body ng-app="app" ng-controller="appCtrl">
<script
    src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<script
    src="http://maps.googleapis.com/maps/api/js?sensor=false&language=en"></script>
  <script type="text/javascript" src="geoLoc.js"></script>
<h3>Google Maps</h3>

    <!-- search/go to current location -->
    <div class="text-right">
        <div class="input-append text-right">
            <input type="text" ng-model="search"/>
            <button class="btn" type="button" ng-click="geoCode()" ng-disabled="search.length == 0" title="search" >
              &nbsp;<i class="icon-search"></i>Where is this place?
            </button>
            <button class="btn" type="button" ng-click="gotoCurrentLocation()" title="current location">
              &nbsp;<i class="icon-home"></i>Where am I now?
            </button>
        </div>
    </div>

    <!-- map -->
    <app-map style="height:400px;margin:12px;box-shadow:0 3px 25px black;"
        center="loc"
        markers="cities"  >
    </app-map>

    <!-- current location -->
    <div class="text-info text-right">
        {{loc.lat | lat:0}}, {{loc.lon | lon:0}}
    </div>

    <!-- list of cities -->
    <div class="container-fluid">
        <div class="span3 btn"
            ng-repeat="a in cities"
            ng-click="gotoLocation(a.lat, a.lon)">
            <b>{{a.place}}</b>: {{a.desc}}
        </div>
    </div>
</body>
</html
/* JS module */

var app = angular.module("app", []);

app.controller("appCtrl", function ($scope) {

    // current location
    $scope.loc = { lat: 23, lon: 79 };
    $scope.gotoCurrentLocation = function () {
        if ("geolocation" in navigator) {
            navigator.geolocation.getCurrentPosition(function (position) {
                var c = position.coords;
                $scope.gotoLocation(c.latitude, c.longitude);
            });
            return true;
        }
        return false;
    };
    $scope.gotoLocation = function (lat, lon) {
        if ($scope.lat != lat || $scope.lon != lon) {
            $scope.loc = { lat: lat, lon: lon };
            if (!$scope.$$phase) $scope.$apply("loc");
        }
    };

    // geo-coding
    $scope.search = "";
    $scope.geoCode = function () {
        if ($scope.search && $scope.search.length > 0) {
            if (!this.geocoder) this.geocoder = new google.maps.Geocoder();
                  this.geocoder.geocode({ 'address': $scope.search }, function (results, status) {
                if (status == google.maps.GeocoderStatus.OK) {
                    var loc = results[0].geometry.location;
                    $scope.search = results[0].formatted_address;
                    $scope.gotoLocation(loc.lat(), loc.lng());
                } else {
                    alert("Sorry, this search produced no results.");
                }
            });
        }
    };

 $scope.cities = [
              {
                  place : 'India',
                  desc : 'A country of culture and tradition!',
                  lat : 23.200000,
                  lon : 79.225487
              },
              {
                  place : 'New Delhi',
                  desc : 'Capital of India...',
                  lat : 28.500000,
                  lon : 77.250000
              },
              {
                  place : 'Kolkata',
                  desc : 'City of Joy...',
                  lat : 22.500000,
                  lon : 88.400000
              },
              {
                  place : 'Mumbai',
                  desc : 'Commercial city!',
                  lat : 19.000000,
                  lon : 72.90000
              },
              {
                  place : 'Bangalore',
                  desc : 'Silicon Valley of India...',
                  lat : 12.9667,
                  lon : 77.5667
              }
          ];   
});

// formats a number as a latitude (e.g. 20.46... => "20°27'44"N")
app.filter('lat', function () {
    return function (input, decimals) {
        if (!decimals) decimals = 0;
        input = input * 1;
        var ns = input > 0 ? "N" : "S";
        input = Math.abs(input);
        var deg = Math.floor(input);
        var min = Math.floor((input - deg) * 60);
        var sec = ((input - deg - min / 60) * 3600).toFixed(decimals);
        return deg + "°" + min + "'" + sec + '"' + ns;
    }
});

// formats a number as a longitude (e.g. -80.02... => "80°1'24"W")
app.filter('lon', function () {
    return function (input, decimals) {
        if (!decimals) decimals = 0;
        input = input * 1;
        var ew = input > 0 ? "E" : "W";
        input = Math.abs(input);
        var deg = Math.floor(input);
        var min = Math.floor((input - deg) * 60);
        var sec = ((input - deg - min / 60) * 3600).toFixed(decimals);
        return deg + "°" + min + "'" + sec + '"' + ew;
    }
});

// - Documentation: https://developers.google.com/maps/documentation/
app.directive("appMap", function () {
    return {
        restrict: "E",
        replace: true,
        template: "<div></div>",
        scope: {
            center: "=",        // Center point on the map (e.g. <code>{ latitude: 10, longitude: 10 }</code>).
            markers: "=",       // Array of map markers (e.g. <code>[{ lat: 10, lon: 10, name: "hello" }]</code>).
            width: "@",         // Map width in pixels.
            height: "@",        // Map height in pixels.
            zoom: "@",          // Zoom level (one is totally zoomed out, 25 is very much zoomed in).
            mapTypeId: "@",     // Type of tile to show on the map (roadmap, satellite, hybrid, terrain).
            panControl: "@",    // Whether to show a pan control on the map.
            zoomControl: "@",   // Whether to show a zoom control on the map.
            scaleControl: "@"   // Whether to show scale control on the map.
        },
        link: function (scope, element, attrs) {
            var toResize, toCenter;
            var map;
            var currentMarkers;

            // listen to changes in scope variables and update the control
            var arr = ["width", "height", "markers", "mapTypeId", "panControl", "zoomControl", "scaleControl"];
            for (var i = 0, cnt = arr.length; i < arr.length; i++) {
                scope.$watch(arr[i], function () {
                    cnt--;
                    if (cnt <= 0) {
                        updateControl();
                    }
                });
            }

            // update zoom and center without re-creating the map
            scope.$watch("zoom", function () {
                if (map && scope.zoom)
                    map.setZoom(scope.zoom * 1);
            });
            scope.$watch("center", function () {
                if (map && scope.center)
                    map.setCenter(getLocation(scope.center));
            });

            // update the control
            function updateControl() {

                // update size
                if (scope.width) element.width(scope.width);
                if (scope.height) element.height(scope.height);

                // get map options
                var options =
                {
                    center: new google.maps.LatLng(23, 79),
                    zoom: 6,
                    mapTypeId: "roadmap"
                };
                if (scope.center) options.center = getLocation(scope.center);
                if (scope.zoom) options.zoom = scope.zoom * 1;
                if (scope.mapTypeId) options.mapTypeId = scope.mapTypeId;
                if (scope.panControl) options.panControl = scope.panControl;
                if (scope.zoomControl) options.zoomControl = scope.zoomControl;
                if (scope.scaleControl) options.scaleControl = scope.scaleControl;

                // create the map
                map = new google.maps.Map(element[0], options);

                // update markers
                updateMarkers();

                // listen to changes in the center property and update the scope
                google.mapTypeIds.event.addListener(map, 'center_changed', function () {

                    // do not update while the user pans or zooms
                    if (toCenter) clearTimeout(toCenter);
                    toCenter = setTimeout(function () {
                        if (scope.center) {

                            // check if the center has really changed
                            if (map.center.lat() != scope.center.lat ||
                                map.center.lng() != scope.center.lon) {

                                // update the scope and apply the change
                                scope.center = { lat: map.center.lat(), lon: map.center.lng() };
                                if (!scope.$$phase) scope.$apply("center");
                            }
                        }
                    }, 500);
                });
            }

            // update map markers to match scope marker collection
            function updateMarkers() {
                if (map && scope.markers) {

                    // clear old markers
                    if (currentMarkers != null) {
                        for (var i = 0; i < currentMarkers.length; i++) {
                            currentMarkers[i] = m.setMap(null);
                        }
                    }

                    // create new markers
                    currentMarkers = [];
                    var markers = scope.markers;
                    if (angular.isString(markers)) markers = scope.$eval(scope.markers);
                    for (var i = 0; i < markers.length; i++) {
                        var m = markers[i];
                        var loc = new google.maps.LatLng(m.lat, m.lon);
                        var mm = new google.maps.Marker({ position: loc, map: map, title: m.name });
                        currentMarkers.push(mm);
                    }
                }
            }

            // convert current location to Google maps location
            function getLocation(loc) {
                if (loc == null) return new google.maps.LatLng(23, 79);
                if (angular.isString(loc)) loc = scope.$eval(loc);
                return new google.maps.LatLng(loc.lat, loc.lon);
            }
        }
    };
});


You can also find the code in : Google Drive

And can also check out for the video tutorial on : Youtube - Using Google Map Geolocation API with AngularJS

Google Maps



{{loc.lat | lat:0}}, {{loc.lon | lon:0}}

{{a.place}}: {{a.desc}}

Tuesday 26 May 2015

Using google map with Angular JS.

Today I have tried a small project to implement google map with Angular JS. I have used  in this project 3 files. 1. google-map.html 2. map.js  3. map.css. google-map.html contains the container to display the map with it's default locations and custom locations. I have provided it with 5 citeis of India with their latitude and longitude, Below given is the code of both 3 modules.





// map.js

var cities = [
              {
                  place : 'India',
                  desc : 'A country of culture and tradition!',
                  lat : 23.200000,
                  long : 79.225487
              },
              {
                  place : 'New Delhi',
                  desc : 'Capital of India...',
                  lat : 28.500000,
                  long : 77.250000
              },
              {
                  place : 'Kolkata',
                  desc : 'City of Joy...',
                  lat : 22.500000,
                  long : 88.400000
              },
              {
                  place : 'Mumbai',
                  desc : 'Commercial city!',
                  lat : 19.000000,
                  long : 72.90000
              },
              {
                  place : 'Bangalore',
                  desc : 'Silicon Valley of India...',
                  lat : 12.9667,
                  long : 77.5667
              }
          ];

          //Angular App Module and Controller
          var mapApp = angular.module('mapApp', []);
          mapApp.controller('MapController', function ($scope) {
             
              var mapOptions = {
                  zoom: 4,
                  center: new google.maps.LatLng(25,80),
                  mapTypeId: google.maps.MapTypeId.ROADMAP
              }

              $scope.map = new google.maps.Map(document.getElementById('map'), mapOptions);

              $scope.markers = [];
             
              var infoWindow = new google.maps.InfoWindow();
             
              var createMarker = function (info){
                 
                  var marker = new google.maps.Marker({
                      map: $scope.map,
                      position: new google.maps.LatLng(info.lat, info.long),
                      title: info.place
                  });
                  marker.content = '<div class="infoWindowContent">' + info.desc + '<br />' + info.lat + ' E,' + info.long +  ' N, </div>';
                 
                  google.maps.event.addListener(marker, 'click', function(){
                      infoWindow.setContent('<h2>' + marker.title + '</h2>' +
                        marker.content);
                      infoWindow.open($scope.map, marker);
                  });
                 
                  $scope.markers.push(marker);
                 
              } 
             
              for (i = 0; i < cities.length; i++){
                  createMarker(cities[i]);
              }

              $scope.openInfoWindow = function(e, selectedMarker){
                  e.preventDefault();
                  google.maps.event.trigger(selectedMarker, 'click');
              }

          });


<!--google-map.html -->

<!DOCTYPE html>
<html ng-app="mapApp">
<head>
<meta charset="ISO-8859-1">
<title>Maps in AngularJS</title>
<link rel="stylesheet" href="map.css">
<script
    src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.3/angular.min.js"></script>
<script
    src="http://maps.googleapis.com/maps/api/js?sensor=false&language=en"></script>
  <script type="text/javascript" src="map.js"></script>
</head>
<body>
<div ng-controller="MapController">
    <div id="map"></div>
    <div id="repeat" ng-repeat="marker in markers | orderBy : 'title'">
         <a id="country_container" href="#" ng-click="openInfoWindow($event, marker)">
         <label id="names" >{{marker.title}}</label></a>
    </div>
</div>
</body>
</html>


/* map.css */

body {
    font: bold 12px Arial;
     }
a {
    text-decoration: none;
  }
#map{
    height:500px;
    width:500px;
/*    box-shadow: 3px 3px 10px gray;*/ 
    }
#repeat{
     display: inline;
     }
#country_container {
     margin: 8px 2px 2px 0px;
     text-align: center;
     width: 90px;
     padding: 5px;
     color: white;
     background-color: gray;
     font-size: 16px;
     cursor: pointer;
     }
#country_container:hover {
     box-shadow: 0px 0px 10px blue;
     background-color: gray;
     border: 1px solid gray;
     cursor: pointer;
     }
#names {
     cursor: pointer;
       }

Wednesday 13 May 2015

Factory versus service in Angular JS



In my previous post I have shown how to inject service dependencies in Angular JS. This portion of code shows difference between service and factory. I have created one service and one factory  Although I have used only the factory but you can replace the factory with the service injecting inside the controller.

<html ng-app="app">
<head>
<title>
    Difference between factory and service.
</title>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script type="text/javascript">
    app = angular.module('app',[]);
    app.factory('CalcFactory',function() {
        return {
        Add: function(a,b) {
            return parseFloat(a) + parseFloat(b);
        },
        Multiply: function(a,b) {
            return a * b;
        }
        }
    });

    app.service('CalcService',function() {
        this.Add = function(a,b) {
            return parseFloat(a) + parseFloat(b);
        };
        this.Multiply = function(a,b) {
            return a * b;
        };
    });  

    app.controller('MainCtrl',function($scope,CalcFactory,CalcService) {
        $scope.AddNumbers = function() {
        $scope.resultNum = CalcFactory.Add($scope.firstNum,$scope.secondNum);
        };
        $scope.MultiplyNumbers = function() {
        $scope.resultNum = CalcFactory.Multiply($scope.firstNum,$scope.secondNum);
        };
    });

</script>
</head>
<body ng-controller="MainCtrl">
<label>Enter First Number : </label>
<input type="text" name="firstNum" ng-model="firstNum" value="" /><br />
<label>Enter Second Number : </label>
<input type="text" name="secondNum" ng-model="secondNum" value="" /><br />
<input type="button" value="Add Number" ng-click="AddNumbers()" / ><br />
<span>Result Value : {{resultNum}}</span>
</body>
</html>
 

Injecting dependencies with service.



This section of code is written with an attempt to clear the concept of dependency injection with service. Here a service Calc is created and injected in a controller. I hope you will like this section of code and do comment if you have any queries regarding any part of it. I have notadded any separate app.js file but added all the code within a file with script tag.

<html ng-app="app">
<head>
<title>
    Injecting dependency in services.
</title>
<script src= "http://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script type="text/javascript">
    app = angular.module('app',[]);
    //Creating service with two functions which will be injected later on into the controller.
    app.service('CalcService',function() {
        this.Add = function(a,b) {
            return parseFloat(a) + parseFloat(b);
        };
        this.Multiply = function(a,b) {
            return a * b;
        };
    });
   // You can find how CalcService is injected into the controller
    app.controller('MainCtrl',function($scope,CalcService) {
        $scope.AddNumbers = function() {
        $scope.resultNum = CalcService.Add($scope.firstNum,$scope.secondNum);
        };
        $scope.MultiplyNumbers = function() {
        $scope.resultNum = CalcService.Multiply($scope.firstNum,$scope.secondNum);
        };
    });

</script>
</head>
<body ng-controller="MainCtrl">
<label>Enter First Number : </label>
<input type="text" name="firstNum" ng-model="firstNum" value="" /><br />
<label>Enter Second Number : </label>
<input type="text" name="secondNum" ng-model="secondNum" value="" /><br />
<input type="button" value="Multiply Number" ng-click="MultiplyNumbers()" / ><br />
<span>Result Value : {{resultNum}}</span>
</body>
</html>