Skip Navigation LinksCustom JavaScript Code

For further information about using JavaScript with InstantAtlas refer to our JavaScript API.


When you publish an InstantAtlas report, the output contains a file called custom.js.

You can use this file to include custom code that will be executed once the report has completed loading.

The default custom.js file contains the following code:

/** 
 * This function is called after the report has finished loading.
 * The report object is the entry point to the JavaScript API.
 *
 * @param report The InstantAtlas Report object.
 */
onIAReportComplete = function(report)
{

};

When a report has finished loading it calls the function onIAReportComplete with a report object that can be used as the entry point to the InstantAtlas JavaScript API. Any code placed inside this function will be executed at this point.

This page contains examples of code that you can use and adapt to customize your reports.

Either copy and paste the sample code into your custom.js file or download a custom.js file from this page and overwrite the old file.

Make sure all code you add is contained within the onIAReportComplete function.

Custom Code

  1. Event Listeners
    1. Listen for when a geography, indicator or filter has been changed. (v671)
    2. Listen for mouse events that occur when map features, chart items or table rows are clicked, hovered etc. (v671)
    3. Listen for selection and highlighting of map features, chart items or table rows. (v671)
    4. Listen for map navigation mouse events, such as when the map is dragged or clicked. (v671)
  2. Custom Components
    1. Add a custom button. (v671)
    2. Add a custom panel that updates when the indicator is changed. (v671)
    3. Add a custom panel that updates when a feature is selected. (v671)
    4. Add a custom panel that displays indicator data for the selected features. (v671)
    5. Add a custom button that toggles a custom panel. (v671)
    6. Add a menu which enables the user to load a different map.js and data.js without reloading the report. (v671)
    7. Change the data explorers behaviour to just show the first theme. (v671)
    8. Display a splash screen at startup. (v671)
    9. Select and zoom to a feature from a list of feature names. (v671)
    10. Collapse the tree in the data explorer. (v671)
    11. Use custom dropdown menus for selecting data. (v671)
    12. Use a button to toggle between multiple charts layered on top of each other. (v671)
  3. Custom Map Behaviour
    1. Show a callout box that displays indicator data when you click on a map feature. (v671)
    2. Add a drilldown to the map when you click or double click on a feature. (v671)
    3. Change the maps behaviour to zoom in / zoom out when a feature is selected / unselected. (v671)
    4. Synchronize selection and highlighting across two maps. (v671)
    5. Toggle a contextual layer depending on the selected geography. (v671)
    6. Toggle a contextual layer depending on the selected indicator. (v671)
    7. Change the base layer according to the zoom level of the map. (v671)
  4. Search functions that can be attached to the map search tool
    1. Search the feature names in all map layers for the given search term.
    2. Carry out a single line search using the ArcGIS Server geocoding rest api. (v671)
    3. Carry out a single line address search using the ArcGIS Server geocoding rest api. (v671)
  5. Touch Devices
    1. Disable the default touch functionality. (v671)
  6. Custom Charts
    1. Add a google tree map that displays profile data for a selected feature. (v671)
  7. Custom Data Behaviour
    1. Change the geography depending on the selected indicator. (v671)
    2. Toggle a contextual layer depending on the selected geography. (v671)
    3. Toggle a contextual layer depending on the selected indicator. (v671)
    4. Load a different map.js and data.js without reloading the report. (v671)
    5. Change the data explorers behaviour to just show the first theme. (v671)
    6. Define the geographies that will be displayed in the geography explorer using JSON. (v671)
  8. Custom Template Behaviour
    1. Load a different config.xml without reloading the report. (v672)
  9. Interface
    1. Add tooltips to component tools (v672)

Custom functions that can be called buttons, hyperlinked text or menu bar buttons

These are functions that you will most likely call from buttons or the menu bar.

An example of what this looks like in your 'config.xml' file when opened in a text editor is:
<Button href="javascript:iaToggle(map)" />

You may also call multiple functions from the same button, using a semi-colon to separate each function:
<Button href="javascript:iaToggle(map);iaToggle(table)" />

These functions will be visible to any other JavaScript Libraries that you may have included in your web page so give them names which are not likely to cause conflicts. A good rule of thumb is to prepend all your functions with "ia" as in "iaToggle(map)"

  1. Toggle Components
    1. Toggle the visibility of a component. (v671)
    2. Toggle the visibility of a popup window. (v671)
    3. Toggle the visibility of a callout box. (v671)
    4. Toggle the visibility of the share callout box. (v671)
    5. Show a component. (v671)
    6. Hide a component. (v671)
    7. Resize a component. (v671)
    8. Expand / Collapse the profile tree. (v671)
    9. Open the print preview window. (v671)
  2. Change Data
    1. Load a new data.js and map.js file without reloading the report. (v671)
    2. Change the indicator. (v671)
    3. Set a new filter. (v671)
    4. Clear the filter. (v671)
  3. Map Navigation
    1. Zoom in to the map. (v671)
    2. Zoom out of the map. (v671)
    3. Zoom the map to full extents. (v671)
    4. Zoom to a map bounding box. (v671)
    5. Zoom to a feature. (v671)
  4. Miscellaneous
    1. Open notes for the selected indicator. (v671)
Listen for when a geography, indicator or filter has been changed. (v671)
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 
    
// This code executes every time an indicator has changed.
dataGroup.addEventListener(ia.DataEvent.INDICATOR_CHANGED, function(event)
{
    var str = "The indicator was changed:\n";
    str += "\nGeography: "+event.geography.name;
    str += "\nTheme: "+event.theme.name;
    str += "\nIndicator: "+event.indicator.name+" "+event.indicator.date;
    alert(str);
});

// This code executes every time a geography has changed.
dataGroup.addEventListener(ia.DataEvent.GEOG_CHANGED, function(event)
{
    var str = "The geography was changed:\n";
    str += "\nGeography: "+event.geography.name;
    str += "\nTheme: "+event.theme.name;
    str += "\nIndicator: "+event.indicator.name+" "+event.indicator.date;
    alert(str);
});

// This code executes every time a filter has changed.
dataGroup.addEventListener(ia.FilterEvent.FILTER_CHANGED, function(event)
{
    var str = "The filter was changed:\n";
    str += "\nFilter id: "+event.filterId;
    str += "\nFilter name: "+event.filterName;
    str += "\nFilter value: "+event.filterValue;
    alert(str);
});
Listen for mouse events that occur when map features, chart items or table rows are clicked, hovered etc. (v671)
// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 
    
// Records the number of clicks to distiguish between a single and double click.
var clicks = 0;

// Add listeners for mouse item events.
interactionGroup.addEventListener(ia.ItemEvent.ITEM_CLICK, itemEventHandler);
interactionGroup.addEventListener(ia.ItemEvent.ITEM_MOUSE_OVER, itemEventHandler);
interactionGroup.addEventListener(ia.ItemEvent.ITEM_MOUSE_OUT, itemEventHandler);
interactionGroup.addEventListener(ia.ItemEvent.ITEM_MOUSE_DOWN, itemEventHandler);
interactionGroup.addEventListener(ia.ItemEvent.ITEM_MOUSE_UP, itemEventHandler);
interactionGroup.addEventListener(ia.ItemEvent.ITEM_MOUSE_MOVE, itemEventHandler);

// This function is executed whenever one of the above events is dispatched.
function itemEventHandler(event)
{
    if (event.type == ia.ItemEvent.ITEM_CLICK)  // Mouse click event occurred.
    {
        // Test for double click.
        clicks++;

        if (clicks == 1) 
        {
            setTimeout(function()
            {
                if (clicks == 1) 
                {
                    // Single click.
                }
                else 
                {
                    // Double click.
                }
                clicks = 0;
            }, 300);
        }

        // Check the state of the item to see if it is selected or unselected.
        if (event.item.state == "selected" 
        || event.item.state == "rollOverSelected")
        {
            alert(event.item.id+" was selected");
        }
        else if (event.item.state == "unselected")
        {
            alert(event.item.id+" was unselected");
        }
    }
    else if (event.type == ia.ItemEvent.ITEM_MOUSE_MOVE) {}     // Mouse move event occurred.
    else if (event.type == ia.ItemEvent.ITEM_MOUSE_OVER) {}     // Mouse over event occurred. 
    else if (event.type == ia.ItemEvent.ITEM_MOUSE_OUT) {}      // Mouse out event occurred.  
    else if (event.type == ia.ItemEvent.ITEM_MOUSE_DOWN) {}     // Mouse down event occurred. 
    else if (event.type == ia.ItemEvent.ITEM_MOUSE_UP) {}       // Mouse up event occurred.  
}

