Show:

File: ia\ui\LegendEditor.js

/**
 * An editor for thematics.
 *
 * @author J Clare
 * @class ia.LegendEditor
 * @constructor
 * @param {ia.Thematic} thm The theme
 * @param {ia.ReportCnofig} config The report config. 
 * @param {Object} legendSettings The legend settings. 
 */
ia.LegendEditor = function(thm, config, legendSettings)
{
	var me = this;

	this.showLegendTypePanel = true;
	this.showLegendTools = true;
	this.showPalettePanel = true;
	this.showSizePanel = true;

	this._updateTimeout = undefined;
	this._lockEditor = false;
	this._isVisible = false;
	this._thematic = thm;
	this._thematic.addEventListener(ia.Event.THEME_CHANGED,function() {me.render()});
	this._reportConfig = config;
	this._settings = legendSettings;
	
	// Create the container element.
	this.container = $j('<div class="ia-editor"></div>');
	$j("body").bind(ia.CLICK_TYPE, function(e) 
	{
		me.hide();
	});
	this.container.bind(ia.CLICK_TYPE, function(e) 
	{
		e.stopPropagation();
	});

	// Initialise.
	me.render();
};
	
/**
 * The container that holds the object.
 * 
 * @property container
 * @type JQUERY Element
 */
ia.LegendEditor.prototype.container;

/**
 * Display the legend type panel?
 * 
 * @property showLegendTypePanel
 * @type Boolean
 * @default true
 */
ia.LegendEditor.prototype.showLegendTypePanel;

/**
 * Display the legend tools panel?
 * 
 * @property showLegendTools
 * @type Boolean
 * @default true
 */
ia.LegendEditor.prototype.showLegendTools;

/**
 * Display the palette panel?
 * 
 * @property showPalettePanel
 * @type Boolean
 * @default true
 */
ia.LegendEditor.prototype.showPalettePanel;

/**
 * Display the size panel?
 * 
 * @property showSizePanel
 * @type Boolean
 * @default true
 */
ia.LegendEditor.prototype.showSizePanel;

/** 
 * Render the legend editor after changes.
 *
 * @method render
 */
