Show:

File: ia\ui\MapTools.js

/**
 * <code>ia.MapTools</code> is a set of map tools that can be attached to a map.
 *
 * @author J Clare
 * @class ia.MapTools
 * @constructor
 * @param {ia.Map} map The associated map object.
 * @param {ia.DataGroup} dataGroup The associated data group.
 * @param {ia.InteractionGroup} interactionGroup The associated interaction group.
 * @param {Boolean} googleMaps Indicates if google maps is being used.
 * @param {Boolean} includeSearchTool Indicates if the search tool is included.
 */
ia.MapTools = function(map, dataGroup, interactionGroup, googleMaps, includeSearchTool)
{
	var me = this;

	me._clearBtn = undefined;
	me._filterBtn = undefined;
	me._map = map;
	me._useGoogleMaps = googleMaps;
	me._includeSearchTool = includeSearchTool;
	me._searching = false;
	me._interactionGroup = interactionGroup;
	me._dataGroup = dataGroup;

	// Create Load a marker for search results.
	me._marker = new Image();
	me._marker.src = "./map_tool_search.png";

	// Create the container element.
	me.container = $j('<div class="ia-map-toolbar"></div>');

	// Listen for the selection changing.
	interactionGroup.addEventListener(ia.InteractionEvent.SELECTION_CHANGED, this._updateToolbar.bind(this));

	// Listen for the filter changing.
	dataGroup.addEventListener(ia.FilterEvent.FILTER_CHANGED, this._updateToolbar.bind(this));
};

/** 
 * Updates the tool bar.
 * 
 * @property updateToolbar
 * @private
 */
ia.MapTools.prototype._updateToolbar = function() 
{
	if (this._interactionGroup.getSelection().length > 0) 
	{
		if (this._clearBtn) 
			this._clearBtn.removeClass('ia-cross-btn-disabled ia-toolbar-text-btn-disabled').addClass('ia-list-item ia-cross-btn');
		if (this._filterBtn) 
			this._filterBtn.removeClass('ia-cross-btn ia-toolbar-text-btn-disabled').addClass('ia-list-item ia-cross-btn-disabled');
	}
	else
	{
		if (this._clearBtn) 
			this._clearBtn.removeClass('ia-list-item ia-cross-btn').addClass('ia-cross-btn-disabled ia-toolbar-text-btn-disabled');
		if (this._filterBtn)
		{
			if (this._dataGroup.getFilteredFeatures().length > 0)  
				this._filterBtn.removeClass('ia-cross-btn-disabled ia-toolbar-text-btn-disabled').addClass('ia-list-item ia-cross-btn');
			else 
				this._filterBtn.removeClass('ia-list-item ia-cross-btn').addClass('ia-cross-btn-disabled ia-toolbar-text-btn-disabled');
		}
	}
};

/**
 * The container that holds the object.
 * 
 * @property container
 * @type JQUERY Element
 */
ia.MapTools.prototype.container;

/** 
 * Allows a custom function to be set for when the filter button is pressed.
 * 
 * @property filterFunction
 * @type Function
 */
ia.MapTools.prototype.filterFunction = function() {};

/** 
 * Allows a custom function to be set for when the clear button is pressed.
 * 
 * @property filterFunction
 * @type Function
 */
ia.MapTools.prototype.clearFunction = function() {};

/**
 * Default function carries out a single search using the ArcGIS Server geocoding rest api.
 * Override this function to use a different geogode service.
 *
 * @param searchTerm The search term entered by the user.
 * @param callbackfunction A function to call with the search results as a parameter.
 */
ia.MapTools.prototype.searchFunction = function(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 = this._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;
				item.location = location.feature.geometry; // {x:-10010459, y:3521002}
				item.bounds = location.extent; // {xmin:-10032723, ymin:3495284, xmax:-10010459, ymax:3521002}
				items[items.length] = item;
			}
		}

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

/**
 * The text for the clear button.
 * 
 * @property clearButtonText
 * @type String
 */
ia.MapTools.prototype.clearButtonText;

/**
 *  The text for the filter button.
 * 
 * @property filterButtonText
 * @type String
 */	
ia.MapTools.prototype.filterButtonText;

/** 
 * Render the toolbar.
 *
 * @method render
 */
