Thursday, September 5, 2013

How to add user interactivity to jVectorMap

jVectorMap Series 
How to Build a Simple jVectorMap Display
How to integrate data with jVectorMap
How to customize jVectorMap region popups
How to add user interactivity to jVectorMap
How to add a popup modal to jVectorMap using Bootstrap
How to integrate jVectorMap with SharePoint 2010
How to integrate SharePoint 2010 list data with jVectorMap
How to use REST to integrate SharePoint 2010 list data with jVectorMap
How to use SOAP to integrate SharePoint 2010 list data with jVectorMap
Introduction

In the previous posting in this series, we explored how to customize jVectorMap region popups. In this posting, we will explore how to add user interactivity to the jVectorMap display. In this posting, we'll explore how to give the end user the means to:
  • Set the initial focus
  • Change the focus based on user input, and
  • Clear all coloration
Each of these items is implemented using a standard method available through jVectorMap. Understanding how these simple methods are implemented provides the basis for implementing more complex user interactivity in the future.

Before we get started, let's review the code that has been created thus far:
<!DOCTYPE html>
 <html>
 <head>
 <title>jVectorMap demo</title>
<!-- jQuery Library -->
<script src="js/jquery.min.js"></script>
<!-- jvectormap -->
 <link href="css/jquery-jvectormap.css" rel="stylesheet" media="all" />
<script src="js/jquery-jvectormap.js"></script>
<script src="js/jquery-mousewheel.js"></script>
<script src="lib/jvectormap.js"></script>
<script src="lib/abstract-element.js"></script>
<script src="lib/abstract-canvas-element.js"></script>
<script src="lib/abstract-shape-element.js"></script>
<script src="lib/svg-element.js"></script>
<script src="lib/svg-group-element.js"></script>
<script src="lib/svg-canvas-element.js"></script>
<script src="lib/svg-shape-element.js"></script>
<script src="lib/svg-path-element.js"></script>
<script src="lib/svg-circle-element.js"></script>
<script src="lib/vml-element.js"></script>
<script src="lib/vml-group-element.js"></script>
<script src="lib/vml-canvas-element.js"></script>
<script src="lib/vml-shape-element.js"></script>
<script src="lib/vml-path-element.js"></script>
<script src="lib/vml-circle-element.js"></script>
<script src="lib/vector-canvas.js"></script>
<script src="lib/simple-scale.js"></script>
<script src="lib/numeric-scale.js"></script>
<script src="lib/ordinal-scale.js"></script>
<script src="lib/color-scale.js"></script>
<script src="lib/data-series.js"></script>
<script src="lib/proj.js"></script>
<script src="lib/world-map.js"></script>
<script src="assets/jquery-jvectormap-world-mill-en.js"></script>
<!-- Script -->
<script> 
 $.getJSON('data/cdata2.json', function(cdata){
   function chkValue(val){
     if (typeof val ==="undefined"){
       x = 0;
     }
     else{
       x = val;
     }
     return x;
   };
   $('.map1').vectorMap({ 
     map: 'world_mill_en',
     series: {
       //this is the object for passing country/region data into
       regions: [{
         //define the range of color values
         scale: ['#DEEBF7', '#08519C'],
        //define the function that maps data to color range
         normalizeFunction: 'linear',
         //define the coloration method
         attribute: 'fill',
         //define the array of country data
         values: cdata
       }]
     },
     onRegionLabelShow: function(event, label, code){
       label.html(label.html() +' (' + code.toString() + ') <br>Count: ' 
      + chkValue(cdata[code]));
     },
   });
   setInterval(function(){
     $.getJSON('data/cdata2.json', function(cdata){
       var map = $('.map1').vectorMap('get', 'mapObject');
       map.series.regions[0].setValues(cdata);
     })
   }, 10000); 
})
</script>
 </head>
 <body>
<!-- jVectorMap display container -->
 <div class="map1" style="width: 800px; height: 550px"></div>
 </body>
 </html>
This is the markup and script that we'll be working with for the rest of this posting.

How to set the initial focus

To set the initial focus and scale of the display, we'll need to set one property: the focusOn property.  This needs to be added after the map property setting, like so (looking at just the <script> section).  Highlighted below is what you need to add:
<script>
 $.getJSON('data/cdata2.json', function(cdata){
   function chkValue(val){
     if (typeof val ==="undefined"){
       x = 0;
     }
     else{
       x = val;
     }
     return x;
   };
   $('.map1').vectorMap({ 
     map: 'world_mill_en',
    //Set the initial focus to the center of the map
    //at the maximum zoom out
    focusOn: {
       x: 0.5,
       y: 0.5,
       scale: 1
     },
     series: {
       //this is the object for passing country/region data into
       regions: [{
         //define the range of color values
         scale: ['#DEEBF7', '#08519C'],
         //define the function that maps data to color range
         normalizeFunction: 'linear',
         //define the coloration method
         attribute: 'fill',
         //define the array of country data
         values: cdata
       }]
     },
     onRegionLabelShow: function(event, label, code){
       label.html(label.html() +' (' + code.toString() + ') <br>Count: ' 
      + chkValue(cdata[code]));
     },
   });
   setInterval(function(){
     $.getJSON('data/cdata2.json', function(cdata){
       var map = $('.map1').vectorMap('get', 'mapObject');
       map.series.regions[0].setValues(cdata);
     })
   }, 10000); 
})
</script>