ia.LegendEditor.prototype.render = function() 
{
	var me = this;
	this.container.empty();
	
	// Holds the menu.
	var menu = $j("<div>");
	this.container.append(menu);
	
	var nClassifier = this._thematic.numericClassifier;
	var cClassifier = this._thematic.categoricClassifier;
	var paletteConfig = this._reportConfig.getMapPalette();

	if (this._thematic.getDataType() === ia.Thematic.CATEGORIC) // Categoric.	
	{
		if (this.showPalettePanel)
		{
			// Palette Panel.
			var $paletteTable = $j("<table class='ia-editor-panel ia-editor-palette-panel'>");
			menu.append($paletteTable);

			var $paletteTableRow = $j("<tr>");
			$paletteTable.append($paletteTableRow);

			var $td = $j("<td>");
			$paletteTableRow.append($td);

			// Color Panel.
			var $table = $j("<table class='ia-editor-color-panel'>");
			$td.append($table);

			var $tr = $j("<tr>");
			$table.append($tr);

			var palettes = paletteConfig.getColorSchemes();
			for (var i = 0; i < palettes.length; i++) 
			{
				var p = palettes[i];

				// Palette button.
				var $td = $j("<td class='ia-list-item'>");
				$tr.append($td);
				(function() // Execute immediately
				{ 
					var palette = p;
					$td.bind(ia.CLICK_TYPE, function(e)
					{ 
						cClassifier.colorPalette = palette;
						me._settings.schemeId = palette.id;
						me._updateTheme();
					});
				})();

				// Color swatches.
				var colorList = p.getColorList();
				for (var j = 0; j < colorList.length; j++) 
				{
					var color = colorList[j];
					var $colorswatch = $j("<div class='ia-editor-color-panel-discrete-swatch'>");
					if (p.id ===  cClassifier.colorPalette.id) $colorswatch.addClass("ia-editor-swatch-selected")
					$colorswatch.css({"background-color" : color});
					$td.append($colorswatch);
				}
			}
		}
		
		if (this._thematic.symbol !== ia.Shape.SQUARE)  // Categoric Symbol Size
		{
			if (this.showSizePanel)
			{
				// Separator.
				if (this.showPalettePanel)
				{
					var $separator = $j("<div class='ia-editor-separator'>");
					menu.append($separator);
				}

				// Symbol size.
				var pointIncrementSize = 5;
				var minAllowedPointSize = 5;
				if (this._thematic.symbol === ia.Shape.LINE) 
				{
					pointIncrementSize = 1;
					minAllowedPointSize = 1;
				}
				var symbolSize = cClassifier.symbolSize;

				// Size Panel.
				var $sizeTable = $j("<table class='ia-editor-panel ia-editor-size-panel'>");
				menu.append($sizeTable);

				var $tr = $j("<tr>");
				$sizeTable.append($tr);

				// Decrease symbol size.
				var $td = $j("<td class='ia-list-item' style='width:50px'>").html("-");
				$tr.append($td);
				$td.bind(ia.CLICK_TYPE, function(e) 
				{ 
					var size = symbolSize - pointIncrementSize;
					if (size < minAllowedPointSize) size = minAllowedPointSize;
					cClassifier.symbolSize = size;
					me._updateTheme();
				});

				// Symbol.
				var $td = $j("<td style='padding:5px'>");
				$tr.append($td);

				var canvas = document.createElement('canvas');
				canvas.width = symbolSize + 2;
				if (this._thematic.symbol === ia.Shape.LINE) canvas.width = 100;
				canvas.height = symbolSize + 2;
				$td.append($j(canvas))
				var context = canvas.getContext("2d");

				if (this._thematic.symbol === ia.Shape.LINE)
				{
					context.strokeStyle = "#cccccc";
					context.lineWidth = symbolSize;
					context.beginPath();
						ia.Shape.draw(this._thematic.symbol, context, canvas.width/2, canvas.height/2, canvas.width);
					context.stroke();
				}
				else
				{
					context.strokeStyle = "#cccccc";
					context.fillStyle = "#f9f9f9";
					context.lineWidth = 1;
					context.beginPath();
					ia.Shape.draw(this._thematic.symbol, context, canvas.width/2, canvas.height/2, symbolSize);
					context.fill();
					context.stroke();
				}

				// Increase Symbol Size
				var $td = $j("<td class='ia-list-item' style='width:50px'>").html("+");
				$tr.append($td);
				$td.bind(ia.CLICK_TYPE, function(e) 
				{ 
					cClassifier.symbolSize = (symbolSize + pointIncrementSize);
					me._updateTheme();
				});
			}
		}

	}
	else  // Numeric.	
	{
		// Current classifier name.
		var cName = nClassifier.classificationName;
		if (cName !== "customClassifier")
		{
			var $table = $j("<table class='ia-editor-panel ia-editor-classifier-panel'>");
			menu.append($table);
					
			var $tr = $j("<tr>");
			$table.append($tr);

			if (this.showLegendTypePanel)
			{
				// Classification arrays.
				var cNames = [ia.Thematic.QUANTILE,ia.Thematic.EQUAL_INTERVAL,ia.Thematic.NATURAL,ia.Thematic.CONTINUOUS,ia.Thematic.STANDARD_DEVIATION];
				var cLabels = [this._reportConfig.getProperty("quantile"),
					this._reportConfig.getProperty("equalInterval"),
					this._reportConfig.getProperty("natural"),
					this._reportConfig.getProperty("continuous"),
					this._reportConfig.getProperty("standardDeviation")];
					
				// Current label
				var cLabel = cLabels[cNames.indexOf(cName)];

				for (var i = 0; i < cNames.length; i++) 
				{
					var name = cNames[i];
					var label = cLabels[i];

					if (label !== undefined)
					{
						var $td = $j("<td class='ia-list-item'>").html(label);
						if (label === cLabel) $td.addClass("ia-editor-classifier-selected")
						$tr.append($td);

						(function() // Execute immediately
						{ 
							var n = name;
							$td.bind(ia.CLICK_TYPE, function(e)
							{ 
								me._typeMenuOpen = false;
								nClassifier.classificationName = n;
								me._settings.legendType = n;
								me._updateTheme();
							});
						})();
					}
				}
			}
		}
		
		if (cName !== ia.Thematic.CONTINUOUS)  // Numeric Discrete.
		{
			if (cName !== "customClassifier")
			{
				if (this.showPalettePanel)
				{
					// Separator.
					if (this.showLegendTypePanel)
					{
						var $separator = $j("<div class='ia-editor-separator'>");
						menu.append($separator);
					}

					// Palette Panel.
					var $paletteTable = $j("<table class='ia-editor-panel ia-editor-palette-panel'>");
					menu.append($paletteTable);

					var $paletteTableRow = $j("<tr>");
					$paletteTable.append($paletteTableRow);

					var $td = $j("<td>");
					$paletteTableRow.append($td);

					// Color Panel.
					var $table = $j("<table class='ia-editor-color-panel'>");
					$td.append($table);

					var $tr = $j("<tr>");
					$table.append($tr);

					// Discrete palettes.
					var palettes = paletteConfig.getColorPalettes();
					for (var i = 0; i < palettes.length; i++) 
					{
						var p = palettes[i];

						// Palette button.
						var $td = $j("<td class='ia-list-item'>");
						if (p.id ===  nClassifier.colorPalette.id) $td.addClass("ia-editor-selected")
						$tr.append($td);
						(function() // Execute immediately
						{ 
							var palette = p;
							$td.bind(ia.CLICK_TYPE, function(e)
							{ 
								nClassifier.colorPalette = palette;
								me._settings.paletteId = palette.id;
								me._updateTheme();
							});
						})();

						// Color swatches.
						var noClasses = nClassifier.noClasses;
						if (cName === ia.Thematic.STANDARD_DEVIATION) noClasses = 6;
						var colors = p.getInterpolatedColors(noClasses);
						for (var j = 0; j < colors.length; j++) 
						{
							var color = colors[j];
							var $colorswatch = $j("<div class='ia-editor-color-panel-discrete-swatch'>");
							if (p.id ===  nClassifier.colorPalette.id) $colorswatch.addClass("ia-editor-swatch-selected")
							$colorswatch.css({"background-color" : color});
							$td.append($colorswatch);
						}
					}

					if (this.showLegendTools)
					{
						// Tool Panel.
						var $td = $j("<td>");
						$paletteTableRow.append($td);

						var $table = $j("<table class='ia-editor-tool-panel'>");
						$td.append($table);

						// Flip palette colors.
						var $tr = $j("<tr>");
						$table.append($tr);
						var $td = $j("<td class='ia-list-item'>").html("&uArr;&dArr;");
						$tr.append($td);
						$td.bind(ia.CLICK_TYPE, function(e) 
						{ 
							nClassifier.colorPalette.getColorList().reverse();
							me._updateTheme();
						});

						if (cName !== ia.Thematic.STANDARD_DEVIATION)
						{
							// Decrease no classes.
							var $tr = $j("<tr>");
							$table.append($tr);
							var $td = $j("<td class='ia-list-item'>").html("-");
							$tr.append($td);
							$td.bind(ia.CLICK_TYPE, function(e) 
							{ 
								if (nClassifier.noClasses > paletteConfig.minNoClasses) 
								{
									nClassifier.noClasses--;
									me._updateTheme();
								}
							});

							// Increase no classes.
							var $tr = $j("<tr>");
							$table.append($tr);
							var $td = $j("<td class='ia-list-item'>").html("+");
							$tr.append($td);
							$td.bind(ia.CLICK_TYPE, function(e) 
							{ 
								if (nClassifier.noClasses < paletteConfig.maxNoClasses) 
								{
									me._thematic.numericClassifier.noClasses++;
									me._updateTheme();
								}
							});
						}
					}
				}
			}
		}
		else  // Numeric Continuous.
		{
			if (this.showPalettePanel)
			{
				// Separator.
				if (this.showLegendTypePanel)
				{
					var $separator = $j("<div class='ia-editor-separator'>");
					menu.append($separator);
				}

				// Palette Panel.
				var $paletteTable = $j("<table class='ia-editor-panel ia-editor-palette-panel'>");
				menu.append($paletteTable);

				var $paletteTableRow = $j("<tr>");
				$paletteTable.append($paletteTableRow);

				var $td = $j("<td>");
				$paletteTableRow.append($td);

				// Color Panel.
				var $table = $j("<table class='ia-editor-color-panel'>");
				$td.append($table);

				var $tr = $j("<tr>");
				$table.append($tr);

				// Continuous palettes.
				var palettes = paletteConfig.getColorPalettes();
				for (var i = 0; i < palettes.length; i++) 
				{
					var p = palettes[i];

					// Palette button.
					var $td = $j("<td class='ia-list-item'>");
					$tr.append($td);
					(function() // Execute immediately
					{ 
						var palette = p;
						$td.bind(ia.CLICK_TYPE, function(e)
						{ 
							nClassifier.colorPalette = palette;
							me._settings.paletteId = palette.id;
							me._updateTheme();
						});
					})();

					var colors = p.getColorList();

					// Create a canvas to contain the gradient.
					var canvas = document.createElement('canvas');
					$j(canvas).addClass("ia-editor-color-panel-continuous-swatch");
					if (p.id ===  nClassifier.colorPalette.id) $j(canvas).addClass("ia-editor-swatch-selected")
					$td.append($j(canvas));
					
					// Draw the gradient.
					var context = canvas.getContext("2d");
					context.beginPath();
					ia.Shape.drawGradient(canvas, colors, "bottomToTop");
					context.fill();
				}

				if (this.showLegendTools)
				{
					// Tool Panel.
					var $td = $j("<td>");
					$paletteTableRow.append($td);

					var $table = $j("<table class='ia-editor-tool-panel'>");
					$td.append($table);
						
					// Flip palette colors.
					var $tr = $j("<tr>");
					$table.append($tr);
					var $td = $j("<td class='ia-list-item'>").html("&uArr;&dArr;");
					$tr.append($td);
					$td.bind(ia.CLICK_TYPE, function(e) 
					{ 
						nClassifier.colorPalette.getColorList().reverse();
						me._updateTheme();
					});
				}
			}
		}
		
		if (this._thematic.symbol !== ia.Shape.SQUARE)  // Numeric Symbol Size
		{
			if (this.showSizePanel)
			{
				// Separator.
				if (this.showPalettePanel || this.showLegendTypePanel)
				{
					var $separator = $j("<div class='ia-editor-separator'>");
					menu.append($separator);
				}

				// Size palette.
				var pointIncrementSize = 5;
				var minAllowedPointSize = 5;
				
				if (this._thematic.symbol === ia.Shape.LINE) 
				{
					pointIncrementSize = 1;
					minAllowedPointSize = 1;
				}

				var sizePalette = nClassifier.sizePalette;
				var colorList = nClassifier.colorPalette.getColorList();
				var minColor = colorList[0];
				var maxColor = colorList[colorList.length-1];

				// Size Panel.
				var $sizeTable = $j("<table class='ia-editor-panel ia-editor-size-panel'>");
				menu.append($sizeTable);

				var $sizeTableRow = $j("<tr>");
				$sizeTable.append($sizeTableRow);

				// Min Buttons.
				var $td = $j("<td style='vertical-align:top;width:50px;padding:0px'>");
				$sizeTableRow.append($td);

				var $table = $j("<table style='width:100%'>");
				$td.append($table);

				// Decrease min button.
				var $tr = $j("<tr>");
				$table.append($tr);
				var $td = $j("<td class='ia-list-item'>").html("-");
				$tr.append($td);
				$td.bind(ia.CLICK_TYPE, function(e) 
				{ 
					var size = sizePalette.minSize - pointIncrementSize;
					if (size < minAllowedPointSize) size = minAllowedPointSize;
					sizePalette.minSize = size;
					me._updateTheme();
				});

				// Increase min button.
				var $tr = $j("<tr>");
				$table.append($tr);
				var $td = $j("<td class='ia-list-item'>").html("+");
				$tr.append($td);
				$td.bind(ia.CLICK_TYPE, function(e) 
				{ 
					sizePalette.minSize = (sizePalette.minSize + pointIncrementSize);
					me._updateTheme();
				});
								
				// Min Symbol.
				var $td = $j("<td style='padding:5px'>");
				$sizeTableRow.append($td);

				var canvasSize = Math.max(sizePalette.minSize,sizePalette.maxSize)  + 2;

				var canvas = document.createElement('canvas');
				canvas.width = canvasSize;
				if (this._thematic.symbol === ia.Shape.LINE) canvas.width = 100;
				canvas.height = canvasSize;
				$td.append($j(canvas))
				var context = canvas.getContext("2d");

				if (this._thematic.symbol === ia.Shape.LINE)
				{
					context.strokeStyle = minColor;
					context.lineWidth = sizePalette.minSize;
					context.beginPath();
						ia.Shape.draw(this._thematic.symbol, context, canvas.width/2, canvas.height/2, canvas.width);
					context.stroke();
				}
				else
				{
					context.strokeStyle = "#cccccc";
					context.fillStyle = minColor;
					context.lineWidth = 1;
					context.beginPath();
					ia.Shape.draw(this._thematic.symbol, context, canvas.width/2, canvas.height/2, sizePalette.minSize);
					context.fill();
					context.stroke();
				}
				
				// Max Symbol.
				var $td = $j("<td style='padding:5px'>");
				$sizeTableRow.append($td);

				var canvas = document.createElement('canvas');
				canvas.width = canvasSize;
				if (this._thematic.symbol === ia.Shape.LINE) canvas.width = 100;
				canvas.height = canvasSize;
				$td.append($j(canvas))
				var context = canvas.getContext("2d");

				if (this._thematic.symbol === ia.Shape.LINE)
				{
					context.strokeStyle = maxColor;
					context.lineWidth = sizePalette.maxSize;
					context.beginPath();
						ia.Shape.draw(this._thematic.symbol, context, canvas.width/2, canvas.height/2, canvas.width);
					context.stroke();
				}
				else
				{
					context.strokeStyle = "#cccccc";
					context.fillStyle = maxColor;
					context.lineWidth = 1;
					context.beginPath();
						ia.Shape.draw(this._thematic.symbol, context, canvas.width/2, canvas.height/2, sizePalette.maxSize);
					context.fill();
					context.stroke();
				}

				// Max Buttons.
				var $td = $j("<td style='vertical-align:top;width:50px;padding:0px'>");
				$sizeTableRow.append($td);

				var $table = $j("<table style='width:100%'>");
				$td.append($table);

				var $tr = $j("<tr>");
				$table.append($tr);
				
				// Decrease max button.
				var $td = $j("<td class='ia-list-item'>").html("-");
				$tr.append($td);
				$td.bind(ia.CLICK_TYPE, function(e) 
				{ 
					var size = sizePalette.maxSize - pointIncrementSize;
					if (size < minAllowedPointSize) size = minAllowedPointSize;
					sizePalette.maxSize = size;
					me._updateTheme();
				});

				// Increase max button.
				var $tr = $j("<tr>");
				$table.append($tr);
				var $td = $j("<td class='ia-list-item'>").html("+");
				$tr.append($td);
				$td.bind(ia.CLICK_TYPE, function(e) 
				{
					sizePalette.maxSize = (sizePalette.maxSize + pointIncrementSize);
					me._updateTheme();
				});
			}
		}
	}
			
	this._lockEditor = false;
};

