Show:

File: ia\data\MapData.js

/** 
 * Contains information about a map file which has been published 
 * through the InstantAtlas publisher.
 *
 * @author J Clare
 * @class ia.MapData
 * @extends ia.EventDispatcher
 * @constructor
 */
ia.MapData = function()
{		
	ia.MapData.baseConstructor.call(this);
	
	this._layerCount = -1;
	this._visibleLayers = new Array();
	this._callbackFnc = undefined;
	this._layerHash = new Object();

	this.tilePath = "./";
	this.useGoogleMaps = false;
	this.path = "";
};
ia.extend(ia.EventDispatcher, ia.MapData);

/** 
 * The template number.
 *
 * @property template
 * @type String
 */
ia.MapData.prototype.template;

/** 
 * The version number.
 *
 * @property version
 * @type String
 */
ia.MapData.prototype.version;

/** 
 * The maps bounding box.
 *
 * @property mapBBox
 * @type ia.BoundingBox
 */
ia.MapData.prototype.mapBBox;

/** 
 * All layers.
 *
 * @property layers
 * @type ia.LayerBase[]
 */
ia.MapData.prototype.layers;

/** 
 * Base layers.
 *
 * @property baseLayers
 * @type ia.LayerBase[]
 */
ia.MapData.prototype.baseLayers;

/** 
 * The current base layer.
 *
 * @property baseLayer
 * @type ia.LayerBase
 */
ia.MapData.prototype.baseLayer;

/** 
 * None Base layers.
 *
 * @property noneBaseLayers
 * @type ia.LayerBase[]
 */
ia.MapData.prototype.noneBaseLayers;

/** 
 * Icon layers.
 *
 * @property iconLayers
 * @type ia.LayerBase[]
 */
ia.MapData.prototype.iconLayers;

/** 
 * The path to tiles for tile layers.
 *
 * @property tilePath
 * @type String
 */
ia.MapData.prototype.tilePath;

/** 
 * Set to true if using google maps.
 *
 * @property useGoogleMaps
 * @type Boolean
 * @default false
 */
ia.MapData.prototype.useGoogleMaps;

/** 
 * The google map type.
 *
 * @property googleMapType
 * @type String
 */
ia.MapData.prototype.googleMapType;

/** 
 * The google map api key.
 *
 * @property googleApiKey
 * @type String
 */
ia.MapData.prototype.googleApiKey;
	
/** 
 * The url of the data source.
 *
 * @property url
 * @type String
 */
ia.MapData.prototype.url;

/** 
 * The directory path to the data source.
 *
 * @property path
 * @type String
 * @default ""
 */
ia.MapData.prototype.path;

/** 
 * Loads and parses the source file then calls the given function with the ReportConfig object
 * as the first parameter.
 *
 * @method parseData
 * @param {String} url The url to the data. 
 * @param {Function} callbackFunction The call back function. 
 */
ia.MapData.prototype.loadSource = function(url, callbackFunction) 
{
	var me = this;
	this.url = url;
	this.path = ia.File.getFileDirectory(url);

	ia.File.load(
	{
		url: url,
		dataType: "json", 
		onSuccess:function(json)
		{
			me.parseData(json, callbackFunction);
		}
	});
};

/** 
 * Returns the layer that corresponds to the id.
 * 
 * @method getLayer
 * @param {String} id The layer id.
 * @return {ia.LayerBase} The layer for the given id.
 */
ia.MapData.prototype.getLayer = function(id) 
{
	return this._layerHash[id];
};

/** 
 * Updates the data.
 *
 * @method parseData
 * @param {JSON} data The raw data. 
 * @param {Function} callbackFunction The call back function. 
 */
