Introduction
This small tip will help to embed Google Visualization Geomap in AngularJS to take AngularJS advantages, e.g., data binding, filtering and responsive behavior.
Let's Start
Let's start with a simple example. Assume there is a big company having consulting business in all states of US. We want to see US map and by clicking on each state, revenue for different departments should be displayed.
The basic code for Geomap is taken from the following URL:
<html>
<head>
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['geomap']});
google.charts.setOnLoadCallback(drawMap);
function drawMap()
{
var data = google.visualization.arrayToDataTable([
['Country', 'Popularity'],
['Germany', 200],
['United States', 300],
['Brazil', 400],
['Canada', 500],
['France', 600],
['RU', 700]
]);
var options = {};
options['dataMode'] = 'regions';
var container = document.getElementById('regions_div');
var geomap = new google.visualization.GeoMap(container);
geomap.draw(data, options);
};
</script>
</head>
<body>
<div id="regions_div" style="width: 900px; height: 500px;"></div>
</body>
</html>
Next, let's update this code to have AngularJS
and separate the JavaScript
and HTML
. First, update the Google map setOnLoadCallback
method and add angular.bootstrap
function to manually start the Angular application (read more about angular.bootstrap
here).
google.load('visualization', '1', { 'packages': ['geochart'] });
google.setOnLoadCallback(function () {
angular.bootstrap(document.body, ['mapsApp']);
});
Surround the rest of code in Angular Module
and Controller
.
angular.module('mapsApp', []).
controller('MapCtrl', ['$scope', '$filter',
function ($scope, $filter) {
All states and number of company's branches in each state are added as data input to the Geomap.
var data = google.visualization.arrayToDataTable([
['State', 'Number of Branches'],
['AL', 32],
['AR', 12],
['AZ', 181],
['CA', 624],
['CO', 139],
['CT', 45],
['DC', 28],
..................
..................
Next, coding block is used to setup Map UI and regions to display. This is quite self-explanatory.
var opts = {
backgroundColor: { fill: '#FFFFFF', stroke: '#FFFFFF', strokeWidth: 0 },
colorAxis: { minValue: 0, maxValue: 4, colors:
['blue', 'yellow', 'green', 'purple', 'brown', ] },
legend: 'none',
backgroundColor: { fill: '#FFFFFF', stroke: '#FFFFFF', strokeWidth: 0 },
datalessRegionColor: '#f5f5f5',
displayMode: 'regions',
enableRegionInteractivity: 'true',
resolution: 'continents',
sizeAxis: { minValue: 1, maxValue: 1, minSize: 10, maxSize: 10 },
region: 'US',
displayMode: 'regions',
resolution: 'provinces',
width: 640,
height: 480
};
Once the UI and data input to Geomap is done, it's time to draw the map. Specify the DIV
name where you want to add the Map. In my case, DIV
name is visualization
.
geochart = new google.visualization.GeoChart(
document.getElementById('visualization'));
geochart.draw(data, opts);
According to our requirement, we want to display each state's department revenue so let's add the click
event in our Geomap. In Geomap, we have select
event that can return value from Geomap input dataset. The following code block will get the state name once user will click
on any state on the map and call $scope.findValue
method that will search revenue data from JSON array.
google.visualization.events.addListener(geochart, 'select', function () {
var selectedItem = geochart.getSelection()[0];
if (selectedItem) {
$scope.findValue(data.getValue(selectedItem.row, 0));
}
});
Following is the revenue data against each state, you can always load this data from datasource using AngularJS services but for POC purpose, I am hard coding the data:
$scope.mapdata = {
"results": [{
state: 'AL',
IT: '$323,208,017.0 ',
FINANCE: '$46,620,000.00 ',
MARKETING: '$63,875,000.00 ',
AUDIT: '$27,440,000.00 ',
},
{
state: 'AR',
IT: '$107,302,792.00',
FINANCE: '$11,660,000.00 ',
MARKETING: '$741,785,000.00',
AUDIT: '$741,785,000.00',
},
..................
..................
The findValue
function will take state name as input parameter and by using the AngularJS $filter
method, it searches revenue data from $scope.mapdata
JSON array variable and returns the result. There was some issue with two way binding and $scope.result
was not visible in HTML so I used the $scope.$apply
method to explicitly populate the $scope
variables.
$scope.findValue = function (vstate) {
var res = $filter('filter')($scope.mapdata.results, { state: vstate })[0];
$scope.$apply(function () { $scope.result = res; });
}
Our result is stored in $scope.result
variable that you can use in HTML file to display.
<script src="angular.js"></script>
<script src="jsapi.js"></script>
<script src="mapsApp.js"></script>
<div ng-controller="MapCtrl" class="row">
<div id="visualization" style="margin: 1em; float:left"> </div>
<div style="float:right">
<div style="width:600px">
<div style="width:600px;">
<div style="width:200px;
float:left"><b>Department</b></div>
<div style="width:200px;
float:left"><b>Revenue</b></div>
</div>
<br />
<hr />
<br />
<div style="width:600px;">
<div style="width:200px;
float:left"><b>IT</b></div>
<div style="width:200px;
float:left">{{result.IT}}</div>
</div>
<br />
<div style="width:600px;">
<div style="width:200px;
float:left"><b>Finance</b></div>
<div style="width:200px;
float:left">{{result.FINANCE}}</div>
</div>
<br />
<div style="width:600px;">
<div style="width:200px;
float:left"><b>Marketing</b></div>
<div style="width:200px;
float:left">{{result.MARKETING}}</div>
</div>
<br />
<div style="width:600px;">
<div style="width:200px;
float:left"><b>Audit</b></div>
<div style="width:200px;
float:left">{{result.AUDIT}}</div>
</div>
</div>
</div>
</div>
History