With this addition, you will get a display that looks just like the one you created previously.


The difference is that you now control the initial focus and can set it to wherever you want. Note that the X and Y ranges are from "0" to "1", where "0,0" would be the top left corner and "1,1" would be the bottom right corner.

Change the focus based on user input

We can provide the capability to the user to change the focus by using a button click event to drive the vectorMap set method.  We'll use jQuery to simplify selecting the appropriate button element; and then we'll add a button element to the markup.  The results is shown below, with additions highlighted:
<script>
 $.getJSON('data/cdata2.json', function(cdata){
   function chkValue(val){
     if (typeof val ==="undefined"){
       x = 0;
     }
     else{
       x = val;
     }
     return x;
   };
  //Sets focus on Sweden
   $('#focus-single').click(function(){
     $('.map1').vectorMap('set', 'focus', 'SE');
   });
   $('.map1').vectorMap({ 
     map: 'world_mill_en',
     //Set the initial focus to the center of the map
     //at the maximum zoom out
     focusOn: {
       x: 0.5,
       y: 0.5,
       scale: 1
     },
     series: {
       //this is the object for passing country/region data into
       regions: [{
         //define the range of color values
         scale: ['#DEEBF7', '#08519C'],
         //define the function that maps data to color range
         normalizeFunction: 'linear',
         //define the coloration method
         attribute: 'fill',
         //define the array of country data
         values: cdata
       }]
     },
     onRegionLabelShow: function(event, label, code){
       label.html(label.html() +' (' + code.toString() + ') <br>Count: ' 
      + chkValue(cdata[code]));
     },
   });
   setInterval(function(){
     $.getJSON('data/cdata2.json', function(cdata){
       var map = $('.map1').vectorMap('get', 'mapObject');
       map.series.regions[0].setValues(cdata);
     })
   }, 10000); 
})
</script>
 </head>
 <body>
<!-- jVectorMap display container -->
 <div class="map1" style="width: 800px; height: 550px"></div>
<!-- button focus on Sweden container -->
 <button id="focus-single">Focus on Sweden</button>
 </body>
 </html>
The result of these additions is shown in the image below:

Note that the selector for the button used the element ID.  You could also have used a unique class - either approach works.  Just be sure to distinguish between using the class method, which employs a ".", and the ID method, which employs a "#".  Examine the script carefully to  see these differences. 

Now, another capability can be added that resets the focus. To do so, just add this bit of script after the one you added previously:
//Reset focus
 $('#focus-init').click(function(){
   $('.map1').vectorMap('set', 'focus', 1, 0, 0);
});  
Then, add another button container, like so:
<!-- Reset map button -->
 <button id="focus-init">Reset Map</button>
Refresh your map, and you'll then see the image below:
The last three parameters that you see here, "1, 0, 0", set the zoom level and the x and y coordinates.  Setting the zoom level to "1", is the maximum zoom out level.  So, it doesn't really matter what you set the x,y coordinates to, as maximum zoom out effectively centers the display.  If you explore this a bit further, you will discover that you can create highly customized zoom functions to any coordinates on the map and at all available zoom levels.  Remember: the ranges for the x,y coordinates are 0 to 1.

Note that the selector for the element again used the ID method.  When adding these event handlers in the format shown here, be sure to add them within the context of the getJSON function.  You can add any other type of capability here using the same approach - just change the script in the event handler to whatever you need to do.

Clear all coloration

In the last part of this article, we'll explore how to clear all of the coloration of the map.  Note that the current implementation has a refresh capability through the JavaScript setInterval function, so, implementing a clear map function will allow you to more clearly see the refresh capability in action.  To clear all of coloration means to clear all of the color coding among the regions of the map.  To do this, we'll need to use the clear method of the regions object.  Remember that it was the values property of the regions object that you populated with country date, in the second article of this series.  To use this method, we'll first need to create a new instance of the map object.  We'll use another button event handler to drive this action.  First, add this script just after the previous event handlers that you added above:
//Clears all region colors
 $('#clear-map').click(function(){
   var map = $('.map1').vectorMap('get', 'mapObject');
   map.series.regions[0].clear();
});  
Then add the container for the new button:
<!-- Clear map button -->
 <button id="clear-map">Clear Map</button>

And then refresh the map.  Click on the new button, and you'll see all of the regional color cleared, as shown in the image below.
Wait a few moments, and the regions will be colored again.
Note that the clear method only affects the coloration: it does not affect the popup values.  After clicking the Clear Map button, move the cursor around and you'll see that the appropriate regional names and counts continue to be displayed.

Summary

In this article, you have learned how to set the initial focus on the map and provide capabilities to the user to change that focus, reset the focus, and clear the regional coloration.  In the next article of this series, we'll explore how to add a modal popup help button.

References
Notes
  • The vectorMap method can be used to change any option (except callbacks) after map initialization.  Note that one of the input parameters for the function is the name of the particular method that you want to employ.

No comments: