← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 11146: (PT) Experimenting with legend sets. WIP.

 

------------------------------------------------------------
revno: 11146
committer: Jan Henrik Overland <janhenrik.overland@xxxxxxxxx>
branch nick: dhis2
timestamp: Wed 2013-06-05 22:11:33 +0200
message:
  (PT) Experimenting with legend sets. WIP.
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java
  dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml
  dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java
  dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java
  dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module.properties
  dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module_fr_FR.properties
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/i18n.vm
  dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java	2013-05-29 13:05:35 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/reporttable/ReportTable.java	2013-06-05 20:11:33 +0000
@@ -58,6 +58,7 @@
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.i18n.I18nFormat;
 import org.hisp.dhis.indicator.Indicator;
+import org.hisp.dhis.mapping.MapLegendSet;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.period.Period;
 import org.hisp.dhis.period.RelativePeriods;
@@ -192,6 +193,11 @@
      */
     private String fontSize;
     
+    /**
+     * The legend set in the table.
+     */
+    private MapLegendSet legendSet;
+    
     // -------------------------------------------------------------------------
     // Transient properties
     // -------------------------------------------------------------------------
@@ -921,6 +927,19 @@
         this.fontSize = fontSize;
     }
 
+    @JsonProperty
+    @JsonView( {DetailedView.class, ExportView.class, DimensionalView.class} )
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0)
+    public MapLegendSet getLegendSet()
+    {
+        return legendSet;
+    }
+
+    public void setLegendSet( MapLegendSet legendSet )
+    {
+        this.legendSet = legendSet;
+    }
+
     // -------------------------------------------------------------------------
     // Get- and set-methods for transient properties
     // -------------------------------------------------------------------------
@@ -990,6 +1009,7 @@
             digitGroupSeparator = reportTable.getDigitGroupSeparator();
             displayDensity = reportTable.getDisplayDensity();
             fontSize = reportTable.getFontSize();
+            legendSet = reportTable.getLegendSet();
             
             columnDimensions.clear();
             columnDimensions.addAll( reportTable.getColumnDimensions() );

=== modified file 'dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml'
--- dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml	2013-05-15 10:10:47 +0000
+++ dhis-2/dhis-services/dhis-service-reporting/src/main/resources/org/hisp/dhis/reporttable/hibernate/ReportTable.hbm.xml	2013-06-05 20:11:33 +0000
@@ -144,6 +144,9 @@
     
     <property name="userOrganisationUnitChildren" />
 
+    <many-to-one name="legendSet" class="org.hisp.dhis.mapping.MapLegendSet" column="legendsetid"
+		cascade="all" foreign-key="fk_reporttable_legendsetid" />
+
     <!-- Access properties -->
     <many-to-one name="user" class="org.hisp.dhis.user.User" column="userid" foreign-key="fk_reporttable_userid" />
 

=== modified file 'dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java'
--- dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java	2013-06-05 12:45:22 +0000
+++ dhis-2/dhis-web/dhis-web-api/src/main/java/org/hisp/dhis/api/controller/ReportTableController.java	2013-06-05 20:11:33 +0000
@@ -47,6 +47,7 @@
 import org.hisp.dhis.i18n.I18nFormat;
 import org.hisp.dhis.i18n.I18nManager;
 import org.hisp.dhis.indicator.IndicatorService;
+import org.hisp.dhis.mapping.MappingService;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitGroupService;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java	2013-06-03 18:55:28 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/java/org/hisp/dhis/pivot/action/InitializeAction.java	2013-06-05 20:11:33 +0000
@@ -37,6 +37,7 @@
 import org.hisp.dhis.common.DimensionService;
 import org.hisp.dhis.i18n.I18nFormat;
 import org.hisp.dhis.mapping.MapLegendSet;
+import org.hisp.dhis.mapping.MappingService;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitService;
 import org.hisp.dhis.period.Period;
@@ -76,6 +77,13 @@
     {
         this.dimensionService = dimensionService;
     }
+    
+    private MappingService mappingService;
+
+    public void setMappingService( MappingService mappingService )
+    {
+        this.mappingService = mappingService;
+    }
 
     private I18nFormat format;
 