// Add listener for when the selection is cleared.
interactionGroup.addEventListener(ia.Event.CLEAR_SELECTION, clearSelectionHandler);
function clearSelectionHandler(event)
{
    if (event.type == ia.Event.CLEAR_SELECTION) {alert("The selection was cleared")}  
}
Listen for selection and highlighting of map features, chart items or table rows. (v671)
// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 

// Add listeners for selection and highlight events.
interactionGroup.addEventListener(ia.InteractionEvent.SELECTION_CHANGED, interactionEventHandler);
interactionGroup.addEventListener(ia.InteractionEvent.HIGHLIGHT_CHANGED, interactionEventHandler);

// This function is executed whenever one of the above events is dispatched.
function interactionEventHandler(event)
{
    if (event.type == ia.InteractionEvent.SELECTION_CHANGED) // Selection Changed.
    {
        alert("Selected ids: " + event.ids);
    }
    else if (event.type == ia.InteractionEvent.HIGHLIGHT_CHANGED) // Highlight Changed.
    {
        // alert("Highlight id: " + event.ids);
    } 
}
Listen for map navigation mouse events, such as when the map is dragged or clicked. (v671)
// Map events dont work when using google maps.
var map = report.getComponent("map");

// Add listeners for map mouse events.
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_CLICK, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_OVER, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_OUT, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_DOWN, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_UP, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_MOVE, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_DRAG, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_DRAG_UP, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_WHEEL, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_MOUSE_WHEEL_END, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_PINCH_DOWN, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_PINCH_MOVE, mapEventHandler);
map.addEventListener(ia.MapMouseEvent.MAP_PINCH_UP, mapEventHandler);

// This function is executed whenever one of the above events is dispatched.
function mapEventHandler(event)
{
    // alert(event.map); // The map that dispatched the event.
    
    if (event.type == ia.MapMouseEvent.MAP_MOUSE_CLICK)             // Mouse click event occurred. 
    {
        alert("mouse-x='" + event.x 
                + "' mouse-y='" + event.y 
                + "' data-x='" + event.dataX 
                + "' data-y='" + event.dataY + "'");
    }
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_MOVE) {}      // Mouse move event occurred.
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_OVER) {}      // Mouse over event occurred. 
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_OUT) {}       // Mouse out event occurred.  
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_DOWN) {}      // Mouse down event occurred. 
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_UP) {}        // Mouse up event occurred. 
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_DRAG) {}      // Mouse drag event occurred. 
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_DRAG_UP) {}   // Mouse drag up event occurred.   
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_WHEEL) {}     // Mouse wheel event occurred.   
    else if (event.type == ia.MapMouseEvent.MAP_MOUSE_WHEEL_END) {} // Mouse wheel end event occurred.   
    else if (event.type == ia.MapMouseEvent.MAP_PINCH_DOWN) {}      // Pinch down event occurred.   
    else if (event.type == ia.MapMouseEvent.MAP_PINCH_MOVE) {}      // Pinch move event occurred.   
    else if (event.type == ia.MapMouseEvent.MAP_PINCH_UP) {}        // Pinch up event occurred.  
}

// Add listeners for map bounding box events.
map.addEventListener(ia.BBoxEvent.BBOX_TRANSLATE, bBoxEventHandler);
map.addEventListener(ia.BBoxEvent.BBOX_SCALE, bBoxEventHandler);
function bBoxEventHandler(event)
{
     // alert(event.bBox.toString());
}
Add a custom button. (v671)
var myButton = new ia.Button("myButtonId", "My Button"); 
myButton.tooltip("My Button Tip");
myButton.setDimensions(55, 15, 15, 4); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
myButton.onclick(function(e) 
{
    alert("clicked!");
});
report.addButton(myButton);
Add a custom panel that updates when the indicator is changed. (v671)
   
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// Add custom panel.
var myPanel = new ia.Panel("myPanelId", "Indicator Info");
myPanel.setDimensions(55, 20, 15, 40); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
myPanel.closeable(true);
report.addPanel(myPanel);
myPanel.show();

// Add a scrollable div to contain your content.
var $myContent = $j("<div style='overflow:auto;height:100%;padding:10px'>");
myPanel.append($myContent);

// Executed when the report is first loaded.
var str = "Geography: <b>"+dataGroup.geography.name+"</b>";
str += "<br/>Theme: <b>"+dataGroup.theme.name+"</b>";
str += "<br/>Indicator: <b>"+dataGroup.indicator.name+" "+dataGroup.indicator.date+"</b>";
$myContent.html(str);
    
// This code executes every time an indicator has changed.
dataGroup.addEventListener(ia.DataEvent.INDICATOR_CHANGED, function(event)
{
    var str = "Geography: <b>"+event.geography.name+"</b>";
    str += "<br/>Theme: <b>"+event.theme.name+"</b>";
    str += "<br/>Indicator: <b>"+event.indicator.name+" "+event.indicator.date+"</b>";
    $myContent.html(str);
});
Add a custom panel that updates when a feature is selected. (v671)
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 

// Add custom panel.
var myPanel = new ia.Panel("myPanelId", "Selected Features");
myPanel.setDimensions(55, 20, 15, 40); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
report.addPanel(myPanel);
myPanel.show();

// Add a scrollable div to contain your content.
var $myContent = $j("<div style='overflow:auto;height:100%;padding:10px'>");
myPanel.append($myContent);

// Add listeners for selection and highlight events.
interactionGroup.addEventListener(ia.InteractionEvent.SELECTION_CHANGED, function (event)
{
    if (event.type == ia.InteractionEvent.SELECTION_CHANGED) // Selection Changed.
    {
        if (event.ids.length > 0)
        {
            var str = "";

            for (var i = 0; i < event.ids.length; i++)
            {   
                var id = event.ids[i]
                var feature = dataGroup.geography.getFeature(id);
                str += feature.name+"<br/>";
            }

            $myContent.html(str);
        }
        else $myContent.empty();
    }
});
Add a custom panel that displays indicator data for the selected features. (v671)
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 

// Add custom panel.
var myPanel = new ia.Panel("myPanelId", "Selected Feature Profile");
myPanel.setDimensions(55, 20, 15, 40); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
myPanel.closeable(true);
report.addPanel(myPanel);
myPanel.show();

// Add a scrollable div to contain your content.
var $myContent = $j("<div style='overflow:auto;height:100%;padding:10px'>");
myPanel.append($myContent);

// Listen for selection events.
interactionGroup.addEventListener(ia.ItemEvent.ITEM_CLICK, itemEventHandler);
interactionGroup.addEventListener(ia.Event.CLEAR_SELECTION, itemEventHandler);
function itemEventHandler(event)
{
    if (event.type == ia.Event.CLEAR_SELECTION) 
    {
        $myContent.empty()
    }
    else if (event.type == ia.ItemEvent.ITEM_CLICK)
    {
        if (event.item.state == "selected" || event.item.state == "rollOverSelected")
        { 
            // Get a profile for the selected features.
            $myContent.html(getFeatureProfiles(interactionGroup.getSelection()));
        }
        else if (event.item.state == "unselected")
        {
            // Get a profile for the selected features.
            $myContent.html(getFeatureProfiles(interactionGroup.getSelection()));
        }
    }
};

// Returns the profile data for the given feature ids.
function getFeatureProfiles(featureIds)
{   
    // Only get data for selected date.
    var data = dataGroup.geography.getFeatureData(featureIds, dataGroup.indicator.date);

    // Build the html using jquery.
    var str = "";
    $j.each(data.features, function(fIndex, feature)
    {   
        str += "<b>" + feature.name+ " ("+dataGroup.indicator.date+")</b>";

        $j.each(feature.themes, function(tIndex, theme)
        {
            if (theme.id == dataGroup.theme.id) // Comment this out to get all themes.
            {
                $j.each(theme.indicators, function(iIndex, indicator)
                {   
                    str += "<br/>" + indicator.name + ": <b>" + indicator.formattedValue + "</b>";
                });
            }
        });

        str += "<br/><br/>";
    });

    return str;
};  
Add a custom button that toggles a custom panel. (v671)
// Add custom button to toggle the panel off/on.
var myButton = new ia.Button("myButtonId", "Toggle Panel"); 
myButton.tooltip("Click to toggle panel");
myButton.onclick(function(e) {myPanel.toggle()});
myButton.setDimensions(55, 15, 15, 4); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(myButton);

