575 lines
18 KiB
JavaScript
Executable File
575 lines
18 KiB
JavaScript
Executable File
// reportOptions variable comes from respective config file
|
|
|
|
//var defaultFilterText = "type text to filter the chart";
|
|
// Array that stores objects for each element returned via rest
|
|
var chartsData;
|
|
var map;
|
|
|
|
var commasFixed2 = function(d) {return d3.format(",")(d.toFixed(2)); };
|
|
|
|
//var clickablePieChartLegend = "Pie Chart :: ";
|
|
//var detailedPieChartLegend = "Pie Chart :: ";
|
|
|
|
var clickableDOMId = "clickable-piechart";
|
|
var detailedDOMId = "detailed-piechart";
|
|
|
|
var lastSliceClicked = null;
|
|
|
|
function initPage() {
|
|
// function from generic.js, variable from config file
|
|
initHeaderAndFilters(headerAndFilters);
|
|
|
|
$("#content-body")
|
|
.append(
|
|
$("<div>").attr("id", clickableDOMId)
|
|
)
|
|
.append(
|
|
$("<div>").attr("id", detailedDOMId)
|
|
);
|
|
|
|
initSvg(clickableDOMId);
|
|
|
|
if (reportOptions.hasFriendlierNames) {
|
|
$("#content")
|
|
.append(
|
|
$("<div>")
|
|
.attr("id", "friendlier-names-field")
|
|
.append(
|
|
$("<input>")
|
|
.attr("id", "friendlier-names")
|
|
.attr("type", "checkbox")
|
|
.attr("disabled", false)
|
|
.prop("checked", true)
|
|
)
|
|
.append(
|
|
$("<label>")
|
|
.attr("for", "friendlier-names")
|
|
.attr("title", "Check to Switch to Friedlier Names")
|
|
.text("Friendlier Names")
|
|
.click(function() {
|
|
if (chartsData)
|
|
drawCharts();
|
|
})
|
|
)
|
|
);
|
|
}
|
|
|
|
if (reportOptions.hasDetailedMap) {
|
|
$("#" + detailedDOMId).parent().append(
|
|
$("<div>")
|
|
.attr("id", reportOptions.hasDetailedMap)
|
|
.addClass("hidden")
|
|
);
|
|
map = new SVGMap(reportOptions.hasDetailedMap, project.map);
|
|
map.hide();
|
|
}
|
|
|
|
updateWidth();
|
|
|
|
$("#filter").click(function() {
|
|
generateCharts();
|
|
});
|
|
|
|
//updateChartHeight();
|
|
generateCharts();
|
|
}
|
|
|
|
function generateCharts() {
|
|
chartsData = [];
|
|
|
|
// get the social club header filtering parameter values, headerAndFilters.headerType comes from local conf
|
|
var pValues = config.headerOptions[headerAndFilters.headerType].getParamValues();
|
|
|
|
if (reportOptions.hasExtraRestParams) {
|
|
$.each(reportOptions.hasExtraRestParams, function(i, paramObj) {
|
|
var value;
|
|
if (typeof paramObj.value === "function") {
|
|
value = paramObj.value();
|
|
}
|
|
else
|
|
value = paramObj.value;
|
|
pValues.Pairs[paramObj.key] = value;
|
|
});
|
|
}
|
|
|
|
if (reportOptions.hasDualEndpoints) {
|
|
|
|
var req = new ReportRequest(null, "json", null, config.restHost + config.reportsQueryAsync);
|
|
var endpointObject1 = {
|
|
restUrl: config.restHost + reportOptions.restEndpoint,
|
|
restAsyncUrl: config.restHost + reportOptions.restEndpointAsync,
|
|
pValues: [pValues],
|
|
}
|
|
var endpointObject2 = {
|
|
restUrl: config.restHost + reportOptions.restEndpoint2,
|
|
restAsyncUrl: config.restHost + reportOptions.restEndpoint2Async,
|
|
pValues: [pValues],
|
|
}
|
|
|
|
if ($("select#game-types option:eq(0)").is(":selected") && !$("select#game-types option:eq(1)").is(":selected")) {
|
|
req.sendMultipleAsyncRequest([endpointObject1], reportOptions.handleResults);
|
|
}
|
|
else if (!$("select#game-types option:eq(0)").is(":selected") && $("select#game-types option:eq(1)").is(":selected")) {
|
|
req.sendMultipleAsyncRequest([endpointObject2], reportOptions.handleResults);
|
|
}
|
|
else if ($("select#game-types").val() != null) {
|
|
if ($("select#game-types").val().length == 2) {
|
|
req.sendMultipleAsyncRequest([endpointObject1, endpointObject2], reportOptions.handleResults);
|
|
}
|
|
}
|
|
else if (!$("select#game-types").val()) {
|
|
req.sendMultipleAsyncRequest([endpointObject1, endpointObject2], reportOptions.handleResults);
|
|
}
|
|
|
|
} // End of if has dual end-points
|
|
else {
|
|
var req = new ReportRequest(config.restHost + reportOptions.restEndpoint,
|
|
"json",
|
|
config.restHost + reportOptions.restEndpointAsync + pValues.ForceUrlSuffix,
|
|
config.restHost + config.reportsQueryAsync);
|
|
|
|
req.sendSingleAsyncRequest(pValues, drawCharts);
|
|
}
|
|
|
|
} //end of generateCharts()
|
|
|
|
function cleanCharts() {
|
|
cleanGraph(clickableDOMId);
|
|
cleanDetailedChart();
|
|
// Unbind onResize event
|
|
if (typeof window.onresize === "function")
|
|
window.onresize = null;
|
|
//console.log(window.onresize);
|
|
}
|
|
|
|
function cleanDetailedChart() {
|
|
$("#" + detailedDOMId).hide("fade", {}, "normal");
|
|
$("#" + detailedDOMId).find("div").each(function() {
|
|
//console.log($(this).attr("id"));
|
|
cleanGraph($(this).attr("id"));
|
|
lastSliceClicked = null;
|
|
});
|
|
//cleanGraph(detailedDOMId);
|
|
if (map)
|
|
map.hide();
|
|
}
|
|
|
|
/*
|
|
function updateChartHeight() {
|
|
// Adjust the height of the charts automatically
|
|
//var windowHeight = $("#content").height() - 40;
|
|
var windowHeight = $("#content").height() - 2 * $("#sub-header").height();
|
|
$("#" + clickableDOMId).css("height", windowHeight);
|
|
$("#" + detailedDOMId).css("height", windowHeight);
|
|
if (reportOptions.hasDetailedMap)
|
|
$("#" + reportOptions.hasDetailedMap).css("height", windowHeight);
|
|
}
|
|
*/
|
|
|
|
function updateWidth() {
|
|
if (reportOptions.hasDetailedMap) {
|
|
//if ($(window).width() > 1366) {
|
|
|
|
$("#" + clickableDOMId).css("width", "33%");
|
|
$("#" + detailedDOMId)
|
|
.css("width", "33%")
|
|
//.css("left", "33%");
|
|
$("#" + reportOptions.hasDetailedMap)
|
|
.css("width", "33%")
|
|
//.css("left", "66%");
|
|
//}
|
|
//else {
|
|
// $("#" + clickableDOMId).css("width", "455");
|
|
// $("#" + detailedDOMId)
|
|
// .css("width", "455")
|
|
// .css("left", "455px !important");
|
|
// $("#" + reportOptions.hasDetailedMap)
|
|
// .css("width", "455")
|
|
// .css("left", "910px !important");
|
|
//}
|
|
}
|
|
}
|
|
|
|
function drawCharts(data) {
|
|
//cleanDetailedChart();
|
|
//$("#detailed-piechart").hide("fade", {}, "normal");
|
|
|
|
// If a processFunction function is specified
|
|
if (data) {
|
|
if (reportOptions.processFunction)
|
|
chartsData = reportOptions.processFunction(data);
|
|
else
|
|
chartsData = data;
|
|
}
|
|
|
|
totalValue = chartsData.reduce(function(a, b) { return (a + reportOptions.getValue(b)); }, 0);
|
|
//console.log(totalValue);
|
|
|
|
if ((chartsData.length < 1) || (totalValue == 0)) {
|
|
cleanCharts();
|
|
Sexy.alert(config.noDataText);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
var filterText = $("#chart-filter-input").val();
|
|
if (filterText == defaultFilterText)
|
|
filterText = "";
|
|
|
|
var re = new RegExp(filterText, "i");
|
|
|
|
// create an array that will store the filtered chart data
|
|
var filteredArray = [];
|
|
|
|
// loop to each element's data
|
|
$.each(chartsData, function(i, chartData) {
|
|
// match the name with the input filter text
|
|
if (re.test(reportOptions.getName(chartData))) {
|
|
// for each chart type, populate its array with the predefined functions over the data
|
|
chartData["Name"] = reportOptions.getName(chartData);
|
|
chartData["Value"] = reportOptions.getValue(chartData);
|
|
filteredArray.push(chartData);
|
|
}
|
|
});
|
|
|
|
if (filteredArray.length < 1) {
|
|
//console.log("Nothing matched for '" + filterText + "'");
|
|
cleanCharts();
|
|
return;
|
|
}
|
|
|
|
filteredArray.sort(function(a, b) { return (a.Value > b.Value) ? -1 : 1});
|
|
//console.log(filteredArray);
|
|
|
|
// Construct the chart data in a format that nvd3 understands
|
|
var datum = [{
|
|
values: filteredArray,
|
|
}];
|
|
*/
|
|
|
|
var datum = [{
|
|
values: chartsData
|
|
.filter(function(d) {
|
|
d.disabled = false; // for re-enabling the legend
|
|
return reportOptions.getValue(d) > 0; // filter out the 0 values
|
|
})
|
|
.sort(function(a, b) {
|
|
return ((reportOptions.getValue(a) > reportOptions.getValue(b)) ? -1 : 1);
|
|
}),
|
|
}];
|
|
|
|
nv.addGraph({
|
|
generate: function() {
|
|
|
|
var chart = nv.models.pieChart()
|
|
.x(function(d) { return reportOptions.getName(d); })
|
|
.y(function(d) { return reportOptions.getValue(d); })
|
|
.showLabels(true)
|
|
.pieLabelsOutside(reportOptions.pieLabelsOutside)
|
|
.labelSunbeamLayout(reportOptions.labelSunbeamLayout)
|
|
.showLegend(reportOptions.legend)
|
|
.donut(reportOptions.donut)
|
|
.donutLabelsOutside(reportOptions.donutLabelsOutside)
|
|
.margin({top: 0, right: reportOptions.lrMargin, bottom: 0, left: reportOptions.lrMargin})
|
|
.tooltipContent(function(key, y, e, graph) {
|
|
if (reportOptions.tooltipContent)
|
|
return reportOptions.tooltipContent(key, y, e, graph);
|
|
else {
|
|
var sum = d3.sum(graph.container.__data__[0].values, function(d) {
|
|
return (!d.disabled) ? reportOptions.getValue(d) : 0;
|
|
});
|
|
// Use e.value instead of y, y is a formated string and parsing to number fails
|
|
var percentage = ((e.value/sum)*100).toFixed(2);
|
|
|
|
return "<h3>" + key + "</h3>"
|
|
+ "<p>" + commasFixed2(e.value) + " " + reportOptions.unit
|
|
+ " - " + percentage + "%" + "<br />"
|
|
+ " (of " + commasFixed2(sum) + " " + reportOptions.unit +")" + "</p>";
|
|
}
|
|
});
|
|
|
|
/* Add on click events */
|
|
chart.pie.dispatch.on("elementClick", function(e) {
|
|
//var detailedDataObject = chartsData[e.index] || chartsData[e.label];
|
|
//var detailedDataObject = filteredArray[e.index];
|
|
detailedDataObject = e.point;
|
|
lastSliceClicked = e.label;
|
|
|
|
if (reportOptions.hasDetailedData(detailedDataObject)) {
|
|
// console.log(e);
|
|
//$("#detailed-piechart legend")
|
|
// .html(detailedPieChartLegend
|
|
// + "<span id='detailed-metric'>"
|
|
// + reportOptions.detailedTitle
|
|
// + e.label
|
|
// + "</span>"
|
|
// );
|
|
$("#" + detailedDOMId).show("fade", {}, "normal");
|
|
drawDetailedChart(detailedDataObject);
|
|
}
|
|
//else {
|
|
// Sexy.alert("No detailed data available for " + e.label + ".");
|
|
// cleanDetailedChart();
|
|
//}
|
|
});
|
|
|
|
var svg = d3.select("#" + clickableDOMId + " svg");
|
|
|
|
svg.datum(datum)
|
|
.transition()
|
|
.duration(config.transitionDuration)
|
|
.call(chart);
|
|
|
|
nv.utils.windowResize(chart.update);
|
|
//nv.utils.windowResize(updateChartHeight);
|
|
nv.utils.windowResize(function() {
|
|
drawDonutLabel(clickableDOMId, reportOptions.title);
|
|
decorateKeys(clickableDOMId);
|
|
});
|
|
|
|
/*
|
|
svg.select(".nv-pie")
|
|
.attr("filter", "url(#dropShadow)");
|
|
*/
|
|
|
|
return chart;
|
|
},
|
|
callback: function() {
|
|
drawDonutLabel(clickableDOMId, reportOptions.title);
|
|
decorateKeys(clickableDOMId);
|
|
|
|
//console.log(lastSliceClicked);
|
|
if (lastSliceClicked) {
|
|
var availableLabels = datum[0].values.map(function(d) { return reportOptions.getName(d); });
|
|
var searchIndex = availableLabels.indexOf(lastSliceClicked);
|
|
|
|
if (searchIndex != -1) {
|
|
drawDetailedChart(datum[0].values[searchIndex]);
|
|
}
|
|
else {
|
|
// clean it cause the previous selected item is not available
|
|
cleanDetailedChart();
|
|
}
|
|
}
|
|
|
|
},
|
|
});
|
|
//$("#" + clickableDOMId + " legend").text(clickablePieChartLegend + reportOptions.title);
|
|
|
|
}
|
|
|
|
function drawDetailedChart(selectedObject) {
|
|
// Construct the chart data in a format that nvd3 understands
|
|
|
|
//var placeholderHeight = $("#" + detailedDOMId).height() - 2 * $("#" + detailedDOMId + " legend").height();
|
|
var placeholderHeight = $("#" + detailedDOMId).height();
|
|
var detailedColumns = 2;
|
|
|
|
var detailedObjects = reportOptions.getDetailedObjects(selectedObject);
|
|
|
|
// Clean not needed previous svg's
|
|
var existingItems = $("#" + detailedDOMId).find("div");
|
|
if (existingItems.length > detailedObjects.length)
|
|
existingItems.slice(detailedObjects.length).remove();
|
|
|
|
$.each(detailedObjects, function(i, detailedObject) {
|
|
|
|
var detailedPiechartDOMId = detailedDOMId + "_" + i;
|
|
|
|
// This will add the svg on the first time
|
|
if ($("#" + detailedDOMId).find("#" + detailedPiechartDOMId).size() == 0) {
|
|
$("#" + detailedDOMId)
|
|
.append(
|
|
$("<div>").attr("id", detailedPiechartDOMId)
|
|
);
|
|
initSvg(detailedPiechartDOMId);
|
|
}
|
|
|
|
$("#" + detailedPiechartDOMId)
|
|
.removeClass().addClass(function() {return (i%2) ? "float-right" : "float-left"})
|
|
.css("width", function() {
|
|
// give max width to the first element in odd number of detailed piecharts
|
|
return (((i==0) && (detailedObjects.length%2)) || (detailedObjects.length == detailedColumns))
|
|
? "100%" : Math.floor(100/detailedColumns) + "%";
|
|
})
|
|
.css("height",function() {
|
|
return (detailedObjects.length == detailedColumns)
|
|
? Math.floor(placeholderHeight/ Math.round(detailedObjects.length))
|
|
: Math.floor(placeholderHeight/ Math.round(detailedObjects.length / detailedColumns))
|
|
})
|
|
|
|
var pieItems = detailedObject.Items.sort(function(a, b) {
|
|
return (reportOptions.getDetailedValue(a) > reportOptions.getDetailedValue(b)) ? -1 : 1
|
|
});
|
|
|
|
var datum = [{
|
|
values: pieItems,
|
|
}];
|
|
|
|
var hasDetailedLabel = reportOptions.getDetailedLabel && reportOptions.getDetailedLabel(detailedObject);
|
|
|
|
nv.addGraph({
|
|
generate: function() {
|
|
var chart = nv.models.pieChart()
|
|
.x(function(d) { return reportOptions.getDetailedName(d); })
|
|
.y(function(d) { return reportOptions.getDetailedValue(d); })
|
|
.showLabels(true)
|
|
//.labelThreshold(.04)
|
|
.pieLabelsOutside((hasDetailedLabel) ? false : reportOptions.detailedPieLabelsOutside)
|
|
.labelSunbeamLayout(reportOptions.detailedLabelSunbeamLayout)
|
|
.showLegend(reportOptions.detailedLegend)
|
|
.donut((hasDetailedLabel) ? false : reportOptions.detailedDonut)
|
|
.donutLabelsOutside((hasDetailedLabel) ? false : reportOptions.detailedDonutLabelsOutside)
|
|
.margin({top: 0, right: reportOptions.lrMargin, bottom: 0, left: reportOptions.lrMargin})
|
|
.tooltipContent(function(key, y, e, graph) {
|
|
if (reportOptions.tooltipContent)
|
|
return reportOptions.tooltipContent(key, y, e, graph);
|
|
else {
|
|
var sum = d3.sum(graph.container.__data__[0].values, function(d) {
|
|
return reportOptions.getDetailedValue(d);
|
|
});
|
|
// Use e.value instead of y, y is a formated string and parsing to number fails
|
|
var percentage = ((e.value/sum)*100).toFixed(2);
|
|
|
|
return "<h3>" + key + "</h3>"
|
|
+ "<p>" + commasFixed2(e.value) + " " + reportOptions.unit
|
|
+ " - " + percentage + "%" + "<br />"
|
|
+ " (of " + commasFixed2(sum) + " " + reportOptions.unit +")" + "</p>";
|
|
}
|
|
});
|
|
|
|
var svg = d3.select("#" + detailedPiechartDOMId + " svg");
|
|
|
|
svg.datum(datum)
|
|
.transition()
|
|
.duration(config.transitionDuration)
|
|
.call(chart);
|
|
|
|
nv.utils.windowResize(chart.update);
|
|
nv.utils.windowResize(function() {
|
|
decorateKeys(detailedPiechartDOMId);
|
|
});
|
|
|
|
//nv.utils.windowResize(updateChartHeight);
|
|
return chart;
|
|
},
|
|
callback: function() {
|
|
decorateKeys(detailedPiechartDOMId);
|
|
|
|
var svg = d3.select("#" + detailedPiechartDOMId + " svg");
|
|
|
|
svg.selectAll(".detailed-label").remove();
|
|
|
|
if (hasDetailedLabel) {
|
|
drawPieLabel(detailedPiechartDOMId, reportOptions.getDetailedLabel(detailedObject));
|
|
nv.utils.windowResize(function() {
|
|
drawPieLabel(detailedPiechartDOMId, reportOptions.getDetailedLabel(detailedObject));
|
|
});
|
|
}
|
|
else {
|
|
drawDonutLabel(detailedPiechartDOMId, lastSliceClicked);
|
|
nv.utils.windowResize(function() {
|
|
drawDonutLabel(detailedPiechartDOMId, lastSliceClicked);
|
|
});
|
|
}
|
|
|
|
if (reportOptions.hasDetailedMap && !reportOptions.getDetailedLabel(detailedObject)) {
|
|
svg.selectAll(".nv-slice").each(function(d, i) {
|
|
//colours.push(d3.select(this).attr("fill"));
|
|
pieItems[i]["Colour"] = d3.select(this).attr("fill");
|
|
});
|
|
drawMap(reportOptions.hasDetailedMap, pieItems);
|
|
}
|
|
|
|
}
|
|
});
|
|
|
|
});
|
|
}
|
|
|
|
function drawDonutLabel(elementID, labelText) {
|
|
var svg = d3.select("#" + elementID + " svg");
|
|
|
|
svg.selectAll(".donut-label").remove();
|
|
|
|
var legendHeight = svg.select(".nv-legendWrap");
|
|
legendHeight = (legendHeight[0][0]) ? legendHeight[0][0].getBoundingClientRect().height : 0;
|
|
|
|
svg.append("svg:text")
|
|
.attr("class", "donut-label")
|
|
.attr("x", $("#" + elementID).width() / 2)
|
|
.attr("y", (($("#" + elementID).height() - legendHeight) / 2) + legendHeight/2)
|
|
.attr("text-anchor", "middle")
|
|
.attr("stroke", 5)
|
|
.text(labelText);
|
|
}
|
|
|
|
function drawPieLabel(elementID, labelText) {
|
|
var svg = d3.select("#" + elementID + " svg");
|
|
|
|
svg.selectAll(".pie-label").remove();
|
|
|
|
svg.append("svg:text")
|
|
.attr("class", "pie-label")
|
|
.attr("x", $("#" + elementID).width() / 2)
|
|
.attr("y", ($("#" + elementID).height() - 10))
|
|
.attr("dy", 6)
|
|
.attr("text-anchor", "middle")
|
|
.attr("stroke", 5)
|
|
.text(labelText);
|
|
}
|
|
|
|
function decorateKeys(elementID) {
|
|
$("#" + elementID + " .nv-legend rect").remove();
|
|
|
|
var legend = d3.select("#" + elementID + " svg")
|
|
.select("g.nv-legend g");
|
|
if (!legend[0][0])
|
|
return;
|
|
|
|
var bbox = legend[0][0].getBBox();
|
|
var margin = 5;
|
|
|
|
legend.append("svg:rect")
|
|
.attr("x", bbox.x - margin)
|
|
.attr("y", bbox.y - margin)
|
|
.attr("width", bbox.width + 2*margin)
|
|
.attr("height", bbox.height + 2*margin)
|
|
.attr("rx", margin)
|
|
.attr("ry", margin)
|
|
.attr("pointer-events", "none");
|
|
}
|
|
|
|
function drawMap(elementId, dataObjects) {
|
|
map.show();
|
|
map.removeOverlay();
|
|
|
|
map.drawCircles(dataObjects, mapDataFunctions);
|
|
|
|
$("#export-map").remove();
|
|
|
|
$("#content-description").append(
|
|
$("<input />")
|
|
.attr("type", "button")
|
|
.attr("id", "export-map")
|
|
.attr("name", "export-map")
|
|
.attr("title", "Export current viewport to png")
|
|
.val("Export Map to PNG")
|
|
.css("float", "right")
|
|
.addClass("red-button hand")
|
|
.click(map.exportToImage)
|
|
);
|
|
|
|
if ($.browser.msie)
|
|
$("#export-map")
|
|
.addClass("hidden");
|
|
}
|
|
|
|
var mapDataFunctions = {
|
|
getValue: function(d) {return reportOptions.getDetailedValue(d); },
|
|
getName: function(d) {return d.Name; },
|
|
getX: function(d) {return d.StartCoordinates.X; },
|
|
getY: function(d) {return d.StartCoordinates.Y; },
|
|
getColour: function(d) {return d.Colour;},
|
|
}
|