(function() { var Ext = window.Ext4 || window.Ext; /** * @private * Provides the functionality for calculating an artifacts health as represented by a color. * A simple example: * * @example * var colorObject = Rally.util.HealthColorCalculator.getHealthColor({ * startDate: new Date(2000, 2, 2), * endDate: new Date(2000, 3, 3), * asOfDate: new Date(2010, 2, 5), * percentComplete: 0.50 * }); * alert(colorObject.hex); * */ Ext.define('Rally.util.HealthColorCalculator', { requires: [], singleton: true, colors:{ red:{ label: 'Late', hex: '#F66349' }, green:{ label: 'On Track', hex: '#8DC63F' }, yellow:{ label: 'At Risk', hex: '#FAD200' }, white:{ label: 'Not Started', hex: '#E0E0E0' }, gray:{ label: 'Complete', hex: '#D1D1D1' } }, /** * @param {Object} config * @param {Date} config.startDate (days since the epoch or date type where Tomorrow()-Today() = 1.0 (real)) * @param {Date} config.endDate (same type as startDate) * @param {Date} config.asOfDate (same type as startDate) - Most often today. The naming of * this variable supports the idea that you may want to look * at the report as-of a certain date. All A2.0 reports will * support printing any report as-of a certain timestamp. * @param {Number} config.acceptanceStartDelay Defaults to 0.1 * (endDate - startDate) * @param {Number} config.warningDelay Defaults to 0.1 * (endDate - startDate) * @param {Boolean} config.inProgress Defaults to percentComplete > 0 * @param {Number} config.percentComplete a number between 0 and 1 * @return {Object} statusColor : * White (means that work is not expected to have started yet) * Green (going good) * Yellow (warning) * Red (in trouble) * Gray (work is 100% done) */ calculateHealthColor:function(config) { var colors = Rally.util.HealthColorCalculator.colors; var percentComplete = config.percentComplete * 100; //turn dates into days since epoch, so we don't have to do date math //also round start date to the beginning of the day, and end date to the end of the day var millisecondsInDay = 86400000; var startDate = config.startDate; var endDate = config.endDate; if(Ext.isString(startDate)){ startDate = new Date(Date.parse(startDate)); } if(Ext.isString(endDate)){ endDate = new Date(Date.parse(endDate)); } var startDay = startDate.getTime() / millisecondsInDay; startDay = Math.floor(startDay); var endDay = endDate.getTime() / millisecondsInDay; endDay = Math.ceil(endDay) - 0.01; var asOfDay = config.asOfDate.getTime() / millisecondsInDay; var defaultConfig = { acceptanceStartDelay: (endDay - startDay) * 0.2, warningDelay: (endDay - startDay) * 0.2, inProgress: percentComplete > 0 }; config = Ext.applyIf(Ext.clone(config), defaultConfig); // Special cases if (asOfDay < startDay) { return colors.white; } if ((asOfDay >= startDay) && (asOfDay <= (startDay + config.acceptanceStartDelay)) && (! config.inProgress)) { return colors.green; } if (asOfDay >= endDay) { if (percentComplete >= 100.0) { return colors.gray; } else { return colors.red; } } // Red var redXIntercept = startDay + config.acceptanceStartDelay + config.warningDelay; var redSlope = 100.0 / (endDay - redXIntercept); var redYIntercept = -1.0 * redXIntercept * redSlope; var redThreshold = redSlope * asOfDay + redYIntercept; if (percentComplete < redThreshold) { return colors.red; } // Yellow var yellowXIntercept = startDay + config.acceptanceStartDelay; var yellowSlope = 100 / (endDay - yellowXIntercept); var yellowYIntercept = -1.0 * yellowXIntercept * yellowSlope; var yellowThreshold = yellowSlope * asOfDay + yellowYIntercept; if (percentComplete < yellowThreshold) { return colors.yellow; } // Green return colors.green; }, calculateHealthColorForPortfolioItemData: function(recordData, percentDoneFieldName) { var today = this._getToday(); var config = { percentComplete: recordData[percentDoneFieldName], startDate: recordData.ActualStartDate || recordData.PlannedStartDate || today, asOfDate: today }; if(recordData[percentDoneFieldName] === 1){ config.endDate = recordData.ActualEndDate || recordData.PlannedEndDate || today; } else { config.endDate = recordData.PlannedEndDate || today; } config.inProgress = config.percentComplete > 0; return this.calculateHealthColor(config); }, calculateCapacityHealthColor: function(recordData, percentDoneFieldName) { var percent = (recordData[percentDoneFieldName] || 0) * 100.0; if (percent >= 100) { return Rally.util.HealthColorCalculator.colors.red; } else if (percent >= 80) { return Rally.util.HealthColorCalculator.colors.yellow; } else if (percent > 0) { return Rally.util.HealthColorCalculator.colors.green; } return Rally.util.HealthColorCalculator.colors.gray; }, _getToday:function() { return new Date(); } }); })();