ia.MapData.prototype.parseData = function(data, callbackFunction)
{
	this._layerCount = -1;
	this.useGoogleMaps = false;
	this._callbackFnc = callbackFunction;

	// delete any previous layers
	for (var id in this._layerHash) 
	{
		delete this._layerHash[id];
	};

	this._visibleLayers = new Array();
	this.layers = new Array();
	this.baseLayers = new Array();
	this.noneBaseLayers = new Array(); // Image and contextual.
	
	var imageLayers = new Array();
	var referenceLayers = new Array();
	var pointLayers = new Array();
	var lineLayers = new Array();
	var polygonLayers = new Array();
	
	this._layerHash = new Object();
	
	// Map properties.
	if (data.template !== undefined) this.template = data.template;
	if (data.version !== undefined) this.version = data.version;
	if (data.boundingBox !== undefined) 
	{
		var bb = data.boundingBox.split(" ");
		this.mapBBox = new ia.BoundingBox(parseFloat(bb[0]),
					parseFloat(bb[1]),
					parseFloat(bb[2]),
					parseFloat(bb[3]));  
	}
	
	// Layers.
	var layers = data.layers;
	if (layers !== undefined) 
	{				
		// Check for google layer first.
		var n = layers.length;
		for (var i = 0; i < n; i++) 
		{ 
			var layerData = layers[i];
			if (layerData.type === "google-layer" && navigator.onLine) 
			{
				this.useGoogleMaps = true;
				this.googleMapType = layerData.mapType;
				this.googleApiKey =  layerData.apiKey;
			}
		}
		
		for (var i = 0; i < n; i++) 
		{ 
			var layerData = layers[i];				

			// Ignore background layers when using google maps.
			if (layerData.geometry === "image" && this.useGoogleMaps === false)
			{
				var layer;

				if (layerData.type === "tile-layer")
				{
					var layer = new ia.TileLayer(this.path+layerData.url);
					layer.path = this.tilePath;
					this._parseLayerProperties(layerData, layer);
				}
				else if (layerData.type === "ags-layer" && navigator.onLine)
				{
					var layer = new ia.AGSLayer();
					this._parseLayerProperties(layerData, layer);
				}
				else if (layerData.type === "wms-layer" && navigator.onLine)
				{
					var layer = new ia.WMSLayer();
					this._parseLayerProperties(layerData, layer);
				}
					
				if (layerData.isReference) referenceLayers[referenceLayers.length] = layer;
				else imageLayers[imageLayers.length] = layer;

			}
			if (layerData.geometry !== "image")
			{
				var layer;
				var isFeatureServiceLayer = (layerData.idField !== undefined);

				if (layerData.type === "base-layer")
				{
					if (isFeatureServiceLayer)
						layer = new ia.FeatureServiceLayer(layerData.url);
					else
						layer = new ia.FeatureLayer(this.path+layerData.url);
					this.baseLayers[this.baseLayers.length] = layer;
					
					// Make first base layer the active layer.
					if (this.baseLayers.length === 1) this.baseLayer = layer;
				}
				else if (layerData.type === "contextual-layer")
				{
					if (isFeatureServiceLayer)
						layer = new ia.FeatureServiceLayer(layerData.url);
					else
						layer = new ia.FeatureLayer(this.path+layerData.url);
				}
				else if (layerData.type === "rss-layer")
				{
					layer = new ia.GeoRSSLayer(layerData.url);
				}

				this._parseLayerProperties(layerData, layer);
				
				// Remove extra base layers from visible layers list 
				// so theyre not loaded at startup. And set to invisible.
				if (layerData.type === "base-layer" && this.baseLayers.length > 1) 
				{
					var layer = this._visibleLayers.pop();

					// This was originally commented out but it caused a bug
					// where if the second base layer was point data you couldnt
					// select the first base layer in the map.
					layer.setVisible(false);
				}
				
				if (layerData.type !== "base-layer")
				{
					if (layer.geometry === "point") pointLayers[pointLayers.length] = layer;
					else if (layer.geometry === "line") lineLayers[lineLayers.length] = layer;
					else if (layer.geometry === "polygon") polygonLayers[polygonLayers.length] = layer;
				}

				this._layerHash[layer.id] = layer;
			}
		}
		
		// None base layers.
		this.noneBaseLayers = imageLayers.concat(polygonLayers)
					.concat(lineLayers)
					.concat(pointLayers)
					.concat(referenceLayers);
		
		// Add the base layers in the correct position.
		for (var i = 0; i < this.baseLayers.length; i++)  
		{
			var layer = this.baseLayers[i];
			if (layer.geometry === "point") pointLayers.unshift(layer);
			else if (layer.geometry === "line") lineLayers.unshift(layer);
			else if (layer.geometry === "polygon") polygonLayers.unshift(layer);
		}
		
		this.layers = imageLayers.concat(polygonLayers)
				.concat(lineLayers)
				.concat(pointLayers)
				.concat(referenceLayers);
	}	

	if (this.useGoogleMaps && ia.googleMapsLoaded === false)
	{
		var script = document.createElement("script");
		script.type = "text/javascript";
		
		if (this.googleApiKey !== "")
			script.src = "http://maps.googleapis.com/maps/api/js?key="+this.googleApiKey+"&sensor=false&callback=ia.initGoogleMaps";
		else
			script.src = "http://maps.google.com/maps/api/js?sensor=false&callback=ia.initGoogleMaps";
			
		document.body.appendChild(script);
	}
	else this.loadVisibleLayers();
};