// Add custom panel.
var myPanel = new ia.Panel("myPanelId", "My Panel");
myPanel.setDimensions(55, 20, 15, 40); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
myPanel.closeable(true);
report.addPanel(myPanel);
Add a menu which enables the user to load a different map.js and data.js without reloading the report.
// Add custom menu button to toggle the panel off/on.
var myMenuButton = new ia.MenuButton("myMenuButtonId", "Load Data"); 
myMenuButton.onclick(
function(e) 
{
    report.closePopups("myPanelId");
    myPanel.toggle();
});
myMenuButton.setDimensions(55, 15, 15, 4); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(myMenuButton);

// Add custom panel.
var myPanel = new ia.Panel("myPanelId");
myPanel.setDimensions(55, 20, 15, 40); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
myPanel.closeable(true);
myPanel.popup(true);
report.addPanel(myPanel);

// Build the data explorer
var dataExplorer = new ia.DataExplorer("myExplorerId", function(id)
{
    // When an explorer item is selected load the new data.
    var path = "";
    if (id == "louisiana") path = "louisiana";
    else if (id == "nottinghamshire") path = "nottinghamshire";

    // Loads new data.
    ia.loadData("./data/"+path+"/data.js");

    // Loads new map data.
    ia.loadMap("./data/"+path+"/map.js");

    // Close the panel on selection.
    myPanel.hide();
});

// Create a data tree for the explorer
var data = {};
data["topLevel"] = {id:"topLevel",label:"topLevel",type:"branch",children:["louisiana","nottinghamshire"]};
data["louisiana"] = {id:"louisiana",label:"Louisiana",type:"leaf",parent:"topLevel"};
data["nottinghamshire"] = {id:"nottinghamshire",label:"Nottinghamshire",type:"leaf",parent:"topLevel"};
dataExplorer.data(data);
dataExplorer.build();

// Add the data explorer to the panel.
myPanel.append(dataExplorer.container);
Change the data explorers behaviour to just show the first theme. (v671)
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// Get the data explorer.
var dataExplorer = report.getComponent("dataExplorer"); 
var showDates = false;
dataExplorer.data(dataGroup.theme.getDataTree(showDates));
dataExplorer.build(dataGroup.geography.id+"~"+dataGroup.theme.id);
Display a splash screen at startup. (v671)
// Add custom panel.
var myPanel = new ia.Panel("splashPanel");
myPanel.setDimensions(40, 40, 20, 20); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
myPanel.popup(true);
report.addPanel(myPanel);

// Add a scrollable div to contain your content.
var $myContent = $j("<div>");
myPanel.append($myContent);

// Add some html.
var str = '<div style="text-align:center;padding:30px"><img src="./logo.png"/></div>';
str += '<div style="text-align:center">Brought to you by Geowise</div>';
$myContent.html(str);

// Display the panel.
myPanel.show();
Select and zoom to a feature from a list of feature names. (v671)
// Add custom menu button to toggle the panel off/on.
var myMenuButton = new ia.MenuButton("myMenuButtonId", "Features"); 
myMenuButton.onclick(
function(e) {myPanel.toggle();});
myMenuButton.setDimensions(55, 15, 15, 4); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(myMenuButton);

// Add custom panel.
var myPanel = new ia.Panel("myPanelId");
myPanel.setDimensions(55, 20, 15, 40); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
myPanel.popup(true);
report.addPanel(myPanel);
myPanel.show();

// Add a scrollable div to contain your content.
var $myContent = $j("<div style='overflow:auto;height:100%;'>");
myPanel.append($myContent);

// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// Get the map.
var map = report.getComponent("map");

function updateList()
{
    // Clear previous list.
    $myContent.empty();

    // Create the list of feature names.
    var features = dataGroup.geography.getFeatures();
    for (var i = 0; i < features.length; i++)
    {
        var feature = features[i];
        var $div = $j("<div id='"+feature.id+"' style='padding:5px;cursor:pointer'>").html(feature.name);
        $myContent.append($div);
    }

    // Delegate click event.
    $myContent.delegate('div', ia.CLICK_TYPE, function(e)
    {
        myPanel.hide();
        var id = $j(this).attr("id");
        map.zoomToFeatureWithId(id);
        interactionGroup.select(id);
    });

    // Delegate hover event.
    $myContent.delegate('div', 'hover', function(e) 
    {
        if(e.type === 'mouseenter')
            $j(this).css("background-color", "#d9f1f7");  
        else 
            $j(this).css("background-color", "");  
    });
}
updateList();

// Update the list whenever the geography has changed.
dataGroup.addEventListener(ia.DataEvent.GEOG_CHANGED, function(event)
{
    updateList();
});
Collapse the tree in the data explorer. (v671)
// Get the data explorer component and refresh. 
var dataExplorer = report.getComponent("dataExplorer");
dataExplorer.refresh();
Use custom dropdown menus for selecting data. (v671)
Add the following css to default.css to style the dropdown buttons:
.ia-dropdown-button 
{
	background-image:url(arrow_down.png);
	background-repeat:no-repeat;
	background-position:center right;
	padding-top:10px;
	padding-bottom:10px;
	padding-left:10px;
	padding-right:30px;
	color: #666666; 
	background-color: #f7fbfd; 
	border-radius: 0px; 
	border-width: 1px; 
	border-color: #cccccc; 
}
.ia-dropdown-button:hover 
{
	background-color: #d9f1f7; 
}
.ia-dropdown-button:active 
{
	background-color: #d9f1f7; 
}

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// Variables to hold data ids.
var geogId = dataGroup.geography.id;
var themeId = dataGroup.theme.id;
var indicatorId = dataGroup.indicator.id;
var date = dataGroup.indicator.date;

// Extend the button class to create a new type of dropdown button.
ia.DropdownButton = function(id, text)
{		
	ia.DropdownButton.baseConstructor.call(this, id, text);
	this.container.addClass("ia-dropdown-button"); 
};
ia.extend(ia.Button, ia.DropdownButton);

//*********************** Geography ***********************//

// Add geog drop down button.
var geogButton = new ia.DropdownButton("geogButton", dataGroup.geography.name); 
geogButton.tooltip(dataGroup.geography.name);
geogButton.onclick(
function(e) 
{
    report.closePopups("geogPanel");
    geogPanel.toggle();
});
geogButton.setDimensions(2.5, 3.4, 23, 5); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(geogButton);

// Add geog drop down list.
var geogPanel = new ia.Panel("geogPanel");
geogPanel.setDimensions(2.5, 8.5, 23, 30); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
geogPanel.zIndex(30);
geogPanel.closeable(true);
geogPanel.popup(true);
report.addPanel(geogPanel);

// Add a scrollable div to contain the data list.
var $geogContent = $j("<div style='overflow:auto;padding:10pxheight:100%;'>");
geogPanel.append($geogContent);

// Delegate click event for geog drop down list.
$geogContent.delegate('div.geogItem', ia.CLICK_TYPE, function(e)
{
	geogPanel.hide();
	geogId = $j(this).data("id");
	updateThemeData();
});

// Delegate hover event for theme drop down list.
$geogContent.delegate('div.geogItem', 'hover', function(e) 
{
	if(e.type === 'mouseenter')  $j(this).css("background-color", "#d9f1f7");  
	else $j(this).css("background-color", "");  
});

//*********************** Theme ***********************//

// Add theme drop down button.
var themeButton = new ia.DropdownButton("themeButton", dataGroup.theme.name); 
themeButton.tooltip(dataGroup.theme.name);
themeButton.onclick(
function(e) 
{
    report.closePopups("themePanel");
    themePanel.toggle();
});
themeButton.setDimensions(26.5, 3.4, 23, 5); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(themeButton);

// Add theme drop down list.
var themePanel = new ia.Panel("themePanel");
themePanel.setDimensions(26.5, 8.5, 23, 30); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
themePanel.zIndex(30);
themePanel.closeable(true);
themePanel.popup(true);
report.addPanel(themePanel);