@@ -235,6 +243,8 @@
         last5Years = periodService.reloadPeriods( setNames( rp.getRelativePeriods() ) );
         
         dimensions = dimensionService.getAllDimensions();
+        
+        legendSets = mappingService.getAllMapLegendSets();
 
         return SUCCESS;
     }

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml	2013-06-03 18:55:28 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/resources/META-INF/dhis/beans.xml	2013-06-05 20:11:33 +0000
@@ -16,6 +16,7 @@
     <property name="periodService" ref="org.hisp.dhis.period.PeriodService" />
     <property name="organisationUnitService" ref="org.hisp.dhis.organisationunit.OrganisationUnitService" />
     <property name="dimensionService" ref="org.hisp.dhis.common.DimensionService" />
+    <property name="mappingService" ref="org.hisp.dhis.mapping.MappingService" />
   </bean>
 
   <!-- OrganisationUnit -->

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module.properties	2013-06-03 18:55:28 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module.properties	2013-06-05 20:11:33 +0000
@@ -120,4 +120,5 @@
 data_sets_cannot_be_specified_as_filter=Data sets cannot be specified as filter
 share=Share
 interpretation=interpretation
-write_your_interpretation=Write a comment, question or interpretation
\ No newline at end of file
+write_your_interpretation=Write a comment, question or interpretation
+legend_set=Legend set
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module_fr_FR.properties'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module_fr_FR.properties	2013-06-03 18:55:28 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/resources/org/hisp/dhis/pivot/i18n_module_fr_FR.properties	2013-06-05 20:11:33 +0000
@@ -115,4 +115,5 @@
 graphics=Graphique
 data_sets_cannot_be_specified_as_filter=Ensembles de donn\u00E9es ne peuvent \u00EAtre d\u00E9finies comme filtre
 share=Partager
-interpretation=interpr\u00E9tation
\ No newline at end of file
+interpretation=interpr\u00E9tation
+legend_set=Jeu de l\u00E9gendes
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js	2013-06-05 17:12:40 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/app.js	2013-06-05 20:11:33 +0000
@@ -24,6 +24,7 @@
 	PT.app.getInits = function(r) {
 		var init = Ext.decode(r.responseText);
 
+		// Root nodes
 		for (var i = 0; i < init.rootNodes.length; i++) {
 			init.rootNodes[i].path = '/' + pt.conf.finals.root.id + '/' + init.rootNodes[i].id;
 		}
@@ -38,6 +39,14 @@
 			pt.conf.finals.dimension.objectNameMap[dim.id] = dim;
 		}
 
+		// Legend set map
+		init.idLegendSetMap = {};
+
+		for (var i = 0, set; i < init.legendSets.length; i++) {
+			set = init.legendSets[i];
+			init.idLegendSetMap[set.id] = set;
+		}
+
 		// Viewport afterrender
 		init.afterRender = function() {
 
@@ -266,9 +275,6 @@
 			},
 			listeners: {
 				load: function(s) {
-					//s.each( function(r) {
-						//r.data.name = pt.conf.util.jsonEncodeString(r.data.name);
-					//});
 					pt.util.store.addToStorage(s);
 					pt.util.multiselect.filterAvailable({store: s}, {store: store.indicatorSelected});
 				}
@@ -296,9 +302,6 @@
 			},
 			listeners: {
 				load: function(s) {
-					//s.each( function(r) {
-						//r.data.name = pt.conf.util.jsonEncodeString(r.data.name);
-					//});
 					pt.util.store.addToStorage(s);
 					pt.util.multiselect.filterAvailable({store: s}, {store: store.dataElementSelected});
 				}
@@ -328,9 +331,7 @@
 			listeners: {
 				load: function(s) {
 					this.isLoaded = true;
-					//s.each( function(r) {
-						//r.data.name = pt.conf.util.jsonEncodeString(r.data.name);
-					//});
+
 					pt.util.store.addToStorage(s);
 					pt.util.multiselect.filterAvailable({store: s}, {store: store.dataSetSelected});
 				}
@@ -365,7 +366,7 @@
 			data: []
 		});
 