/** 
 * Parses layer properties.
 *
 * @method _parseLayerProperties
 * @param {JSON} data The raw data. 
 * @param {ia.LayerBase} layer The layer. 
 * @private
 */
ia.MapData.prototype._parseLayerProperties = function(data, layer)
{
	layer.id = data.id;
	layer.name = data.name; 
	layer.showInLayerList = data.showInLayerList; 
	
	// Visibility
	if (data.visible !== undefined) 
	{
		layer.setVisible(data.visible);

		// Base layer is included whether its visible or not so that we can read in whether its an evaluation version.
		if (data.visible === true || data.type === "base-layer") this._visibleLayers[this._visibleLayers.length] = layer;
	}	

	// Feature layers
	if (data.minLabelExtent !== undefined) layer.minLabelExtent = data.minLabelExtent;  
	if (data.maxLabelExtent !== undefined) layer.maxLabelExtent = data.maxLabelExtent;  
	if (data.showLabels !== undefined) layer.showLabels = data.showLabels;  
	if (data.showDataTips !== undefined) layer.showDataTips = data.showDataTips;  
	if (data.iconPath !== undefined && data.iconPath !== "") 
	{
		layer.iconPath = data.iconPath;  
		if (layer.iconPath.indexOf("http") === -1 && layer.iconPath.indexOf("javascript") === -1)
			layer.iconPath = ia.IAS_PATH + layer.iconPath;
	}

	// AGOL FeatureServer layers.
	if (data.idField !== undefined) layer.idField = data.idField;  
	if (data.nameField !== undefined) layer.nameField = data.nameField;  
	if (data.srs !== undefined) layer.srs = data.srs;  
	if (data.featureIds !== undefined) layer.featureIds = data.featureIds; 
	if (data.objectIds !== undefined) layer.objectIds = data.objectIds;   
	if (data.boundingBox !== undefined) 
	{
		var bb = data.boundingBox.split(" ");
		layer.bBox = new ia.BoundingBox(parseFloat(bb[0]),
					parseFloat(bb[1]),
					parseFloat(bb[2]),
					parseFloat(bb[3])); 
	}

	// Styles
	layer.geometry = data.geometry; 
	if (data.geometry !== "image")
	{	
		var style = layer.style;
		if (data.symbolSize !== undefined) layer.symbolSize = data.symbolSize;
		if (data.fillColor !== undefined) 
		{
			// Convert to rgba.
			style.fillStyle = ia.Color.toRGBA(data.fillColor, data.fillOpacity);
		}
		if (data.borderThickness !== undefined) style.lineWidth = data.borderThickness;
		if (data.borderColor !== undefined) 
		{
			// Convert to rgba.
			var alpha = 1;
			if (style.lineWidth === 0) alpha = 0
			style.strokeStyle = ia.Color.toRGBA(data.borderColor, alpha);
		}
		layer.style = style;
	}	
	
	// WMS / AGS layers.
	if (data.url !== undefined) layer.url = data.url;  
	if (data.layers !== undefined) layer.layers = data.layers;  
	if (data.srs !== undefined) layer.srs = data.srs;  
	if (data.version !== undefined) layer.version = data.version;  
	if (data.params !== undefined) layer.params = data.params;  
	if (data.requiresAxisSwitch !== undefined) layer.requiresAxisSwitch = data.requiresAxisSwitch;  
	
	// Tile layers
	if (data.minExtent !== undefined) layer.minExtent = data.minExtent;  
	if (data.maxExtent !== undefined) layer.maxExtent = data.maxExtent;  	
};

/** 
 * Loads the visible data layers.
 *
 * @method loadVisibleLayers
 */
ia.MapData.prototype.loadVisibleLayers = function()
{
	this._layerCount++;
	var me = this;

	// Ensures all layers are loaded before moving on.
	if (this._visibleLayers.length > this._layerCount)
	{
		var layer = this._visibleLayers[this._layerCount];
		layer.addEventListener(ia.Event.LAYER_READY, function ()
		{
			me.loadVisibleLayers();
		});
		layer.loadSource();
	}
	else
	{
		// callback function
		this._callbackFnc.call(null, this);
		me.dispatchEvent(new ia.DataEvent(ia.DataEvent.MAP_DATA_CHANGED, me));
	}
};