// Add a scrollable div to contain the data list.
var $themeContent = $j("<div style='overflow:auto;padding:10pxheight:100%;'>");
themePanel.append($themeContent);

// Delegate click event for theme drop down list.
$themeContent.delegate('div.themeItem', ia.CLICK_TYPE, function(e)
{
	themePanel.hide();
	themeId = $j(this).data("id");
	updateIndicatorData();
});

// Delegate hover event for thene drop down list.
$themeContent.delegate('div.themeItem', 'hover', function(e) 
{
	if(e.type === 'mouseenter')  $j(this).css("background-color", "#d9f1f7");  
	else $j(this).css("background-color", "");  
});

// Update theme data.
function updateThemeData()
{	
	var geog = report.data.getGeography(geogId);

	// Check if the selected indicator/date is available for the new geography/theme.
	var indicator = geog.getIndicator(indicatorId, date, true);
	if (indicator != undefined)
	{
		themeId = indicator.theme.id;
		indicatorId = indicator.id;
		date = indicator.date;
	}
	else
	{
		// If it isnt available get the first indicator.
		indicator = geog.getFirstIndicator(true);

		// Try and match the date for the new indicator
		var indicatorWithDate = geog.getIndicator(indicator.id, date, true);
		if (indicatorWithDate != undefined) 
		{
			themeId = indicatorWithDate.theme.id;
			indicatorId = indicatorWithDate.id;
			date = indicatorWithDate.date;
		}
		else
		{
			themeId = indicator.theme.id;
			indicatorId = indicator.id;
			date = indicator.date;
		}
	}

	// Update the indicator list.
	updateIndicatorData();
};

//*********************** Indicator ***********************//

// Add indicator drop down button.
var indicatorButton = new ia.DropdownButton("indicatorButton", dataGroup.indicator.name); 
indicatorButton.tooltip(dataGroup.indicator.name);
indicatorButton.onclick(
function(e) 
{
    report.closePopups("indicatorPanel");
    indicatorPanel.toggle();
});
indicatorButton.setDimensions(50.5, 3.4, 23, 5); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(indicatorButton);

// Add indicator drop down list.
var indicatorPanel = new ia.Panel("indicatorPanel");
indicatorPanel.setDimensions(50.5, 8.5, 23, 30); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
indicatorPanel.zIndex(30);
indicatorPanel.closeable(true);
indicatorPanel.popup(true);
report.addPanel(indicatorPanel);

// Add a scrollable div to contain the data list.
var $indicatorContent = $j("<div style='overflow:auto;padding:10pxheight:100%;'>");
indicatorPanel.append($indicatorContent);

// Delegate click event for indicator drop down list.
$indicatorContent.delegate('div.indicatorItem', ia.CLICK_TYPE, function(e)
{
	indicatorPanel.hide();
	indicatorId = $j(this).data("id");
	updateData();
});

// Delegate hover event for indicator drop down list.
$indicatorContent.delegate('div.indicatorItem', 'hover', function(e) 
{
	if(e.type === 'mouseenter')  $j(this).css("background-color", "#d9f1f7");  
	else $j(this).css("background-color", "");  
});

// Update indicator data.
function updateIndicatorData()
{	
	// Get the list of indicators.
	var geog = report.data.getGeography(geogId);
	var theme = geog.getTheme(themeId);

	// Check if the selected date is available for the new indicator.
	var indicator = theme.getIndicator(indicatorId, date, true);
	if (indicator != undefined)
	{
		indicatorId = indicator.id;
		date = indicator.date;
	}
	else
	{
		// If it isnt available get the first indicator.
		indicator = theme.getFirstIndicator(true);

		// Try and match the date for the new indicator
		var indicatorWithDate = theme.getIndicator(indicator.id, date, true);
		if (indicatorWithDate != undefined) 
		{
			indicatorId = indicatorWithDate.id;
			date = indicatorWithDate.date;
		}
		else
		{
			indicatorId = indicator.id;
			date = indicator.date;
		}
	}

	// Update the date list.
	updateData();
};

//*********************** Date ***********************//

// Add date drop down button.
var dateButton = new ia.DropdownButton("dateButton", dataGroup.indicator.date); 
dateButton.tooltip(dataGroup.indicator.date);
dateButton.onclick(
function(e) 
{
    report.closePopups("datePanel");
    datePanel.toggle();
});
dateButton.setDimensions(74.5, 3.4, 23, 5); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(dateButton);

// Add date drop down list.
var datePanel = new ia.Panel("datePanel");
datePanel.setDimensions(74.5, 8.5, 23, 30); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
datePanel.zIndex(30);
datePanel.closeable(true);
datePanel.popup(true);
report.addPanel(datePanel);

// Add a scrollable div to contain the data list.
var $dateContent = $j("<div style='overflow:auto;padding:10pxheight:100%;'>");
datePanel.append($dateContent);

// Delegate click event for date drop down list.
$dateContent.delegate('div.dateItem', ia.CLICK_TYPE, function(e)
{
	datePanel.hide();
	date =  $j(this).data("date");
	updateData();
});

// Delegate hover event for date drop down list.
$dateContent.delegate('div.dateItem', 'hover', function(e) 
{
if(e.type === 'mouseenter')  $j(this).css("background-color", "#d9f1f7");  
else $j(this).css("background-color", "");  
});

//*********************** Data Functions ***********************//

// Updates the data.
function updateData()
{
	// When the data is updated, the internal code will try to find a 
	// match for the selected date, otherwise it will choose the latest date.
	dataGroup.setData(geogId, indicatorId, date);
};

// This code executes every time an indicator has changed.
dataGroup.addEventListener(ia.DataEvent.INDICATOR_CHANGED, function(event)
{
	// Reset the data as it may have changed.
	geogId = event.geography.id;
	themeId = event.theme.id;
	indicatorId = event.indicator.id;
	date = event.indicator.date;

	// Update the components.
	updateComponents();
});

//*********************** Rendering ***********************//

// Updates components.
function updateComponents()
{
	var geogName = dataGroup.geography.name;
	var themeName = dataGroup.theme.name;
	var indicatorName = dataGroup.indicator.name;
	var dateName;

	// Hide the date button if theres no dates.
	if (dataGroup.indicator.date != undefined)
	{
		dateName = dataGroup.indicator.date;
		if (dateButton.visible() == false) dateButton.show();
	}
	else
	{
		if (dateButton.visible() == true) dateButton.hide();
	}

	// Update the button names.
	geogButton.text(geogName);
	themeButton.text(themeName);
	indicatorButton.text(indicatorName);
	dateButton.text(dateName); 

	// Update the button tooltips.
	geogButton.tooltip(geogName);
	themeButton.tooltip(themeName);
	indicatorButton.tooltip(indicatorName);
	dateButton.tooltip(dateName); 

	// Update dropdown lists.
	// Geographies.
	$geogContent.empty();
	var geogList = report.data.getGeographies();
	for (var i = 0; i < geogList.length; i++)
	{
		var geog = geogList[i];
		var $listItem = $j("<div id='"+geog.id+"' class='geogItem' style='padding:10pxcursor:pointer'>").html(geog.name);
		$listItem.data("id", geog.id)
		$geogContent.append($listItem);
	}

	// Themes.
	$themeContent.empty();
	var geog = report.data.getGeography(geogId)
	var themeList = geog.getThemes();
	for (var i = 0; i < themeList.length; i++)
	{
		var theme = themeList[i];
		var $listItem = $j("<div id='"+theme.id+"' class='themeItem' style='padding:10pxcursor:pointer'>").html(theme.name);
		$listItem.data("id", theme.id)
		$themeContent.append($listItem);
	}

	// Indicators.
	$indicatorContent.empty();
	var theme = geog.getTheme(themeId);
	var indicatorList = theme.getIndicators();
	var id = "";
	for (var i = 0; i < indicatorList.length; i++)
	{
		var indicator = indicatorList[i];
		if (indicator.id != id)
		{
			id = indicator.id;
			var $listItem = $j("<div id='"+indicator.id+"' class='indicatorItem' style='padding:10pxcursor:pointer'>").html(indicator.name);
			$listItem.data("id", indicator.id)
			$listItem.data("name", indicator.name)
			$indicatorContent.append($listItem);
		}
	}

	// Dates.
	$dateContent.empty();
	var dateList = theme.getIndicatorDates(indicatorId);
	if (dateList != undefined)
	{
		for (var i = 0; i < dateList.length; i++)
	    	{
			var date = dateList[i];
			var $listItem = $j("<div id='"+date+"' class='dateItem' style='padding:10pxcursor:pointer'>").html(date);
			$listItem.data("date", date)
			$dateContent.append($listItem);
		}
	}
};