/**
 * Updates the theme - uses a timer and a lock editor variable to cope with rapid clicking.
 *
 * @method _updateTheme
 * @private
 */
ia.LegendEditor.prototype._updateTheme = function()
{		
	if (!this._lockEditor)
	{
		var me = this;
		clearTimeout(this._updateTimeout);
		this._updateTimeout = setTimeout(function() 
		{
			me._lockEditor = true;
			me._thematic.commitChanges();
		}, 100);
	}
};

/**
 * Toggles the editor visibility.
 *
 * @method toggle
 */
ia.LegendEditor.prototype.toggle = function(visible)
{
	if (this._isVisible) this.hide();
	else this.show();
};

/**
 * Hides the editor.
 *
 * @method hide
 */
ia.LegendEditor.prototype.hide = function()
{	
	//if (this._isVisible) this.container.slideUp('slow', function() {this._isVisible = false;});
	if (this._isVisible) 
	{
		this.container.animate({opacity: 0}, function() 
		{
			this.container.css({visibility: "hidden"});
			this._isVisible = false;
		});
	}
};

/**
 * Shows the editor.
 *
 * @method show
 */
ia.LegendEditor.prototype.show = function()
{
	if (!this._isVisible) 
	{
		this.container.css({visibility: "visible"}).animate({opacity: 1}, function() 
		{
			this._isVisible = true;
		});
	}
};