286 lines
9.0 KiB
Plaintext
286 lines
9.0 KiB
Plaintext
<div id="finInfoGraphPlaceholder">
|
|
<div class="panel panel-white panel-compact otherside collapsible-vertical">
|
|
<div class='panel-heading'>
|
|
<span class='panel-title ui-expander'>
|
|
<a data-target="#graph-container">
|
|
<i class="panel-title-icon fa fa-bar-chart-o"></i><span>Financial Information</span>
|
|
</a>
|
|
</span>
|
|
</div>
|
|
<div class='panel-body table-light' id="graph-container">
|
|
<div class="row padding-sm">
|
|
<div class="graph-container form-group-margin" id="fin-info-graph-container" style="min-height: 260px; min-width: 400px;">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script type="text/javascript">
|
|
// 10 days
|
|
var BAR_WIDTH = 10 * 24 * 60 * 60 * 1000,
|
|
BAR_ALIGN = 'center';
|
|
|
|
var _internalData = null;
|
|
|
|
function initFinInfoGraph() {
|
|
$("#finInfoGraphPlaceholder .panel.collapsible-vertical a").on('click', function () {
|
|
toggleGraphPanel(this, false);
|
|
});
|
|
|
|
restoreUserFinInfoGraphPreferences();
|
|
}
|
|
|
|
function refreshFinInfoGraphData(data) {
|
|
_internalData = data;
|
|
|
|
buildFinInfoGraph();
|
|
}
|
|
|
|
function updateProjectedRevenueOnFinGraph(value) {
|
|
_internalData = _internalData || {};
|
|
_internalData.ProjectedRevenue = value || 0;
|
|
|
|
buildFinInfoGraph();
|
|
}
|
|
|
|
function updateProjectedExpenseOnFinGraph(value) {
|
|
_internalData = _internalData || {};
|
|
_internalData.TDDirectCosts = value || 0;
|
|
|
|
buildFinInfoGraph();
|
|
}
|
|
|
|
function updateRevenueAndExpenseOnFinGraph(revenue, expense) {
|
|
_internalData = _internalData || {};
|
|
_internalData.ProjectedRevenue = revenue || 0;
|
|
_internalData.TDDirectCosts = expense || 0;
|
|
|
|
buildFinInfoGraph();
|
|
}
|
|
|
|
function updateCostSavingsOnFinGraph(value) {
|
|
_internalData = _internalData || {};
|
|
_internalData.CostSavings = value || 0;
|
|
|
|
buildFinInfoGraph();
|
|
}
|
|
|
|
function buildFinInfoGraph() {
|
|
// we should recreate plot container each time when we refresh it, because pixel plot create wrapper around div
|
|
// and push into it some additional information; so if we use original container few times we will have few containers with plot information
|
|
$('#fin-info-graph-container').html('<div id="fin-info-graph"></div>');
|
|
$('#fin-info-graph').pixelPlot(getGraphSeries(), {
|
|
xaxis: {
|
|
mode: "time",
|
|
timeformat: "%b %Y",
|
|
tickSize: [1, "month"],
|
|
tickLength: 0,
|
|
rotateTicks: 90
|
|
},
|
|
yaxes: [
|
|
{
|
|
axisLabel: "SPEND OVER TIME",
|
|
axisLabelUseCanvas: true,
|
|
axisLabelFontSizePixels: 11,
|
|
axisLabelFontFamily: 'Verdana, Arial',
|
|
axisLabelPadding: 10
|
|
}, {
|
|
axisLabel: "EXPENDITURE COST",
|
|
axisLabelUseCanvas: true,
|
|
axisLabelFontSizePixels: 11,
|
|
axisLabelFontFamily: 'Verdana, Arial',
|
|
axisLabelPadding: 10,
|
|
position: "right"
|
|
}
|
|
],
|
|
grid: {
|
|
hoverable: true,
|
|
borderWidth: 3,
|
|
backgroundColor: { colors: ["#878787", "#444444"] }
|
|
}
|
|
}, {
|
|
height: 350,
|
|
tooltipText: 'getToolTip(x, y)'
|
|
});
|
|
}
|
|
|
|
function getToolTip(x, y) {
|
|
var date = (new Date(x)).toString().split(' ');
|
|
return '$' + y.toFixed(2) + ' at ' + date[1] + ' ' + date[3];
|
|
}
|
|
|
|
function prepareGraphData() {
|
|
var data = _internalData || {};
|
|
|
|
var graphData = {
|
|
ECExpense: [],
|
|
TotalExpense: [],
|
|
ProjectedRevenue: [],
|
|
TDDIrectCost: [],
|
|
CostSavings: []
|
|
};
|
|
|
|
var total = 0;
|
|
for (var key in data.ECExpense || {}) {
|
|
total += (data.ECExpense[key] || 0);
|
|
graphData.ECExpense.push([key, data.ECExpense[key]]);
|
|
graphData.TotalExpense.push([key, total]);
|
|
}
|
|
|
|
if (graphData.ECExpense.length > 0) {
|
|
var tenDays = (10 * 24 * 60 * 60 * 1000),
|
|
endDate = parseInt(graphData.ECExpense[graphData.ECExpense.length - 1][0]) + tenDays;
|
|
|
|
var expense = parseFloat(data.TDDirectCosts || 0);
|
|
if (expense > 0)
|
|
graphData.TDDIrectCost.push([endDate, expense]);
|
|
|
|
// if expense exists we should show revenue and/or cost savings right after it
|
|
if (graphData.TDDIrectCost.length > 0)
|
|
endDate += tenDays;
|
|
|
|
if (data.IsRevenueGenerating === true) {
|
|
var revenue = parseFloat(data.ProjectedRevenue || 0);
|
|
if (revenue > 0)
|
|
graphData.ProjectedRevenue.push([endDate, revenue]);
|
|
}
|
|
|
|
var costSavings = parseFloat(data.CostSavings || 0);
|
|
if (costSavings > 0)
|
|
graphData.CostSavings.push([endDate, costSavings]);
|
|
}
|
|
|
|
return graphData;
|
|
}
|
|
|
|
function getGraphSeries() {
|
|
var graphData = prepareGraphData();
|
|
if (!graphData)
|
|
return;
|
|
|
|
var colors = {
|
|
ECExpenseColor: '#9d9d9d',
|
|
TotalExpenseColor: '#3156be',
|
|
CostSavingsColor: '#e8e64e',
|
|
RevenueColor: '#71c73e',
|
|
ExpenseColor: '#d54848',
|
|
};
|
|
|
|
var headers = [{
|
|
label: "Expenditure Cost",
|
|
data: graphData.ECExpense,
|
|
type: "Cost",
|
|
stack: false,
|
|
color: colors.ECExpenseColor,
|
|
lines: {
|
|
show: true,
|
|
fill: true
|
|
},
|
|
yaxis: 2
|
|
}, {
|
|
label: "Total Cost",
|
|
data: graphData.TotalExpense,
|
|
type: "Cost",
|
|
stack: false,
|
|
color: colors.TotalExpenseColor,
|
|
bars: {
|
|
show: true,
|
|
align: BAR_ALIGN,
|
|
barWidth: BAR_WIDTH,
|
|
lineWidth: 1,
|
|
fill: true
|
|
}
|
|
}];
|
|
|
|
if (graphData.TDDIrectCost.length > 0) {
|
|
headers.push({
|
|
label: "Projected Expense",
|
|
data: graphData.TDDIrectCost,
|
|
type: "Cost",
|
|
stack: false,
|
|
color: colors.ExpenseColor,
|
|
bars: {
|
|
show: true,
|
|
align: BAR_ALIGN,
|
|
barWidth: BAR_WIDTH,
|
|
lineWidth: 1,
|
|
fill: true
|
|
}
|
|
});
|
|
}
|
|
|
|
if (graphData.CostSavings.length > 0) {
|
|
headers.push({
|
|
label: "Cost Savings",
|
|
data: graphData.CostSavings,
|
|
type: "Cost",
|
|
stack: true,
|
|
color: colors.CostSavingsColor,
|
|
bars: {
|
|
show: true,
|
|
align: BAR_ALIGN,
|
|
barWidth: BAR_WIDTH,
|
|
lineWidth: 1,
|
|
fill: true
|
|
}
|
|
});
|
|
}
|
|
|
|
if (graphData.ProjectedRevenue.length > 0) {
|
|
headers.push({
|
|
label: "Projected Revenue",
|
|
data: graphData.ProjectedRevenue,
|
|
type: "Cost",
|
|
stack: true,
|
|
color: colors.RevenueColor,
|
|
bars: {
|
|
show: true,
|
|
align: BAR_ALIGN,
|
|
barWidth: BAR_WIDTH,
|
|
lineWidth: 1,
|
|
fill: true
|
|
}
|
|
});
|
|
}
|
|
|
|
return headers;
|
|
}
|
|
|
|
function toggleGraphPanel(chevron) {
|
|
var isCollapsed = $(chevron).hasClass("collapsed");
|
|
$(chevron).toggleClass("collapsed");
|
|
|
|
if (!isCollapsed) {
|
|
var panelBody = $(chevron).closest(".panel-compact").find(".panel-body");
|
|
$(chevron).parents('.panel').find(".row.padding-sm").slideUp();
|
|
}
|
|
else {
|
|
$(chevron).parents('.panel').find(".row.padding-sm").slideDown();
|
|
}
|
|
|
|
var prefs = [{
|
|
Key: "graph-panel-collapsed",
|
|
Value: !isCollapsed
|
|
}];
|
|
|
|
saveUserPagePreferences(prefs, getDataSection($("#finInfoGraphPlaceholder")), '/Scenarios/Details');
|
|
if (isCollapsed)
|
|
buildFinInfoGraph();
|
|
}
|
|
|
|
function restoreUserFinInfoGraphPreferences() {
|
|
var prefs = loadUserPagePreferences(getDataSection($("#finInfoGraphPlaceholder")), '/Scenarios/Details');
|
|
if (!!prefs && prefs.length > 0) {
|
|
for (var i = 0; i < prefs.length; i++) {
|
|
switch (prefs[i].Key) {
|
|
case "graph-panel-collapsed":
|
|
if (prefs[i].Value == true) {
|
|
$("#finInfoGraphPlaceholder .panel.collapsible-vertical a").trigger('click');
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script> |