// initialisation.
updateComponents();
Use a button to toggle between multiple charts layered on top of each other. (v671)
var index = 0;
var breakDownChart = report.getWidget("areaBreakdownBarChart-panel");
var timeSeries = report.getWidget("timeSeries-panel");
var barChart = report.getWidget("barChart-panel");
var featureCard = report.getWidget("featureCard-panel");
var featureLegend = report.getWidget("featureLegend-panel");

rotateCharts = function ()
{
    index++;
    if (index > 3) index = 0;

    if (index == 0)
    {
        breakDownChart.show();
        timeSeries.hide()
        barChart.hide()
        featureCard.hide()
        featureLegend.show();
    }
    else if (index == 1)
    {
        breakDownChart.hide();
        timeSeries.show()
        barChart.hide()
        featureCard.hide()
        featureLegend.show();
    }
    else if (index == 2)
    {
        breakDownChart.hide();
        timeSeries.hide();
        barChart.show();
        featureCard.hide()
        featureLegend.hide();
    }
    else if (index == 3)
    {
        breakDownChart.hide();
        timeSeries.hide();
        barChart.hide();
        featureCard.show()
        featureLegend.hide();
    }
}
Show a callout box that displays indicator data when you click on a map feature. (v671)
   
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 

// Only allow one area to be selected at a time.
interactionGroup.selectionMode = "single";

// (id, notchPosition["top-bottom","left-right","none"])
var myCallout = new ia.CalloutBox("myCallout", "top-bottom");
report.addCallout(myCallout);

// Holds the content.
var $myContent = $j("<div style='overflow:auto;max-height:300px'>");
myCallout.append($myContent);

// Add mouse listeners to the base layers.
var baseLayers = dataGroup.mapData.baseLayers;
for (var i = 0; i < baseLayers.length; i++)
{
    var layer = baseLayers[i];
    layer.addEventListener(ia.ItemEvent.ITEM_CLICK, itemEventHandler);
    layer.addEventListener(ia.ItemEvent.NONE_ITEM_CLICK, itemEventHandler);
}

// This function is executed whenever one of the above events is dispatched.
function itemEventHandler(event)
{
    if (event.type == ia.ItemEvent.NONE_ITEM_CLICK) 
    {
        // Empty the callout.
        myCallout.hide();
        $myContent.empty()
    }
    else if (event.type == ia.ItemEvent.ITEM_CLICK)
    {
        if (event.item.state == "selected" || event.item.state == "rollOverSelected")
        { 
            // Get a profile for the selected feature and display in the callout.
            $myContent.html(getFeatureProfile(event.item.id));
            myCallout.position(event.pageX, event.pageY);
            myCallout.show();
        }
        else if (event.item.state == "unselected")
        {
            // Empty the callout.
            myCallout.hide();
            $myContent.empty()
        }
    }
};

// Returns the profile data for the given feature id.
function getFeatureProfile(featureId)
{   
    // Only get data for selected date.
    var data = dataGroup.geography.getFeatureData([featureId], dataGroup.indicator.date);

    // Build the html using jquery.
    var str = "";
    $j.each(data.features, function(fIndex, feature)
    {   
        str += "<b>" + feature.name+ " ("+dataGroup.indicator.date+")</b>";

        $j.each(feature.themes, function(tIndex, theme)
        {
            if (theme.id == dataGroup.theme.id) // Comment this out to get all themes.
            {
                $j.each(theme.indicators, function(iIndex, indicator)
                {   
                    str += "<br/>" + indicator.name + ": <b>" + indicator.formattedValue + "</b>";
                });
            }
        });
    });

    return str;
};  
Add a drilldown to the map when you click or double click on a feature. (v671)
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// Add listeners to the base layers.
var baseLayers = dataGroup.mapData.baseLayers;
for (var i = 0; i < baseLayers.length; i++)
{
    var layer = baseLayers[i];
    layer.addEventListener(ia.ItemEvent.ITEM_CLICK, itemEventHandler);
}

var clicks = 0
function itemEventHandler(event)
{
    if (event.type == ia.ItemEvent.ITEM_CLICK)
    {
        // Test for double click.
        clicks++;
        if (clicks == 1)
        {
            setTimeout(function()
            {
                if (clicks == 1) alert("single click");
                else
                {
                    alert("double click");
                    
                    // Open a new page using the id of the clicked item.
                    // Replace "_self" with "_blank" to open in a new tab.
                    // var w = window.open('./' + encodeURIComponent(event.item.id) + '/atlas.html', "_self");
                }
                clicks = 0;
            }, 300);
        }
    }
};
Change the maps behaviour to zoom in / zoom out when a feature is selected / unselected. (v671)
// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 

// Get the map.
var map = report.getComponent("map");

// Only allow one area to be selected at a time.
interactionGroup.selectionMode = "single";

// Add listeners for mouse item events.
interactionGroup.addEventListener(ia.ItemEvent.ITEM_CLICK, itemEventHandler);
interactionGroup.addEventListener(ia.Event.CLEAR_SELECTION, itemEventHandler);

// This function is executed whenever one of the above events is dispatched.
function itemEventHandler(event)
{
    if (event.type == ia.Event.CLEAR_SELECTION) 
    {
        map.controller.zoomFull();
    }
    else if (event.type == ia.ItemEvent.ITEM_CLICK)
    {
        if (event.item.state == "selected" || event.item.state == "rollOverSelected")
        {
            map.zoomToFeatureWithId(event.item.id);
        }
        else if (event.item.state == "unselected")
        {
            map.controller.zoomFull();
        }
    }
};
Synchronize selection and highlighting across two maps. (v671)
// Use this so we dont get caught in a loop.
var updating = false;

var interactionGroup1 = report.getComponent("interactionGroup"); 
interactionGroup1.addEventListener(ia.InteractionEvent.SELECTION_CHANGED, interactionEventHandler1);
interactionGroup1.addEventListener(ia.InteractionEvent.HIGHLIGHT_CHANGED, interactionEventHandler1);
function interactionEventHandler1(event)
{
    if (updating == false)
    {
        updating = true;
        if (event.type == ia.InteractionEvent.SELECTION_CHANGED) 
            interactionGroup2.setSelection(event.ids);
        else if (event.type == ia.InteractionEvent.HIGHLIGHT_CHANGED) 
            interactionGroup2.setHighlight(event.ids[0]);

        updating = false;
    }
}

var interactionGroup2 = report.getComponent("interactionGroup2"); 
interactionGroup2.addEventListener(ia.InteractionEvent.SELECTION_CHANGED, interactionEventHandler2);
interactionGroup2.addEventListener(ia.InteractionEvent.HIGHLIGHT_CHANGED, interactionEventHandler2);
function interactionEventHandler2(event)
{
    if (updating == false)
    {
        updating = true;
        if (event.type == ia.InteractionEvent.SELECTION_CHANGED) 
            interactionGroup1.setSelection(event.ids);
        else if (event.type == ia.InteractionEvent.HIGHLIGHT_CHANGED) 
            interactionGroup1.setHighlight(event.ids[0]);

        updating = false;
    }
}
Toggle a contextual layer depending on the selected geography. (v671)
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// Get the map component.
var map = report.getComponent("map");

// Get the legend component.
var legend = report.getComponent("legend"); 
    
// This code executes every time the geography has changed.
dataGroup.addEventListener(ia.DataEvent.GEOG_CHANGED, function(event)
{
    var layerId = "contextualLayer1";
    var layer = map.getLayer(layerId);
    if (layer != undefined)
    {
        if (event.geography.id == "Louisiana_Regions")
        {
            layer.setVisible(false);
            legend.hideLayer(layerId);
        }
        else 
        {
            layer.setVisible(true);
            legend.showLayer(layerId);
        }
    }
});
Toggle a contextual layer depending on the selected indicator. (v671)
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 
   
