[moodle] / contrib / plugins / grade / report / visual / flare_visualization / flare_visualization.as Repository:

View of /contrib/plugins/grade/report/visual/flare_visualization/flare_visualization.as

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.2 - (download) (annotate)
Tue Jul 15 03:27:17 2008 WST (16 months, 1 week ago) by dservos
Branch: MAIN
Changes since 1.1: +539 -59 lines
CONTRIB-497
Cleaned up some of the code for report/visual and the flex based application for viewing the visualizations.

Improved the UI of the visualization.

Added documentation to both the php and actionscript 3 (flex) code.

Removed some unneeded files.

TODO:
*Add more visualizations.
*Add printer firendly version.
*Make flex appplications settings less hardcoded and loaded from moodle.
*Load lang files from moodle to flex for full language support.
*Add a settings page for the report.
///////////////////////////////////////////////////////////////////////////
//                                                                       //
// NOTICE OF COPYRIGHT                                                   //
//                                                                       //
// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
//          http://moodle.org                                            //
//                                                                       //
// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
//                                                                       //
// This program is free software; you can redistribute it and/or modify  //
// it under the terms of the GNU General Public License as published by  //
// the Free Software Foundation; either version 2 of the License, or     //
// (at your option) any later version.                                   //
//                                                                       //
// This program is distributed in the hope that it will be useful,       //
// but WITHOUT ANY WARRANTY; without even the implied warranty of        //
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         //
// GNU General Public License for more details:                          //
//                                                                       //
//          http://www.gnu.org/copyleft/gpl.html                         //
//                                                                       //
///////////////////////////////////////////////////////////////////////////
  
 /**
 * This is the flex with flare based visualizer for the Moodle 2.x visual
 * grade book plug-in. This should load the grade book data for a given
 * visualization from the report/visual plug-in based on a set of flashvars
 * passed to it from Moodle and display a visual repersenation.
 */