-		store.tables = Ext.create('Ext.data.Store', {
+		store.reportTable = Ext.create('Ext.data.Store', {
 			fields: ['id', 'name', 'lastUpdated', 'access'],
 			proxy: {
 				type: 'ajax',
@@ -407,6 +408,19 @@
 			}
 		});
 
+		store.legendSet = Ext.create('Ext.data.Store', {
+			fields: ['id', 'name', 'index'],
+			data: function() {
+				var data = pt.init.legendSets;
+				data.unshift({id: 0, name: PT.i18n.none, index: -1});
+				return data;
+			}(),
+			sorters: [
+				{property: 'index', direction: 'ASC'},
+				{property: 'name', direction: 'ASC'}
+			]
+		});
+
 		return store;
 	};
 
@@ -869,6 +883,20 @@
 		});
 		pt.viewport.digitGroupSeparator = digitGroupSeparator;
 
+		legendSet = Ext.create('Ext.form.field.ComboBox', {
+			cls: 'pt-combo',
+			style: 'margin-bottom:3px',
+			width: 250,
+			labelWidth: 130,
+			fieldLabel: PT.i18n.legend_set,
+			valueField: 'id',
+			displayField: 'name',
+			editable: false,
+			value: 0,
+			store: pt.store.legendSet
+		});
+		pt.viewport.legendSet = legendSet;
+
 		reportingPeriod = Ext.create('Ext.form.field.Checkbox', {
 			boxLabel: PT.i18n.reporting_period,
 			style: 'margin-bottom:4px',
@@ -946,7 +974,6 @@
 		});
 		pt.viewport.topLimit = topLimit;
 
-
 		data = {
 			bodyStyle: 'border:0 none',
 			style: 'margin-left:14px',
@@ -963,7 +990,8 @@
 			items: [
 				displayDensity,
 				fontSize,
-				digitGroupSeparator
+				digitGroupSeparator,
+				legendSet
 			]
 		};
 
@@ -997,6 +1025,7 @@
 					displayDensity: displayDensity.getValue(),
 					fontSize: fontSize.getValue(),
 					digitGroupSeparator: digitGroupSeparator.getValue(),
+					legendSet: {id: legendSet.getValue()},
 					reportingPeriod: reportingPeriod.getValue(),
 					organisationUnit: organisationUnit.getValue(),
 					parentOrganisationUnit: parentOrganisationUnit.getValue(),
@@ -1013,6 +1042,7 @@
 				displayDensity.setValue(Ext.isString(layout.displayDensity) ? layout.displayDensity : 'normal');
 				fontSize.setValue(Ext.isString(layout.fontSize) ? layout.fontSize : 'normal');
 				digitGroupSeparator.setValue(Ext.isString(layout.digitGroupSeparator) ? layout.digitGroupSeparator : 'space');
+				legendSet.setValue(Ext.isObject(layout.legendSet) && Ext.isString(layout.legendSet.id) ? layout.legendSet.id : 0);
 				reportingPeriod.setValue(Ext.isBoolean(layout.reportingPeriod) ? layout.reportingPeriod : false);
 				organisationUnit.setValue(Ext.isBoolean(layout.organisationUnit) ? layout.organisationUnit : false);
 				parentOrganisationUnit.setValue(Ext.isBoolean(layout.parentOrganisationUnit) ? layout.parentOrganisationUnit : false);
@@ -1070,6 +1100,10 @@
 					if (!w.hasHideOnBlurHandler) {
 						pt.util.window.addHideOnBlurHandler(w);
 					}
+
+					if (!legendSet.store.isLoaded) {
+						legendSet.store.load();
+					}
 				}
 			}
 		});
@@ -1107,7 +1141,7 @@
 			windowWidth = 500,
 			windowCmpWidth = windowWidth - 22;
 