// Get the map component.
var map = report.getComponent("map");

// Get the legend component.
var legend = report.getComponent("legend"); 
	    
// This code executes every time an indicator has changed.
dataGroup.addEventListener(ia.DataEvent.INDICATOR_CHANGED, function(event)
{
	var layerId = "contextualLayer1";
	var layer = map.getLayer(layerId);
	if (layer != undefined)
	{
		if (event.indicator.id == "i1" || event.indicator.id == "i2" || event.indicator.id == "i3")
		{
		    layer.setVisible(false);
		    legend.hideLayer(layerId);
		}
		else 
		{
		    layer.setVisible(true);
		    legend.showLayer(layerId);
		}
	}
});
Change the base layer according to the zoom level of the map. (v671)
// The zoom levels.
var zoomLevels = [400000, 0]; // Make sure 0 is always included.

// Get the list of geographies.
var geogs = report.data.getGeographies();

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 
    
// Add listeners for map bounding box events. Map events dont work when using google maps.
var map = report.getComponent("map");
map.addEventListener(ia.BBoxEvent.BBOX_SCALE, bBoxEventHandler);
function bBoxEventHandler(event)
{
    // The map width.
    var mapWidth = event.bBox.getWidth();

    // Loop through and test each zoom level.
    for (var i = 0; i < zoomLevels.length; i++)
    {   
        // Get the zoom level and compare it with the map width.
        var zoomLevel = zoomLevels[i];
        if (mapWidth > zoomLevel)
        {
            var geog = geogs[i];
            
            // Dont need to change geography if its already been set.
            if (dataGroup.geography.id != geog.id) dataGroup.setData(geog.id, dataGroup.indicator.id, dataGroup.indicator.date)
            
            break; // Break out of loop once correct geography has been found.
        }
    }
}
Search the feature names in all map layers for the given search term. (v671)
// Get the map.
var map = report.getComponent("map");

/**
 * This function can be attached to a map tool bar.
 * The function is then called whenever a search term is entered.
 *
 * @param searchTerm The search term entered by the user.
 * @param callbackfunction A function to call with the search results as a parameter.
 */
function featureSearch(searchTerm, callbackfunction)
{
    var layers = map.getLayers();

    // List to hold returned location items.
    var items = new Array();

    for (var i = 0; i < layers.length; i++)
    {
        var layer = layers[i];
        var features = layer.items;
        if (features != undefined)
        {
            for (var id in features)
            {
                var feature = features[id];

                // Change everything to lower case because "indexOf" is case sensitive.
                // Simply checks if the feature name starts with the search term.
                // Can be modified to do more complex searches if necessary.
                if (feature.name.toLowerCase().indexOf(searchTerm.toLowerCase()) == 0)
                {
                    // Create an item with name, geometry and bounds properties.
                    // The map will zoom to the bounds. If the bounds are undefined the map
                    // will be centred on the location.
                    var item = {};
                    item.name = feature.name;

                    // Pad the bBox.
                    var bb = feature.bBox.clone();
                    var padding = 0.2;
                    var paddingX = bb.getWidth() * padding;
                    var paddingY = bb.getHeight() * padding;

                    var cx = bb.getXCenter();
                    var cy = bb.getYCenter();
                    bb.setWidth(bb.getWidth() + (paddingX * 2));
                    bb.setHeight(bb.getHeight() + (paddingY * 2));
                    bb.setXCenter(cx);
                    bb.setYCenter(cy);

                    item.location = {x:cx, y:cy}
                    item.bounds = {xmin:bb.getXMin(), 
                            ymin:bb.getYMin(), 
                            xmax:bb.getXMax(), 
                            ymax:bb.getYMax()};

                    items[items.length] = item;
                }
            }
        }
    }
    callbackfunction.call(null, items);
};

// Attach the search function to the first map tool bar.
report.getComponent("mapTools").searchFunction = featureSearch;

// Attach the search function to the second map tool bar if it exists.
if (report.getComponent("mapTools2") != undefined) report.getComponent("mapTools2").searchFunction = featureSearch;
Carry out a single line search using the ArcGIS Server geocoding rest api. (v671)
// Get the map.
var map = report.getComponent("map");

/**
 * This function can be attached to a map tool bar.
 * The function is then called whenever a search term is entered.
 *
 * @param searchTerm The search term entered by the user.
 * @param callbackfunction A function to call with the search results as a parameter.
 */
function agsSearch(searchTerm, callbackfunction)
{
    // This is the spatial reference system for the Web Mercator projection used in the ArcGIS Online maps.
    var srs = 102100; 

    // Restrict the search to this bBox.
    var bBox = map.controller.defaultBBox; 
    var bBoxString = '{"xmin":'+bBox.getXMin()+',"ymin":'+bBox.getXMin()+',"xmax":'+bBox.getXMax()+',"ymax":'+bBox.getYMax()+',"spatialReference":{"wkid":'+srs+'}}';
    
    // Maximum nmuber of returned locations.
    var maxLocations = 4; 

    // Build the request url.
    var requestUrl = "http://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find?text="+searchTerm+"&outSR="+srs+"&bbox="+bBoxString+"&maxLocations="+maxLocations+"&f=json";

    // Send the request to the geocoding service.
    ia.File.load(requestUrl, "json", function (searchResults)
    {
        //ia.log(searchResults)

        // List to hold returned location items.
        var items = new Array();

        // Parse the search results.
        if (searchResults.locations != undefined) //  ArcGIS rest api.
        {
            var locations = searchResults.locations;
            for (var i = 0; i < locations.length; i++)
            {   
                var location = locations[i];

                // Create an item with name, geometry and bounds properties.
                // The map will zoom to the bounds. If the bounds are undefined the map
                // will be centred on the location.
                var item = {};
                item.name = location.name;

                // {x:-10010459, y:3521002}
                item.location = location.feature.geometry; 

                // {xmin:-10032723, ymin:3495284, xmax:-10010459, ymax:3521002}
                item.bounds = location.extent;

                items[items.length] = item;
            }
        }

        callbackfunction.call(null, items);
    });
};

// Attach the search function to the first map tool bar.
report.getComponent("mapTools").searchFunction = agsSearch;

// Attach the search function to the second map tool bar if it exists.
if (report.getComponent("mapTools2") != undefined) report.getComponent("mapTools2").searchFunction = agsSearch;
Carry out a single line address search using the ArcGIS Server geocoding rest api. (v671)
// Get the map.
var map = report.getComponent("map");

/**
 * This function can be attached to a map tool bar.
 * The function is then called whenever a search term is entered.
 *
 * @param searchTerm The search term entered by the user.
 * @param callbackfunction A function to call with the search results as a parameter.
 */
function agsAddressSearch(searchTerm, callbackfunction)
{
    // This is the spatial reference system for the Web Mercator projection used in the ArcGIS Online maps.
    var srs = 102100; 

    // Build the request url.
    // "myservice.com" does not exist. You need to supply your own service.
    var requestUrl = "http://myservice.com/GeocodeServer/findAddressCandidates?Single+Line+Input="+searchTerm+"&outSR="+srs+"&f=json";

    // Send the request to the geocoding service.
    ia.File.load(requestUrl, "json", function (searchResults)
    {
        // List to hold returned location items.
        var items = new Array();

        if (searchResults.candidates != undefined) // ArcGIS Server rest api.
        {
            var candidates = searchResults.candidates;
            for (var i = 0; i < candidates.length; i++)
            {   
                var candidate = candidates[i];

                var item = {};
                item.name = candidate.address;
                item.location = candidate.location;
                item.bounds = undefined;
                items[items.length] = item;
            }
        }

        callbackfunction.call(null, items);
    });
};  

// Attach the search function to the first map tool bar.
report.getComponent("mapTools").searchFunction = agsAddressSearch;

// Attach the search function to the second map tool bar if it exists.
if (report.getComponent("mapTools2") != undefined) report.getComponent("mapTools2").searchFunction = agsAddressSearch;
Disable the default touch functionality. (v671)
ia.disableDefaultTouch();
Add a google tree map that displays profile data for a selected feature. (v671)

Requires <script type="text/javascript" src="https://www.google.com/jsapi"></script> added to atlas.html. see: Google Treemaps for further information about Treemaps.

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

// The interactionGroup object exposes functions and properties
// for a group of components that interact with each other. 
var interactionGroup = report.getComponent("interactionGroup"); 