package {
	//Flare imports
    import flare.animate.Transitioner;
    import flare.data.DataSet;
    import flare.data.DataSource;
    import flare.display.TextSprite;
    import flare.vis.Visualization;
    import flare.vis.controls.HoverControl;
    import flare.vis.data.Data;
    import flare.vis.data.DataSprite;
    import flare.vis.legend.Legend;
    import flare.vis.legend.LegendItem;
    import flare.vis.operator.encoder.ColorEncoder;
    import flare.vis.operator.encoder.ShapeEncoder;
    import flare.vis.operator.layout.AxisLayout;
    import flare.vis.scale.ScaleType;
    import flare.vis.util.Filters;
    
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.GlowFilter;
    import flash.geom.Rectangle;
    import flash.net.URLLoader;
    import flash.text.TextFormat;

    [SWF(width="800", height="600", backgroundColor="#ffffff", frameRate="30")]
    /**
    * Main class for handling grade book data and greatating a visualization.
    */
    public class flare_visualization extends Sprite
    {   
    	/**
    	 * The visualization object to be used in creating the visualization.
    	 */
    	private var vis:Visualization;
    	
    	/**
    	 * A refernce to the currently displayed dialog box. If null no dialog
    	 * box is currently being displayed.
    	 */
    	private var lastBox:Sprite = null;
    	
    	/**
    	 * A refernce to the data sprite witch contains the data for witch the 
    	 * currently displayed dialog box is based on and a child of.
    	 */
    	private var lastBoxData:DataSprite = null;
    	
    	/**
    	 * The data feild the X axis is based on.
    	 * @default data.student
    	 */
    	private var axisX:String = "data.student";
    	
    	/**
    	 * The data field the Y axis is based on.
    	 * @default data.grade
    	 */
    	private var axisY:String = "data.grade";    	
    	
    	/**
    	 * A container for the legends witch will be displayed on the righ hand
    	 * side.
    	 */
    	private var legends:Sprite;
    	
    	/**
    	 * The hover control for the dialog box.
    	 */
    	private var boxhc:HoverControl = new HoverControl();
    	
    	/**
    	 * The constucter for the flare_visualization class.
    	 * Calls on harvest_data and sets up the varibles from the flashvars.
    	 */	
        public function flare_visualization()
        {
        	// Call harvest_data, loading needed visualization data from moodle.
        	// The Moodle wwwroot, course id, users sessionid, users session cookie 
        	// and session test data are needed to get the data from moodle are 
        	// loaded threw flashvars.
        	harvest_data(loaderInfo.parameters['wwwroot'] + '/grade/report/visual/data.php?id=' +   escape(loaderInfo.parameters['courseid']) + '&sessioncookie=' +  escape(loaderInfo.parameters['sessioncookie']) + '&sessionid=' +  escape(loaderInfo.parameters['sessionid']) + '&sessiontest=' + escape(loaderInfo.parameters['sessiontest']));
        	//harvest_data('http://localhost/moodle/grade/report/visual/data.php?id=3&sessioncookie=&sessionid=ebb79f5984c0fa4c9b0d85814c573a81&sessiontest=jHKFJhsOPf');
        }
        
        /**
        * Harvests the data from Moodle and calls on buildVis to build the
        * visualization once the data has been loaded.
        * TODO: Add a loading bar and more feed back about the loading process.
        * @param url The url from witch to load the tab formated data for the visualization.
        */
        public function harvest_data(url:String):void
        {
        	var ds:DataSource = new DataSource(url, "tab");
            var loader:URLLoader = ds.load();
            loader.addEventListener(Event.COMPLETE, function(evt:Event):void {
                var ds:DataSet = loader.data as DataSet;
                buildVis(Data.fromDataSet(ds));
            });
        }
     
     	/**
     	 * Find the max width between a container and all of it's decendence
     	 * This dose not find the width of a container but the greatest width
     	 * of an invdual component in it's decenedences.
     	 * @param d The display container to find the max width of.
     	 * @return the max width value of the display objects.
     	 */ 
     	private function getMaxWidth(d:DisplayObjectContainer):int {
     		var max:int = d.width;
     		  
            for(var k:uint = 0; k < d.numChildren; k++ ) {  
            	var width:int = 0;
            	
                if(d.getChildAt(k) is DisplayObjectContainer) {
                	width = getMaxWidth(DisplayObjectContainer(d.getChildAt(k)));  
                } else {
                	width = d.getChildAt(k).width;
                }
  				
  				if(width > max) {
  					max = width;
  				}
            }
            
            return max;
        }
     
     	/**
     	 * Simple function to retrun the greatest of two ints.
     	 * @param num1 the first number to test
     	 * @param num2 the second number to test
     	 * @return the largest value between num1 and num2.
     	 */
     	private function max(num1:int, num2:int):int {
     		if(num1 > num2) {
     			return num1;
     		} else {
     			return num2;
     		}
     	}
     
     	/**
     	 * Find the max height between a container and all of it's decendence
     	 * This dose not find the width of a container but the greatest height
     	 * of an invdual component in it's decenedences.
     	 * @param d The display container to find the max height of.
     	 * @return the max height value of the display objects.
     	 */ 
     	private function getMaxHeight(d:DisplayObjectContainer):int {
     		var max:int = d.height;
     		  
            for(var k:uint = 0; k < d.numChildren; k++ ) {  
            	var height:int = 0;
            	
                if(d.getChildAt(k) is DisplayObjectContainer) {
                	height = getMaxHeight(DisplayObjectContainer(d.getChildAt(k)));  
                } else {
                	height = d.getChildAt(k).height;
                }
  				
  				if(height > max) {
  					max = height;
  				}
            }
            
            return max;
        }  
     
     	/**
     	 * Builds the visualization based on the loaded data.
     	 * Also sets up the legends, buttons and controls.
     	 * @param data The data that was loaded in from moodle.
     	 */
     	private function buildVis(data:Data):void
        {
            vis = new Visualization(data);
            legends = new Sprite();
            
            // Set the functions to be called when a dialog box is hovered over.
            boxhc.onRollOver = boxRollOver;
			boxhc.onRollOut = boxRollOut;
            
			// Set up the encoders and layout
			var colorEncoder:ColorEncoder = new ColorEncoder("data.item", Data.NODES, "lineColor", ScaleType.CATEGORIES);
			var shapeEncoder:ShapeEncoder = new ShapeEncoder("data.group");
			var al:AxisLayout = new AxisLayout(axisX, axisY);
			
			// Add the encoders and layout to the visualization.
			vis.operators.add(al);
            vis.operators.add(colorEncoder);
            vis.operators.add(shapeEncoder);
            
            // Set up the layout of the axes.
            vis.xyAxes.xAxis.horizontalAnchor = TextSprite.LEFT; 
			vis.xyAxes.xAxis.verticalAnchor = TextSprite.MIDDLE; 
			vis.xyAxes.xAxis.labelAngle = Math.PI / 2;
			vis.xyAxes.xAxis.fixLabelOverlap = false;
			vis.xyAxes.yAxis.fixLabelOverlap = false;
			
            // Update the visualization so the widths and other values are correct.
            vis.update();
			
			// Initalize the X and Y axis labels and the visualizations title.
			var labelX:TextSprite = new TextSprite("Student", new TextFormat("mono", 20)); 
			var labelY:TextSprite = new TextSprite("Grade", new TextFormat("mono", 20));
			var title:TextSprite = new TextSprite("Normalized Grades vs Students", new TextFormat("mono", 25));
			
			// Find the largest width out of the X axis labels so it can used for positing sprites.
           	var xLabelsHeight:int = getMaxHeight(vis.xyAxes.xAxis.labels);
            var yLabelsWidth:int = getMaxWidth(vis.xyAxes.yAxis.labels);
            
			// Position the visualization.
			vis.y = title.height + 10;
            vis.x = labelY.height + -vis.xyAxes.yAxis.labelOffsetX + yLabelsWidth;
			
			// Set up the legends.
			var itemLegend:Legend = new Legend("data.item", colorEncoder.scale, colorEncoder.colors, null, null);
            var groupLegend:Legend = new Legend("data.group", shapeEncoder.scale, null, shapeEncoder.shapes, null);
           	
            // Set the bounds of the visualization based on the hieght and width of the flash application,
            // and the other components so the visualization is takes up the unused space.
            vis.bounds = new Rectangle(0, 0, loaderInfo.width - (max(itemLegend.width, groupLegend.width) + 15 + vis.x), loaderInfo.height - (vis.y + xLabelsHeight + labelX.height + vis.xyAxes.xAxis.labelOffsetY)); 
            
            // Add the visualization to the main sprite.
            addChild(vis);
            
            // Set up the properitys of the data sprites and add a eventlistener to check for
            // clicks on them.
            vis.data.visit(function(d:DataSprite):void {
				d.fillColor = 0x018888ff;
				d.fillAlpha = 0.2;
				d.lineWidth = 2;
				d.addEventListener(MouseEvent.CLICK, mouseClicked);
			});
             
            // Position the legends.
            legends.x = vis.bounds.width + 10;
            itemLegend.x = 0;
            itemLegend.y = 0;
            groupLegend.x = 0;
            groupLegend.y = itemLegend.y + itemLegend.height;
            
            // Add a listener for mouse clicks on the legends.
            itemLegend.items.addEventListener(MouseEvent.CLICK, legendClick);
            groupLegend.items.addEventListener(MouseEvent.CLICK, legendClick);
            
            // Add the legends to the legends container.
            legends.addChild(itemLegend);
            legends.addChild(groupLegend);

            // Set up and add a hover control to each legend.  
            var itemHC:HoverControl = new HoverControl(itemLegend.items);
            itemHC.onRollOver = legendRollOver;
			itemHC.onRollOut = legendRollOut;
            var groupHC:HoverControl = new HoverControl(groupLegend.items);
            groupHC.onRollOver = legendRollOver;
			groupHC.onRollOut = legendRollOut;
            
            
            // Position and add the labels and title to the axes.
			labelX.x = vis.bounds.width/2 - labelX.width/2;
			labelX.y = vis.bounds.height + vis.xyAxes.xAxis.labelOffsetY + xLabelsHeight;
            vis.xyAxes.xAxis.addChild(labelX);
            
			labelY.x = -vis.x;
			labelY.y = vis.bounds.height/2 - labelY.width/2;
			labelY.rotation = -90;
			vis.xyAxes.yAxis.addChild(labelY);
			
			title.x = vis.bounds.width/2 - title.width/2;
			title.y = -vis.y;
			vis.xyAxes.addChild(title);
            
      		// Add the legeneds container to the visualization.
            vis.addChild(legends);
            
            // Set up the hovercontrol for the marks on the chart
            var hc:HoverControl = new HoverControl(vis, Filters.isDataSprite);
            hc.onRollOver = rollOver;
			hc.onRollOut = rollOut;
			
			// Set up the buttons and a container for them.
			var controls:Sprite = new Sprite();
			var bInvert:Button = new Button("Invert Axes");
			var bHideAxis:Button = new Button("Hide Axes");
			var bHideXLabel:Button = new Button("Hide X Labels");
			var bHideYLabel:Button = new Button("Hide Y Labels");
			
			var hideXLabelTransitioner:Transitioner = new Transitioner(2);
			bHideXLabel.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
				if(!hideXLabelTransitioner.running) {
					hideXLabelTransitioner.reset();
					
					if(bHideXLabel.text == "Show X Labels") {
						bHideXLabel.text = "Hide X Labels";
						vis.xyAxes.xAxis.showLabels = true;
						vis.bounds = new Rectangle(0, 0, loaderInfo.width - (legends.width + 15 + vis.x), loaderInfo.height - (vis.y + xLabelsHeight + labelX.height + vis.xyAxes.xAxis.labelOffsetY));
					} else {
						bHideXLabel.text = "Show X Labels";
						vis.xyAxes.xAxis.showLabels = false;
						vis.bounds = new Rectangle(0, 0, loaderInfo.width - (legends.width + 15 + vis.x), loaderInfo.height - (vis.y + labelX.height));
					}
					
					hideXLabelTransitioner.$(labelY).x = -vis.x;
					hideXLabelTransitioner.$(labelY).y = vis.bounds.height/2 - labelY.height/2;
				
					vis.update(hideXLabelTransitioner).play();
				}
			});
			
			var hideYLabelTransitioner:Transitioner = new Transitioner(2);
			bHideYLabel.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
				if(!hideYLabelTransitioner.running) {
					var t:Transitioner = new Transitioner(2);
					var newX:int;
					
					hideYLabelTransitioner.reset();
					
					if(bHideYLabel.text == "Show Y Labels") {
						bHideYLabel.text = "Hide Y Labels";
						vis.xyAxes.yAxis.showLabels = true;
						newX = labelY.width + -vis.xyAxes.yAxis.labelOffsetX + yLabelsWidth;
					} else {
						bHideYLabel.text = "Show Y Labels";
						vis.xyAxes.yAxis.showLabels = false;
						newX = labelY.width;
					}
				
					t.$(vis).x = newX;
					vis.bounds = new Rectangle(0, 0, loaderInfo.width - (legends.width + 15 + newX), loaderInfo.height - (vis.y + xLabelsHeight + labelX.height + vis.xyAxes.xAxis.labelOffsetY));
					
					// Reposition the labels and title. 
					t.$(title).x = vis.bounds.width/2 - title.width/2;
					t.$(labelX).x = vis.bounds.width/2 - labelX.width/2;
					t.$(labelX).y = vis.bounds.height + vis.xyAxes.xAxis.labelOffsetY + xLabelsHeight;
					t.$(labelY).x = -newX;
					t.$(labelY).y = vis.bounds.height/2 - labelY.height/2;
				
					// Keep the legends in there place.
					t.$(legends).x = vis.bounds.width + 10;
					
					t.play();
					vis.update(hideYLabelTransitioner).play();
				}
			});
			
			// Set up the transitioner to be used when inverting the axes
			var updateTransitioner:Transitioner = new Transitioner(2);
			updateTransitioner.onEnd = function():void {
				updateMarkVisiblity();
				vis.xyAxes.xAxis.labels.visible = true;
				vis.xyAxes.yAxis.labels.visible = true;
   			};
            updateTransitioner.onStart = function():void {
            	updateMarkVisiblity();
            	vis.xyAxes.xAxis.labels.visible = false;
				vis.xyAxes.yAxis.labels.visible = false;
            }
			
			// The function to invert the axes.
			bInvert.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
				// If we are not allready in the process of inverting the axes.
				if(!updateTransitioner.running) {
					var t:Transitioner = new Transitioner(2);
					var tempText:String = labelX.text;
					var tempOffset:int = vis.xyAxes.xAxis.labelOffsetX;
					var tempWidth:uint = vis.bounds.width;
					
					var tempLabels:int = xLabelsHeight;
					var currentXLabelsHeight:int = getMaxWidth(vis.xyAxes.yAxis.labels);
					
					var tempShowLabels:Boolean = vis.xyAxes.xAxis.showLabels;
				
					// Rest the transitioner for a clean transition.
					updateTransitioner.reset();		
					
					// Flip the axis feilds.
					al.xField = axisY;
					al.yField = axisX;
					axisX = al.xField;
					axisY = al.yField;
				
					xLabelsHeight = yLabelsWidth;
					yLabelsWidth = tempLabels;
				
					vis.xyAxes.xAxis.showLabels = vis.xyAxes.yAxis.showLabels;
					vis.xyAxes.yAxis.showLabels = tempShowLabels;
				
					if(vis.xyAxes.yAxis.showLabels) {
						bHideYLabel.text = "Hide Y Labels";
					} else {
						bHideYLabel.text = "Show Y Labels";
					}
					
					if(vis.xyAxes.xAxis.showLabels) {
						bHideXLabel.text = "Hide X Labels";
					} else {
						bHideXLabel.text = "Show X Labels";
					}
					
				
					// Flip the labels
					labelX.text = labelY.text;
					labelY.text = tempText;
				
					// Find the new X value for the visualization.
					var newX:int = labelY.width + vis.xyAxes.xAxis.labelOffsetY + getMaxHeight(vis.xyAxes.xAxis.labels);
				
					// Reposition and set the bounds of the visualization.
					t.$(vis).x = newX;
					vis.bounds = new Rectangle(0, 0, loaderInfo.width - (legends.width + 15 + newX), loaderInfo.height - (vis.y + currentXLabelsHeight + labelX.height + vis.xyAxes.xAxis.labelOffsetY));
				
					// Reposition the labels and title. 
					t.$(title).x = vis.bounds.width/2 - title.width/2;
					t.$(labelX).x = vis.bounds.width/2 - labelX.width/2;
					t.$(labelX).y = vis.bounds.height + vis.xyAxes.xAxis.labelOffsetY + currentXLabelsHeight;
					t.$(labelY).x = -newX;
					t.$(labelY).y = vis.bounds.height/2 - labelY.width/2;
				
					// Keep the legends in there place.
					t.$(legends).x = vis.bounds.width + 10;
				
					//Play the transition.
            		t.play();
            		vis.update(updateTransitioner).play();
    			}
			});
			
			// Set up the transitioner for the hide axes button.
			var hideAxisTrans:Transitioner = new Transitioner(1);
			
			// Function for hidding the axes.
			bHideAxis.addEventListener(MouseEvent.CLICK, function(evt:MouseEvent):void {
				// If we are not allready in the process of hidding the axes
				if(!hideAxisTrans.running) {
					// Reset the transitoner for a clean transiton.
					hideAxisTrans.reset();
					
					// Hide or show the axes.
					if(bHideAxis.text == "Show Axes") {
						hideAxisTrans.$(bHideAxis).text = "Hide Axes";
						al.showAxes(hideAxisTrans).play();
					} else {
						hideAxisTrans.$(bHideAxis).text = "Show Axes";
						al.hideAxes(hideAxisTrans).play();
					}
				}
			});
			
			// Position the buttons inside there container.
			bHideXLabel.x = 0;
			bHideXLabel.y = 0;
			
			bHideAxis.x = legends.width - bHideAxis.width - 5;
			bHideAxis.y = bHideXLabel.y;
			
			bInvert.x = legends.width - bInvert.width - 5;
			bInvert.y = bHideXLabel.y + bHideXLabel.height + 2;
			
			bHideYLabel.x = 0;
			bHideYLabel.y = bHideXLabel.y + bHideXLabel.height + 2;
			
			// Poistion the buttons container.
			controls.x = legends.x + vis.x; 
			controls.y = legends.y + legends.height + vis.y + 20; 
			
			// Add the buttons to the container and the container to the main sprite.
			controls.addChild(bInvert);
			controls.addChild(bHideAxis);
			controls.addChild(bHideXLabel);
			controls.addChild(bHideYLabel);
			addChild(controls);
	
			// Set the marks on the chart to the higest deepth.
            vis.setChildIndex(vis.marks, vis.numChildren - 1);
	
			// Update.
			vis.update();
			updateMarkVisiblity();
        }
        
        /**
        * Roll over function witch makes the object 0.5 units bigger and adds a glow filter.
        * @param ob the object witch was rolled over.
        */
        private function rollOver(ob:Object):void {
        	ob.filters = [new GlowFilter(0xFFFF55, 0.8, 6, 6, 10)];
        	ob.size += 0.5;
        }
        
        /**
        * Roll out function witch removes the filters and makes the object 0.5 units smaller.
        * @param ob the object witch was rolled out of.
        */
        private function rollOut(ob:Object):void {
        	ob.filters = null;
        	ob.size -= 0.5;
        }
        
        /**
        * Roll over function for the dialog box.
        * Adds a glow filter to the curently active dialog box.
        * @param ob a child of the dialog box.
        */
        private function boxRollOver(ob:Object):void {
        	if(lastBoxData != null) {
        		lastBoxData.filters = [new GlowFilter(0xFFFF55, 0.8, 6, 6, 10)];
        	}
        }
        
        /**
        * Roll out function for the dialog box.
        * Removes filters on the curently active dialog box.
        * @param ob a child of the dialog box.
        */
        private function boxRollOut(ob:Object):void {
        	if(lastBoxData != null) {
        		lastBoxData.filters = null;
        	}
        }
        
        /**
        * Finds the Legend belonging to the LegendItem passed.
        * TODO: See if this can be replaced by a .parent call.
        * @param item a LegendItem to find the Legend of.
        * @return the Legend that contains the passed LegendItem.
        */
        private function findLegendByItem(item:LegendItem):Legend {
       		for(var i:uint = 0; i < legends.numChildren; i++ ) {
        		if(Legend(legends.getChildAt(i)).items.contains(item)) {
        			return Legend(legends.getChildAt(i));
        		}
        	}
        	
        	return null;
        }
        
        /**
        * Roll over function for legends.
        * Adds a glow filter to the legend's item aswell as all the markers on the chart
        * that are realted to the legend item and incrases there size by 1 unit.
        * @param ob the LegendItem being rolled over.
        */ 
        private function legendRollOver(ob:LegendItem):void {
        	var legend:Legend = findLegendByItem(ob);
        	var dataName:String = legend.dataField.substr(legend.dataField.lastIndexOf('.') + 1);
        	
        	ob.filters = [new GlowFilter(0xFFFF55, 0.8, 6, 6, 10)];
        	
        	vis.data.visit(function(d:DataSprite):void {
				if(d.data.hasOwnProperty(dataName) && ob.value == d.data[dataName]) {
					d.filters = [new GlowFilter(0xFFFF55, 0.8, 6, 6, 10)];
					d.size += 1;
				}
			}, 3, Filters.isDataSprite);
        }
        
        /**
        * Roll out function for legends.
        * Removes filters to the legend's item aswell as all the markers on the chart
        * that are realted to the legend item and decrases there size by 1 unit.
        * @param ob the LegendItem being rolled out of.
        */ 
        private function legendRollOut(ob:LegendItem):void {
        	var legend:Legend = findLegendByItem(ob);
        	var dataName:String = legend.dataField.substr(legend.dataField.lastIndexOf('.') + 1);
        	
        	ob.filters = null;
        	
        	vis.data.visit(function(d:DataSprite):void {
				if(d.data.hasOwnProperty(dataName) && ob.value == d.data[dataName]) {
					d.filters = null;
					d.size -= 1;
				}
			}, 3, Filters.isDataSprite);
        }
        
        /**
        * Creates and returns a dialog box containing information on the passed data sprite.
        * @param data the DataSprite containing the information to display.
        * @returns the Sprite containing the dialog box.
        */
        private function dataDialogBox(data:DataSprite):Sprite {
        	var box:Sprite = new Sprite;
        	
        	var backGround:Sprite = new Sprite;	
        	backGround.graphics.beginFill(0x7777ff, 0.60);
        	backGround.graphics.lineStyle(3, 0x0000ff, 0.3);
        	 
        	var text:Sprite = new Sprite;
        	var x:int = 5;
        	var y:int = 0;
        	
        	for(var property:Object in data.data) {
        		var temp:TextSprite = new TextSprite(property.toString() + ": " + data.data[property], new TextFormat("mono", 12, null, true));
        		temp.x = x;
        		temp.y = y;
        		text.addChild(temp);
        		y += temp.height;
        	}
        	
        	/*var name:TextSprite = new TextSprite(data.data.student, new TextFormat("mono", 20, null, true));
        	var item:TextSprite = new TextSprite("Item: " + data.data.item, new TextFormat("mono", 12, null, true));
        	var grade:TextSprite = new TextSprite("Grade: " + data.data.grade + "%", new TextFormat("mono", 12, null, true));
        	var group:TextSprite = new TextSprite("Group: " + data.data.group, new TextFormat("mono", 12, null, true));
        	text.addChild(name);
        	text.addChild(item);
        	text.addChild(group);
        	text.addChild(grade);
        	
        	name.x = text.width/2 - name.width/2;
        	item.x = 5;
        	grade.x = 5;
        	group.x = 5;
        	
        	name.y = 0;
        	item.y = name.y + name.height;
        	group.y = item.y + item.height;
        	grade.y = group.y + group.height;*/
   
        	backGround.graphics.drawRoundRect(0, 0, text.width + 10, text.height, 30, 30);     	
        	
        	box.addChild(backGround);
        	box.addChild(text);
        	
        	return box;
        }
        
        /**
        * Check if a mark on the chart is visible based on the related LegendItems states.
        * @param d the DataSprite to check the visiblility of.
        * @returns true if the mark is visible.
        */
        private function markIsVisible(d:DataSprite):Boolean {
        	var items:Array = getLegendItems(d);
        	
        	for each(var item:LegendItem in items) {
        		if(item.alpha != 1) {
        			return false;
        		}
        	}
        	
        	return true;
        }
        
        /**
        * Gets all LegenedItems realted to a given DataSprite/mark.
        * @params d the DataSprite on the chart.
        * @returns Array of LegendItems that are realted to the given DataSprite.
        */
        private function getLegendItems(d:DataSprite):Array {
        	var items:Array = new Array();
        	
        	for(var i:uint = 0; i < legends.numChildren; i++) {
        		var legend:Legend = Legend(legends.getChildAt(i));

        		for(var k:uint = 0; k < legend.items.numChildren; k++) {
        			var item:LegendItem = LegendItem(legend.items.getChildAt(k));
        			
        			if(d.data[legend.dataField.substr(legend.dataField.lastIndexOf('.') + 1)] == item.value) {
        				items.push(item);
        				break;
        			}
        		}
        	}
        	
        	return items;
        }
        
        /**
        * Sets the visible atrubute of the marks/DataSprites based on the status of the LegendItems realted to it.
        * @param item if set, only updates marks for that LegendItem. Otherwise updates all marks.
        */ 
        private function updateMarkVisiblity(item:LegendItem=null):void {
        	var legend:Legend;
        	var dataName:String;
        	
        	if(item != null) {
        		legend = findLegendByItem(item);
        		dataName = legend.dataField.substr(legend.dataField.lastIndexOf('.') + 1);
        	}
        	
        	vis.data.visit(function(d:DataSprite):void {
				if(item == null || (d.data.hasOwnProperty(dataName) && item.value == d.data[dataName])) {		
					if(markIsVisible(d)) {
						//d.alpha = 1.0;
						d.visible = true;
					} else {
						//d.alpha = 0.0;
						d.visible = false;
					}
				}
			}, 3, Filters.isDataSprite);
        }
        
        /**
        * Function to be called when a LegendItem is clicked.
        * Changes the legendItems alpah value and updates mark visiblity.
        * @param evt the mouse event.
        */
        private function legendClick(evt:MouseEvent):void {
        	var item:LegendItem = LegendItem(evt.target);
        	
        	if(item.alpha == 1) {
        		item.alpha = 0.4;
        	} else {
        		item.alpha = 1.0;
        	}
        	
        	updateMarkVisiblity(item);
        }
        
        /**
        * Function called when a click happens on a mark on the chart.
        * Creates and adds a dialog box for that mark/DataSprite when clicked or removes the dialog box if
        * the mark allready has one.
        * @param the mouse event.
        */
        private function mouseClicked(evt:MouseEvent):void {
        	if(DisplayObject(evt.target).parent == vis.marks) {
        		if(lastBox != null && lastBoxData != null) {
        			lastBoxData.removeChild(lastBox);
        			boxhc.detach();
        		}
        		
        		if(evt.target != lastBoxData) {
        			lastBox = dataDialogBox(DataSprite(evt.target));
        			lastBoxData = DataSprite(evt.target);
        			Sprite(evt.target).addChild(lastBox);
    				vis.marks.setChildIndex(Sprite(evt.target), vis.marks.numChildren - 1);
    				boxhc.attach(Sprite(evt.target));
        		} else {
        			lastBoxData = null;
        			lastBox = null;
        		}
        	}
        }
    }
}

Moodle CVS Admin
ViewVC Help
Powered by ViewVC 1.0.7