-		pt.store.tables.on('load', function(store, records) {
+		pt.store.reportTable.on('load', function(store, records) {
 			var pager = store.proxy.reader.jsonData.pager;
 
 			info.setText('Page ' + pager.page + ' of ' + pager.pageCount);
@@ -1154,7 +1188,7 @@
 
 		NameWindow = function(id) {
 			var window,
-				record = pt.store.tables.getById(id);
+				record = pt.store.reportTable.getById(id);
 
 			nameTextfield = Ext.create('Ext.form.field.Text', {
 				height: 26,
@@ -1176,6 +1210,9 @@
 					var favorite = getBody();
 					favorite.name = nameTextfield.getValue();
 
+					//tmp
+					//delete favorite.legendSet;
+
 					if (favorite && favorite.name) {
 						Ext.Ajax.request({
 							url: pt.baseUrl + '/api/reportTables/',
@@ -1191,7 +1228,7 @@
 
 								pt.favorite = favorite;
 
-								pt.store.tables.loadStore();
+								pt.store.reportTable.loadStore();
 
 								//pt.viewport.interpretationButton.enable();
 
@@ -1220,6 +1257,9 @@
 								reportTable = Ext.decode(r.responseText);
 								reportTable.name = name;
 
+								//tmp
+								//delete reportTable.legendSet;
+
 								Ext.Ajax.request({
 									url: pt.baseUrl + '/api/reportTables/' + reportTable.id,
 									method: 'PUT',
@@ -1230,7 +1270,7 @@
 										alert(r.responseText);
 									},
 									success: function(r) {
-										pt.store.tables.loadStore();
+										pt.store.reportTable.loadStore();
 										window.destroy();
 									}
 								});
@@ -1306,7 +1346,7 @@
 
 						var value = this.getValue(),
 							url = value ? pt.baseUrl + '/api/reportTables/query/' + value + '.json?links=false' : null,
-							store = pt.store.tables;
+							store = pt.store.reportTable;
 
 						store.page = 1;
 						store.loadStore(url);
@@ -1320,7 +1360,7 @@
 			handler: function() {
 				var value = searchTextfield.getValue(),
 					url = value ? pt.baseUrl + '/api/reportTables/query/' + value + '.json?links=false' : null,
-					store = pt.store.tables;
+					store = pt.store.reportTable;
 
 				store.page = store.page <= 1 ? 1 : store.page - 1;
 				store.loadStore(url);
@@ -1332,7 +1372,7 @@
 			handler: function() {
 				var value = searchTextfield.getValue(),
 					url = value ? pt.baseUrl + '/api/reportTables/query/' + value + '.json?links=false' : null,
-					store = pt.store.tables;
+					store = pt.store.reportTable;
 
 				store.page = store.page + 1;
 				store.loadStore(url);
@@ -1419,7 +1459,7 @@
 												success: function() {
 													pt.favorite = favorite;
 													pt.viewport.interpretationButton.enable();
-													pt.store.tables.loadStore();
+													pt.store.reportTable.loadStore();
 												}
 											});
 										}
@@ -1472,7 +1512,7 @@
 											url: pt.baseUrl + '/api/reportTables/' + record.data.id,
 											method: 'DELETE',
 											success: function() {
-												pt.store.tables.loadStore();
+												pt.store.reportTable.loadStore();
 											}
 										});
 									}
@@ -1486,7 +1526,7 @@
 					width: 6
 				}
 			],
-			store: pt.store.tables,
+			store: pt.store.reportTable,
 			bbar: [
 				info,
 				'->',
@@ -1503,7 +1543,7 @@
 					this.store.page = 1;
 					this.store.loadStore();
 
-					pt.store.tables.on('load', function() {
+					pt.store.reportTable.on('load', function() {
 						if (this.isVisible()) {
 							this.fireEvent('afterrender');
 						}

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js	2013-06-03 18:55:28 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/scripts/core.js	2013-06-05 20:11:33 +0000
@@ -239,7 +239,7 @@
 		displayDensity: {
 			'compact': '3px',
 			'normal': '5px',
-			'comfortable': '10px'
+			'comfortable': '10px',
 		},
 		fontSize: {
 			'small': '10px',
@@ -483,14 +483,14 @@
 			return (tmp.indexOf(".") > -1) ? (tmp.length - tmp.indexOf(".") - 1) : 0;
 		},
 
-		roundIf: function(x, fix) {
+		roundIf: function(x, prec) {
 			if (Ext.isString(x)) {
 				x = parseFloat(x);
 			}
 
-			if (Ext.isNumber(x) && Ext.isNumber(fix)) {
+			if (Ext.isNumber(x) && Ext.isNumber(prec)) {
 				var dec = pt.util.number.getNumberOfDecimals(x);
-				return parseFloat(dec > fix ? x.toFixed(fix) : x);
+				return parseFloat(dec > prec ? Ext.Number.toFixed(x, prec) : x);
 			}
 			return x;
 		},
@@ -506,6 +506,34 @@
 		}
 	};
 
+	util.color = {
+		hexToRgb: function(hex) {
+			var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
+			hex = hex.replace(shorthandRegex, function(m, r, g, b) {
+				return r + r + g + g + b + b;
+			});
+
+			var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
+			return result ? {
+				r: parseInt(result[1], 16),
+				g: parseInt(result[2], 16),
+				b: parseInt(result[3], 16)
+			} : null;
+		},
+		getContrast: function(hex) {
+			if (Ext.isString(hex)) {
+				var rgb = util.color.hexToRgb(hex),
+					factor = (rgb.r + rgb.g + rgb.b);
+
+				if (factor < 210) {
+					return '#ffffff';
+				}
+			}
+
+			return '#000000';
+		}
+	};
+
 	util.pivot = {
 		getExtendedLayout: function(layout) {
 			var dimConf = pt.conf.finals.dimension,
@@ -757,8 +785,8 @@
 
 		createTable: function(layout, pt) {
 			var dimConf = pt.conf.finals.dimension,
+				legendSet = layout.legendSet ? pt.init.idLegendSetMap[layout.legendSet.id] : undefined,
 				getSyncronizedXLayout,
-				//getParamString,
 				getExtendedResponse,
 				getExtendedAxis,
 				validateUrl,
@@ -1140,7 +1168,7 @@
 			validateUrl = function(url) {
 				if (!Ext.isString(url) || url.length > 2000) {
 					var percent = ((url.length - 2000) / url.length) * 100;
-					alert('Too many parameters selected. Please reduce the number of parameters by at least ' + percent.toFixed(0) + '%.');
+					alert('Too many parameters selected. Please reduce the number of parameters by at least ' + Ext.Number.toFixed(percent, 0) + '%.');
 					return;
 				}
 
@@ -1187,28 +1215,94 @@
 					htmlArray;
 
 				getTdHtml = function(config) {
-					var cls,
+					var bgColor,
+						legends,
+						cls,
 						colSpan,
 						rowSpan,
 						htmlValue,
 						displayDensity,
-						fontSize;
+						fontSize,
+						html = '',
+						isLegendSet = Ext.isObject(legendSet) && Ext.isArray(legendSet.legends) && legendSet.legends.length,
+						isValue = Ext.isString(config.type) && config.type.substr(0,5) === 'value' && !config.empty;
 
-					if (!(config && Ext.isObject(config))) {
+					if (!Ext.isObject(config)) {
 						return '';
 					}
 
-					cls = config.cls ? config.cls : '';
-					cls += config.hidden ? ' td-hidden' : '';
-					cls += config.collapsed ? ' td-collapsed' : '';
-					colSpan = config.colSpan ? 'colspan="' + config.colSpan + '"' : '';
-					rowSpan = config.rowSpan ? 'rowspan="' + config.rowSpan + '"' : '';
+					// Background color from legend set
+					if (isValue && isLegendSet) {
+						legends = legendSet.legends;
+
+						for (var i = 0, value; i < legends.length; i++) {
+							value = parseFloat(config.value);
+
+							if (Ext.Number.constrain(value, legends[i].sv, legends[i].ev) === value) {
+								bgColor = legends[i].color;
+							}
+						}
+					}
+
+					colSpan = config.colSpan ? 'colspan="' + config.colSpan + '" ' : '';
+					rowSpan = config.rowSpan ? 'rowspan="' + config.rowSpan + '" ' : '';
 					htmlValue = config.collapsed ? '&nbsp;' : config.htmlValue || config.value || '&nbsp;';
 					htmlValue = config.type !== 'dimension' ? pt.util.number.pp(htmlValue, layout.digitGroupSeparator) : htmlValue;
 					displayDensity = pt.conf.pivot.displayDensity[config.displayDensity] || pt.conf.pivot.displayDensity[layout.displayDensity];
 					fontSize = pt.conf.pivot.fontSize[config.fontSize] || pt.conf.pivot.fontSize[layout.fontSize];
 
-					return '<td class="' + cls + '" ' + colSpan + ' ' + rowSpan + ' style="padding:' + displayDensity + '; font-size:' + fontSize + ';">' + htmlValue + '</td>';
+					//var randomFromInterval = function(from,to) {
+						//return Math.floor(Math.random() * (to - from + 1) + from);
+					//};
+
+					//var a = ['#ff0000', '#e7ea22', '#00ff00'];
+
+					//var n = randomFromInterval(0,2);
+					//console.log(n);
+
+//if (Ext.isString(config.type) && config.type.substr(0,5) === 'value') {
+					//bgColor = a[n];
+				//}
+
+					if (bgColor) {
+						cls = 'legend';
+						cls += config.hidden ? ' td-hidden' : '';
+						cls += config.collapsed ? ' td-collapsed' : '';
+
+						html += '<td class="' + cls + '" ';
+						html += colSpan + rowSpan + '>';
+						html += '<div class="legendCt">';
+						html += '<div class="number ' + config.cls + '" style="padding:' + displayDensity + '; padding-right:3px; font-size:' + fontSize + '">' + htmlValue + '</div>';
+						html += '<div class="arrowCt ' + config.cls + '">';
+						html += '<div class="arrow" style="border-bottom:8px solid transparent; border-right:8px solid ' + bgColor + '">&nbsp;</div>';
+						html += '</div>';
+						html += '</div></div></td>';
+
+						//cls = 'legend';
+						//cls += config.hidden ? ' td-hidden' : '';
+						//cls += config.collapsed ? ' td-collapsed' : '';
+
+						//html += '<td class="' + cls + '" ';
+						//html += colSpan + rowSpan + '>';
+						//html += '<div class="legendCt">';
+						//html += '<div style="display:table-cell; padding:' + displayDensity + '; font-size:' + fontSize + '"';
+						//html += config.cls ? ' class="' + config.cls + '">' : '';
+						//html += htmlValue + '</div>';
+						//html += '<div class="legendColor" style="background-color:' + bgColor + '">&nbsp;</div>';
+						//html += '</div></td>';
+					}
+					else {
+						cls = config.cls ? config.cls : '';
+						cls += config.hidden ? ' td-hidden' : '';
+						cls += config.collapsed ? ' td-collapsed' : '';
+
+						html += '<td class="' + cls + '" ';
+						html += colSpan + rowSpan;
+						html += 'style="padding:' + displayDensity + '; font-size:' + fontSize + ';">' + htmlValue;
+						html += '</td>';
+					}
+
+					return html;
 				};
 
 				doSubTotals = function(xAxis) {
@@ -1839,8 +1933,9 @@
 					alert(r.responseText);
 				},
 				success: function(r) {
-					var layoutConfig = Ext.decode(r.responseText),
-						layout = pt.api.layout.Layout(layoutConfig);
+					var layoutConfig = Ext.decode(r.responseText);
+
+					var	layout = pt.api.layout.Layout(layoutConfig);
 
 					if (layout) {
 						pt.favorite = Ext.clone(layout);
@@ -1969,6 +2064,8 @@
 
 		// digitGroupSeparator: string ('space') - 'none', 'comma', 'space'
 
+		// legendSet: object
+
 		// userOrganisationUnit: boolean (false)
 
 		// userOrganisationUnitChildren: boolean (false)
@@ -2074,9 +2171,10 @@
 			layout.showSubTotals = Ext.isBoolean(config.subtotals) ? config.subtotals : (Ext.isBoolean(config.showSubTotals) ? config.showSubTotals : true);
 			layout.hideEmptyRows = Ext.isBoolean(config.hideEmptyRows) ? config.hideEmptyRows : false;
 
-			layout.displayDensity = Ext.isString(config.displayDensity) &&  !Ext.isEmpty(config.displayDensity) ? config.displayDensity : 'normal';
-			layout.fontSize = Ext.isString(config.fontSize) &&  !Ext.isEmpty(config.fontSize) ? config.fontSize : 'normal';
-			layout.digitGroupSeparator = Ext.isString(config.digitGroupSeparator) &&  !Ext.isEmpty(config.digitGroupSeparator) ? config.digitGroupSeparator : 'space';
+			layout.displayDensity = Ext.isString(config.displayDensity) && !Ext.isEmpty(config.displayDensity) ? config.displayDensity : 'normal';
+			layout.fontSize = Ext.isString(config.fontSize) && !Ext.isEmpty(config.fontSize) ? config.fontSize : 'normal';
+			layout.digitGroupSeparator = Ext.isString(config.digitGroupSeparator) && !Ext.isEmpty(config.digitGroupSeparator) ? config.digitGroupSeparator : 'space';
+			layout.legendSet = Ext.isObject(config.legendSet) && Ext.isString(config.legendSet.id) ? config.legendSet : undefined;
 
 			layout.userOrganisationUnit = isOu;
 			layout.userOrganisationUnitChildren = isOuc;

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css	2013-05-29 14:14:12 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/app/styles/style.css	2013-06-05 20:11:33 +0000
@@ -212,16 +212,32 @@
 	text-align: right;
 }
 
-td .good div {
-	background-color: #bbddbb;
-	color: #000;
-}
-td .medium div {
-
-}
-td .bad div {
-	background-color: #eacccc;
-	color: #000;
+	/* Legend */
+.pivot td.legend {
+	padding: 0;
+}
+
+.pivot div.legendCt {
+	display: table;
+	float: right;
+	width: 100%;
+}
+.pivot div.arrowCt {
+	display: table-cell;
+	vertical-align: top;
+	width: 8px;
+}
+.pivot div.arrow {
+	width: 0;
+	height: 0;
+}
+.pivot div.number {
+	display: table-cell;
+}
+
+.pivot div.legendColor {
+	display: table-cell;
+	width: 2px;
 }
 
 

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/i18n.vm'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/i18n.vm	2013-06-03 18:55:28 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/i18n.vm	2013-06-05 20:11:33 +0000
@@ -121,5 +121,6 @@
 	data_sets_cannot_be_specified_as_filter: '$encoder.jsEscape($i18n.getString( 'data_sets_cannot_be_specified_as_filter' ) , "'")',
 	share: '$encoder.jsEscape($i18n.getString( 'share' ) , "'")',
 	interpretation: '$encoder.jsEscape($i18n.getString( 'interpretation' ) , "'")',
-	write_your_interpretation: '$encoder.jsEscape($i18n.getString( 'write_your_interpretation' ) , "'")'
+	write_your_interpretation: '$encoder.jsEscape($i18n.getString( 'write_your_interpretation' ) , "'")',
+	legend_set: '$encoder.jsEscape($i18n.getString( 'legend_set' ) , "'")'
 };

=== modified file 'dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm'
--- dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm	2013-06-03 18:55:28 +0000
+++ dhis-2/dhis-web/dhis-web-pivot/src/main/webapp/dhis-web-pivot/jsonInitialize.vm	2013-06-05 20:11:33 +0000
@@ -4,5 +4,6 @@
 "ou":{"id":"$currentUser.getOrganisationUnit().uid","name":"$currentUser.getOrganisationUnit().name"},
 "ouc":[#foreach($ou in $currentUser.getOrganisationUnit().getSortedChildren()){"id":"$ou.uid","name":"$ou.name"}#if($velocityCount < $oucSize),#end#end]},
 "rootNodes":[#foreach($node in $rootNodes){"id": "$!{node.uid}","text": "$!encoder.jsonEncode( ${node.name} )","level": 1,"hasChildrenWithCoordinates": $!{node.hasChildrenWithCoordinates()},"expanded": true}#if($velocityCount<$rootNodes.size()),#end#end],
-"dimensions":[#foreach($dim in $dimensions){"id":"$!{dim.uid}","name":"$!encoder.jsonEncode($!{dim.name})"}#if($velocityCount<$dimensions.size()),#end#end]							
+"dimensions":[#foreach($dim in $dimensions){"id":"$!{dim.uid}","name":"$!encoder.jsonEncode($!{dim.name})"}#if($velocityCount<$dimensions.size()),#end#end],
+"legendSets":[#foreach($set in $legendSets){"id":"$!{set.uid}","name":"$!encoder.jsonEncode($!{set.name})", "legends":[#foreach($legend in $set.mapLegends){"id":"$!{legend.uid}","name":"$!{legend.name}","sv":"$!{legend.startValue}", "ev":"$!{legend.endValue}", "color":"$!{legend.color}"}#if($velocityCount<$set.mapLegends.size()),#end#end]}#if($velocityCount<$legendSets.size()),#end#end]
 }
\ No newline at end of file