function addTreeMap()
{
    // Add a panel.
    var myPanel = new ia.Panel("treeMapPanel", "Tree Map");
    myPanel.setDimensions(25, 25, 50, 50); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
    myPanel.zIndex(30);
    myPanel.resizeable(true);
    report.addPanel(myPanel);
    myPanel.show();

    // Add a div to contain the tree.
    var $treeMap = $j("<div id='ia-treemap' style='width:100%;height:100%'>");
    myPanel.append($treeMap);

    // Create the tree map.
    var dataTable;
    var treeMap = new google.visualization.TreeMap(document.getElementById('ia-treemap'));

    // Tip.
    var tip = new ia.ChartTip($treeMap);
    var tipText = "";
    google.visualization.events.addListener(treeMap, 'onmouseover', function(e)
    {
        tipText = dataTable.getValue(e.row, 0);
        tip.show();
    });
    google.visualization.events.addListener(treeMap, 'onmouseout', function(e)
    {
        tip.hide();
    });
    $treeMap.mousemove(function(e)
    {
        var x = e.pageX - $treeMap.offset().left + 10;
        var y = e.pageY - $treeMap.offset().top - tip.getHeight();
        tip.text(tipText);
        tip.position(x, y);
    });

    // Draws the tree map.
    function drawTreeMap()
    {
        treeMap.draw(dataTable, 
        {
            minColor: '#e4f4f8',
            midColor: '#6bc1d7',
            maxColor: '#07576b',
            headerHeight: 25,
            headerColor:'#eeeeee',
            showTooltips:true,
            showScale: true,
            fontColor: '#000000',
            fontFamily: 'Verdana',
            fontSize: 10
        });
    }

    // Updates the tree map.
    function updateTreeMap()
    {
        if (interactionGroup.getSelection().length > 0)
        {
            // Get the data for the selected features
            var iaData = dataGroup.geography.getFeatureData(interactionGroup.getSelection(), dataGroup.indicator.date);

            // We need to convert this data into an array.
            var dataTableArray = new Array();

            // The first array defines the columns.
            dataTableArray.push(['Node', 'Parent', 'Size', 'Color'])

            // Only use the last selected feature.
            var feature = iaData.features[iaData.features.length-1];
            var title = dataGroup.theme.name+" in "+feature.name+" ("+dataGroup.indicator.date+")";
            dataTableArray.push([title,null,0,0])

            var displayIndicatorsWithSameDate = true;
            if (displayIndicatorsWithSameDate) // Display indicators in the theme with same date as selected indicator.
            {
                var indicators = dataGroup.theme.getIndicatorsWithDate(dataGroup.indicator.date);
                for (var i = 0; i < indicators.length; i++)
                {
                    var indicator = indicators[i];
                    if (indicator.type == "numeric")
                    {
                        var value = indicator.getValue(feature.id)
                        if (ia.isNumber(value))
                        {
                            // Add the actual data you want to display.
                            dataTableArray.push([indicator.name+": "+indicator.getFormattedValue(feature.id), title, value, value]);
                        }
                    }
                }
            }
            else // Display associates of the selected indicator.
            {
                var associates = dataGroup.indicator.getAssociates();
                for (var i = 0; i < associates.length; i++)
                {
                    var associate = associates[i];
                    if (associate.type == "numeric")
                    {
                        var value = associate.getValue(feature.id)
                        if (ia.isNumber(value))
                        {
                            // Add the actual data you want to display.
                            dataTableArray.push([associate.name+": "+associate.getFormattedValue(feature.id), title, value, value]);
                        }
                    }
                }
            }

            // Convert the array to a google data table.
            dataTable = google.visualization.arrayToDataTable(dataTableArray);
            drawTreeMap();
        }
    }
      
    // On resize redraw the tree map.
    myPanel.container.resize(function(e)
    {
        if (treeMap != undefined && dataTable != undefined) drawTreeMap();
    });

    // Listen for indicator change events.
    dataGroup.addEventListener(ia.DataEvent.INDICATOR_CHANGED, function(event)
    {
        updateTreeMap();
    });

    // Listen for feature selection events.
    interactionGroup.addEventListener(ia.InteractionEvent.SELECTION_CHANGED, function(event)
    {
        updateTreeMap();
    });
};
google.load("visualization", "1", {packages:["treemap"],"callback" : addTreeMap});
Change the geography depending on the selected indicator. (v671)
    
// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup");

// This code executes every time an indicator has changed.
dataGroup.addEventListener(ia.DataEvent.INDICATOR_CHANGED, function (event)
{
    if (event.geography.id == "Louisiana_Regions")
    {
        if (event.indicator.date == "1990" || event.indicator.date == "2000")
        {
            dataGroup.setData("Louisiana_Parishes", event.indicator.id, event.indicator.date)
        }
    }
    else if (event.geography.id == "Louisiana_Parishes")
    {
        if (event.indicator.date == "1960" || event.indicator.date == "1970" || event.indicator.date == "1980")
        {
            dataGroup.setData("Louisiana_Regions", event.indicator.id, event.indicator.date)
        }
    }
});
Define the geographies that will be displayed in the geography explorer using JSON. (v671)
// Get the geography explorer.
var geogExplorer = report.getComponent("geogExplorer");

var treeData = 
{
    "topLevel": 
    {
        "id": "topLevel",
        "label": "topLevel",
        "type": "branch",
        "children": ["Louisiana_Parishes","Louisiana_Regions"]
    },
    "Louisiana_Parishes": 
    {
        "id": "Louisiana_Parishes",
        "label": "My Louisiana Parishes",
        "type": "leaf"
    },
    "Louisiana_Regions": 
    {
        "id": "Louisiana_Regions",
        "label": "My Louisiana Regions",
        "type": "leaf"
    }
}

geogExplorer.data(treeData);
geogExplorer.build();
Load a different config.xml without reloading the report. (v672)
    
// Add custom menu button to toggle the panel off/on.
var myMenuButton = new ia.MenuButton("myMenuButtonId", "Templates");
myMenuButton.onclick(
function (e) { myPanel.toggle(); });
myMenuButton.setDimensions(55, 15, 15, 4); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor)
report.addButton(myMenuButton);

// Add custom panel.
var myPanel = new ia.Panel("myPanelId");
myPanel.setDimensions(55, 20, 15, 40); // (x%, y%, width%, height%, zIndex, xAnchor, yAnchor) 
myPanel.zIndex(30);
myPanel.popup(true);
report.addPanel(myPanel);
myPanel.show();

// Add a scrollable div to contain your content.
var $myContent = $j("<div style='overflow:auto;height:100%;'>");
myPanel.append($myContent);

// Create the list of templates.
var templates = [
    { name: 'Single Map', configs:
    [{ name: 'IA6 General', path: './configs/single/config.xml' }
    , { name: 'IA6 Large Map', path: './configs/single/config-alt.xml'}]
    }

    , { name: 'Double Geography', configs:
    [{ name: 'IA6 Standard', path: './configs/double-geog/config.xml' }
    , { name: 'IA6 Synchronised Data', path: './configs/double-geog/config-alt.xml'}]
    }

    , { name: 'Double Plot', configs:
    [{ name: 'IA6 Standard', path: './configs/double-plot/config.xml' }
    , { name: 'IA6 Synchronised Dates', path: './configs/double-plot/config-alt.xml'}]
    }
];

// Add the templates to the panel.
for (var i = 0; i < templates.length; i++)
{
var template = templates[i];
var $div = $j("<div style='padding:5px;cursor:pointer;font-weight:bold;background-color:#d9f1f7;'>").html(template.name);
$myContent.append($div);

var configs = template.configs;
for (var j = 0; j < configs.length; j++)
{
    var config = configs[j];
    var $div = $j("<div style='padding:5px;cursor:pointer' class='config'>")
    $div.data('path', config.path)
    $div.html(config.name);
    $myContent.append($div);
}
}

// Delegate click event.
$myContent.delegate('.config', ia.CLICK_TYPE, function (e)
{
myPanel.hide();
ia.loadConfig($j(this).data('path'));
});

// Delegate hover event.
$myContent.delegate('.config', 'hover', function (e)
{
if (e.type === 'mouseenter')
    $j(this).css("background-color", "#d9f1f7");
else
    $j(this).css("background-color", "");
});
Add tooltips to component tools. (v671)
    
