(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();
}
});
})();