ia.MapTools.prototype.render = function() 
{
	this.container.empty();
	
	var me = this;
	if (!ia.IS_TOUCH_DEVICE)
	{
		var overToolbar = false;
		this._map.container.mouseenter(function(e) 
		{
			if (!overToolbar)
			{
				me.container.stop();
				me.container.css({visibility: "visible"}).animate({opacity: 1.0});
			}
		});
		this._map.container.mouseleave(function(e) 
		{
			me.container.stop();
			me.container.animate({opacity: 0}, function() 
			{
				me.container.css({visibility: "hidden"});
			});
			overToolbar = false;
		});
		this.container.mouseenter(function(e) 
		{
			overToolbar = true;
			me.container.stop();
			me.container.animate({opacity: 1.0});
		});
		this.container.mouseleave(function(e) 
		{
			overToolbar = false;
			me.container.stop();
			me.container.animate({opacity: 1.0});
		});
	}
	else 
	{
		var toolbarTimeout;
		this.container.bind("touchstart", function(e) 
		{
			me.container.stop();
			me.container.css({visibility: "visible"}).animate({opacity: 1.0});
			
			clearTimeout(toolbarTimeout);
			toolbarTimeout = setTimeout(function()
			{
				clearTimeout(toolbarTimeout);
				me.container.stop();

				if (!me._searching)
				{
					me.container.animate({opacity: 0}, function() 
					{
						me.container.css({visibility: "hidden"});
					});
				}
			}, 5000);
		});
		this._map.container.bind("touchstart", function(e) 
		{
			me._searching = false;

			me.container.stop();
			me.container.css({visibility: "visible"}).animate({opacity: 1.0});
			
			clearTimeout(toolbarTimeout);
			toolbarTimeout = setTimeout(function()
			{
				clearTimeout(toolbarTimeout);
				me.container.stop();

				if (!me._searching)
				{
					me.container.animate({opacity: 0}, function() 
					{
						me.container.css({visibility: "hidden"});
					});
				}
			}, 5000);
		});
	}

	// Add zoom full button 
	var zoomFull = $j('<div class="ia-toolbar-btn ia-list-item ia-zoomfull-btn"></div>');
	this.container.append(zoomFull);
	zoomFull.bind(ia.CLICK_TYPE, function(e)  
	{
		e.stopPropagation();
		e.preventDefault();
		me._map.controller.zoomFull();
	});
	
	// Add zoom out button 
	var zoomOut = $j('<div class="ia-toolbar-btn ia-list-item ia-zoomout-btn"></div>');
	this.container.append(zoomOut);
	zoomOut.bind(ia.CLICK_TYPE, function(e)  
	{
		e.stopPropagation();
		e.preventDefault();
		if (me._useGoogleMaps)
			me._map.gMap.setZoom(me._map.gMap.getZoom()-1);
		else
			me._map.controller.zoomOut();
	});
	
	// Add zoom in button 
	var zoomIn = $j('<div class="ia-toolbar-btn ia-list-item ia-zoomin-btn"></div>');
	this.container.append(zoomIn);
	zoomIn.bind(ia.CLICK_TYPE, function(e)  
	{
		e.stopPropagation();
		e.preventDefault();
		if (me._useGoogleMaps)
			me._map.gMap.setZoom(me._map.gMap.getZoom()+1);
		else
			me._map.controller.zoomIn();
	});

	// Add search button 
	var searchTool;
	if (this._includeSearchTool)
	{
		searchTool = $j('<div class="ia-toolbar-btn ia-list-item ia-search-btn"></div>');
		me.container.append(searchTool);
	}
	
	// Add clear selection button
	if (this.clearButtonText)
	{
		me._clearBtn = $j("<div class='ia-toolbar-text-btn ia-list-item ia-toolbar-text-btn-disabled ia-cross-btn-disabled'>").html(me.clearButtonText);
		me.container.append(me._clearBtn);
		me._clearBtn.bind(ia.CLICK_TYPE, function(e)  
		{
			e.stopPropagation();
			e.preventDefault();
			me.clearFunction();
		});
	}
	
	// Add filter button 
	if (this.filterButtonText)
	{
		this._filterBtn = $j("<div class='ia-toolbar-text-btn ia-list-item ia-toolbar-text-btn-disabled ia-cross-btn-disabled'>").html(this.filterButtonText);
		this.container.append(this._filterBtn);
		this._filterBtn.bind(ia.CLICK_TYPE, function(e)  
		{
			e.stopPropagation();
			e.preventDefault();
			me.filterFunction();
		});
	}

	if (this._includeSearchTool)
	{
		if (this._useGoogleMaps)
		{
			var uiWidget = $j("<div id='ia-search-holder-"+this._map.id+"' class='ui-widget'>");
			var searchWidget = $j("<input id='ia-search-"+this._map.id+"' class='ia-search-input'>");
			uiWidget.append(searchWidget);
			this.container.append(uiWidget);
			uiWidget.hide();

			// Add search click 
			var firstUse = true;
			var geocoder = new google.maps.Geocoder();
			var marker;

			searchTool.bind(ia.CLICK_TYPE, function(e)  
			{
				me._searching = true;

				e.stopPropagation();
				e.preventDefault();
				uiWidget.toggle();

				if (firstUse)
				{
					firstUse = false;
					searchWidget.autocomplete(
			        {
			            source: function(request, response) 
			            {
							var address = request.term;
							geocoder.geocode(
							{
								'address': address,
		      					'bounds':  me._map.defaultBounds
							}, 
							function(results, status) 
							{
								if (status === google.maps.GeocoderStatus.OK) 
								{
									// The bounding box filter only biases the results
									// it could include results outside the bbox 
									// so check if the bounding box of each item intercepts the default bbox.
									var filteredResults = []
									for (var id in results)
									{
										var item = results[id];
										if (item.geometry.bounds)
										{
											if (me._map.defaultBounds.intersects(item.geometry.bounds)) 
												filteredResults[filteredResults.length] = results[id];
										}
									}

									response( $j.map( filteredResults, function( item ) {
			                        return {
					                                label: item.formatted_address,
					                                value: item.formatted_address,
					                                location: item.geometry.location,
					                                bounds: item.geometry.bounds
			                        }
			                		}));
								} 
							});
			            },
			            minLength: 2,
			            select: function( event, ui ) 
			            {
							me._map.gMap.fitBounds(ui.item.bounds);
							if (marker) marker.setMap(null);
							marker = new google.maps.Marker(
							{
								map: me._map.gMap,
								position: ui.item.location
							});

							uiWidget.toggle();


			            },
			            open: function() 
			            {
			                //$(this).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
			            },
			            close: function() 
			            {
			                //$(this).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
			            },
			            appendTo: "#ia-search-holder-"+me._map.id+""
			        });
				}

				searchWidget.focus();
				searchWidget.val([])
	 			searchWidget.autocomplete("close");
			});
		}
		else
		{
			var uiWidget = $j("<div id='ia-search-holder-"+this._map.id+"' class='ui-widget'>");
			var searchWidget = $j("<input id='ia-search-"+this._map.id+"' class='ia-search-input'>");
			uiWidget.append(searchWidget);
			this.container.append(uiWidget);
			uiWidget.hide();

			// Add search click 
			var firstUse = true;
			var marker;

			searchTool.bind(ia.CLICK_TYPE, function(e)  
			{
				me._searching = true;

				// Clear markers.
			    me._map.markerLayer.clearMarkers();

				e.stopPropagation();
				e.preventDefault();
				uiWidget.toggle();

				if (firstUse)
				{
					firstUse = false;
					searchWidget.autocomplete(
			        {
			            source: function( request, response ) 
			            {
		            		me.searchFunction(request.term, function(results)
	            			{
								response($j.map(results, function( item ) {
		                        return {
				                                label: item.name,
				                                value: item.name,
				                                location: item.location,
				                                bounds: item.bounds
		                        }
		                		}));
	            			});
			            },
			            minLength: 2,
			            select: function( event, ui ) 
			            {
			            	var bb = ui.item.bounds;
			            	var location = ui.item.location;

			            	if (bb !== undefined) me._map.controller.zoomToBBox(new ia.BoundingBox(bb.xmin,bb.ymin,bb.xmax,bb.ymax));
			            	else if (location !== undefined) me._map.controller.centerOnCoords(location.x, location.y);

							// Draw a marker.
							if (location !== undefined)
							{
				            	me._map.markerLayer.clearMarkers();
				            	me._map.markerLayer.addMarker(me._marker, location.x, location.y);
				            	me._map.markerLayer.render();
				            }

							uiWidget.toggle();

							me.container.animate({opacity: 0}, function() 
							{
								me.container.css({visibility: "hidden"});
							});
			            },
			            open: function() 
			            {
			                //$(this).removeClass( "ui-corner-all" ).addClass( "ui-corner-top" );
			            },
			            close: function() 
			            {
			                //$(this).removeClass( "ui-corner-top" ).addClass( "ui-corner-all" );
			            },
			            appendTo: "#ia-search-holder-"+me._map.id+""
			        });
				}

				searchWidget.focus();
				searchWidget.val([])
	 			searchWidget.autocomplete("close");
			});
		}
	}

	this._updateToolbar();
}