$j('.ia-panel-resize-btn-maximize').attr('title', 'Resize');
$j('.ia-panel-export-btn').attr('title', 'Export');
$j('.ia-panel-close-btn').attr('title', 'Close');
$j('.ia-panel-settings-btn').attr('title', 'Legend Settings');
Toggle the visibility of a component. (v671)

Example function in config.xml: javascript:iaToggle(dataExplorer)

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Toggle the visibility of a component.
 *
 * @param id The component id.
 */
iaToggle = function(id)
{
    var widgetId = id+"-panel";
    report.closePopups(widgetId);

    var widget = report.getWidget(widgetId);
    if (widget != undefined) widget.toggle();
    else // May be a different sort of widget like a button.
    {
        var widget = report.getWidget(id);
        if (widget != undefined) widget.toggle();
    }
};
Toggle the visibility of a popup window. (v671)

Example function in config.xml: javascript:iaTogglePopup(./help.htm)

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Toggle the visibility of a popup window.
 *
 * @param url The url of a html file to place in the popup.
 */
iaTogglePopup = function(url)
{
    if (url.indexOf("http") == -1) url = ia.IAS_PATH + url;

    // Open in window if a touch device because scrolling isnt handled well in pop-up div.
    if (ia.IS_TOUCH_DEVICE) window.open(url, "_blank");
    else
    {
        iaToggle("popup");

        var popupContent = report.getComponent("popup");
        popupContent.setHtml(url);
    }
};

/**
 * Toggle the visibility of a component.
 *
 * @param id The component id.
 *
 * config.xml href="javascript:iaToggle(dataExplorer)"
 */
iaToggle = function(id)
{
    var widgetId = id+"-panel";
    report.closePopups(widgetId);

    var widget = report.getWidget(widgetId);
    if (widget != undefined) widget.toggle();

    else // May be a different sort of widget like a button.
    {
        var widget = report.getWidget(id);
        if (widget != undefined) widget.toggle();
    }
};
Toggle the visibility of a callout box. (v671)

Example function in config.xml: javascript:iaToggleCallout(shareCallout)

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Toggle the visibility of a callout box.
 *
 * @param id The callout id.
 * @param e The associated event.
 */
iaToggleCallout = function(id, e)
{
    ia.toggleCallout(id, e);
};
Toggle the visibility of the share callout box. (v671)

Example function in config.xml: javascript:iaToggleShare()

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Toggle the visibility of the share callout box.
 *
 * @param e The associated event.
 */
iaToggleShare = function(e) 
{
    iaToggleCallout("shareCallout", e)
};

/**
 * Toggle the visibility of a callout box.
 *
 * @param id The callout id.
 * @param e The associated event.
 */
iaToggleCallout = function(id, e)
{
    ia.toggleCallout(id, e);
};
Show a component. (v671)

Example function in config.xml: javascript:iaShow(map)

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Show a component.
 *
 * @param id The component id.
 */
iaShow = function(id)
{
    var widgetId = id+"-panel";
    report.closePopups(widgetId);

    var widget = report.getWidget(widgetId);
    if (widget != undefined) widget.show();
    else // May be a different sort of widget like a button.
    {
        var widget = report.getWidget(id);
        if (widget != undefined) widget.show();
    }
};
Hide a component. (v671)

Example function in config.xml: javascript:iaHide(map)

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Hide a component.
 *
 * @param id The component id.
 */
iaHide = function(id)
{
    var widgetId = id+"-panel";
    report.closePopups(widgetId);

    var widget = report.getWidget(widgetId);
    if (widget != undefined) widget.hide();
    else // May be a different sort of widget like a button.
    {
        var widget = report.getWidget(id);
        if (widget != undefined) widget.hide();
    }
};
Resize a component. (v671)

Example function in config.xml: javascript:iaResize(map,50,60)

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Resize a component.
 *
 * @param id The component id.
 * @param w The new width of the component in % of the full report width.
 * @param h The new height of the component in % of the full report height.
 */
iaResize = function(id)
{
    var widgetId = id+"-panel";
    report.closePopups(widgetId);

    var widget = report.getWidget(widgetId);
    if (widget != undefined) widget.setSize(w, h);
    else // May be a different sort of widget like a button.
    {
        var widget = report.getWidget(id);
        if (widget != undefined) widget.setSize(w, h);
    }
};
Expand / Collapse the profile tree. (v671)

Example function in config.xml: javascript:iaToggleProfileTree()

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Expand / Collapse profile tree.
 */
iaToggleProfileTree = function() 
{
    var profile = report.getComponent("spineChart");
    profile.toggleTree();
};
Open the print preview window. (v671)

Example function in config.xml: javascript:iaOpenPrintPreview()

This function is already implemented in the IA codebase. You can use this as a starting point for similar code.

/**
 * Open the print preview window.
 */     
iaOpenPrintPreview = function() 
{
    window.open(ia.getUrl(), "_blank");
};
Load a new data.js and map.js file without reloading the report. (v671)

Example function in config.xml: javascript:iaSetData('../data/')

/**
 * Load a new data.js and map.js file.
 *
 * @param path The directory containing the data files.
 */
iaSetData = function(path)
{
    ia.loadData(path+"data.js");
    ia.loadMap(path+"map.js");
};
Change the indicator. (v671)

Example function in config.xml: javascript:iaSetIndicator('States','i32',2006)

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

/**
 * Change the indicator.
 *
 * @param geographyId The geography id.
 * @param indicatorId The indicator id.
 * @param date An optional data.
 */
iaSetIndicator = function(geographyId, indicatorId, date)
{
    dataGroup.setData(geographyId, indicatorId, date);
};
Set a new filter. (v671)

Example function in config.xml: javascript:iaSetFilter('filter5','West South Central')

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

/**
 * Set a new filter.
 *
 * @param filterId The filter id.
 * @param filterValue The filter value.
 */
iaSetFilter = function(filterId, filterValue)
{
    dataGroup.setFilter(filterId, filterValue);
};
Clear the filter. (v671)

Example function in config.xml: javascript:iaClearFilter()

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

/**
 * Clears the filter.
 */
iaClearFilter = function()
{
    dataGroup.clearFilter();
};
Zoom in to the map. (v671)

Example function in config.xml: javascript:iaZoomIn()

var map = report.getComponent("map");

/**
 * Zoom in to the map.
 */
iaZoomIn = function() 
{
    map.controller.zoomIn()
};
Zoom out of the map. (v671)

Example function in config.xml: javascript:iaZoomOut()

var map = report.getComponent("map");

/**
 * Zoom out of the map.
 */
iaZoomOut = function() 
{
    map.controller.zoomOut()
};
Zoom the map to full extents. (v671)

Example function in config.xml: javascript:iaZoomFull()

var map = report.getComponent("map");

/**
 * Zoom the map to full extents.
 */
iaZoomFull = function() 
{
    map.controller.zoomFull()
};
Zoom to a map bounding box. (v671)

Example function in config.xml: javascript:iaZoomToBBox(-14206538,2696945,-7133550,6511566)

var map = report.getComponent("map");

/**
 * Zoom to a map bounding box.
 *
 * @param xMin The x-coord of the bottom-left corner.
 * @param yMin The y-coord of the bottom-left corner. 
 * @param xMax The x-coord of the top-right corner. 
 * @param yMax The y-coord of the top-right corner. 
 */
iaZoomToBBox = function(xMin, yMin, xMax, yMax) 
{
    map.controller.zoomToBBox(new ia.BoundingBox(xMin, yMin, xMax, yMax));
};
Zoom to a feature. (v671)

Example function in config.xml: javascript:iaZoomToFeature('EH122RB')

var map = report.getComponent("map");

/**
 * Zoom to feature example.
 *
 * @param featureId The feature id.
 */
iaZoomToFeature = function(featureId) 
{
    map.zoomToFeatureWithId(featureId);
};
Open notes for the selected indicator. (v671)

Example function in config.xml: javascript:iaOpenNotesPage()

// The dataGroup object exposes functions and properties of the data. 
var dataGroup = report.getComponent("dataGroup"); 

/**
 * Open notes for the selected indicator.
 */
iaOpenNotesPage = function()
{ 
    window.open(dataGroup.indicator.href, "_blank");
};