370 lines
12 KiB
JavaScript
Executable File
370 lines
12 KiB
JavaScript
Executable File
/*
|
|
* Class NVD3CustomGraphs
|
|
*
|
|
* @elementId - the html DOM id
|
|
*
|
|
* Requires nv.d3.js, d3.v2.js
|
|
*/
|
|
|
|
var NVD3CustomGraphs = function() {
|
|
|
|
function drawPiechart(datum, elementId, graphOptions, onClick) {
|
|
//console.log(datum[0]);
|
|
totalValue = datum[0].values.reduce(function(a, b) { return (a + graphOptions.getValue(b)); }, 0);
|
|
|
|
if ((datum[0].values.length < 1) || (totalValue == 0)) {
|
|
cleanGraph(elementId);
|
|
return;
|
|
}
|
|
|
|
datum[0].values = datum[0].values.filter(function(d) {
|
|
d.disabled = false; // for re-enabling the legend
|
|
return (graphOptions.getValue(d)); // filter out the 0 values
|
|
});
|
|
|
|
if (graphOptions.sortByValueDesc) {
|
|
datum[0].values = datum[0].values.sort(function(a, b) {
|
|
return (graphOptions.getValue(a) < graphOptions.getValue(b)) ? 1 : -1;
|
|
});
|
|
}
|
|
|
|
if (graphOptions.getSortingValueAsc) {
|
|
datum[0].values = datum[0].values.sort(function(a, b) {
|
|
return (graphOptions.getSortingValueAsc(a) < graphOptions.getSortingValueAsc(b)) ? -1 : 1;
|
|
});
|
|
}
|
|
|
|
// Construct the chart data in a format that nvd3 understands
|
|
nv.addGraph({
|
|
generate: function() {
|
|
var chart = nv.models.pieChart()
|
|
.x(function(d) { return graphOptions.getName(d); })
|
|
.y(function(d) { return graphOptions.getValue(d); })
|
|
.showLabels(true)
|
|
.pieLabelsOutside(graphOptions.pieLabelsOutside)
|
|
.labelSunbeamLayout(graphOptions.labelSunbeamLayout)
|
|
.showLegend(graphOptions.legend)
|
|
.donut(graphOptions.donut)
|
|
.donutLabelsOutside(graphOptions.donutLabelsOutside)
|
|
.margin({top: 0, right: graphOptions.lrMargin, bottom: 0, left: graphOptions.lrMargin})
|
|
.tooltipContent(function(key, y, e, graph) {
|
|
if (graphOptions.tooltipContent)
|
|
return graphOptions.tooltipContent(key, y, e, graph);
|
|
else {
|
|
var sum = d3.sum(graph.container.__data__[0].values, function(d) {
|
|
return (!d.disabled) ? graphOptions.getValue(d) : 0;
|
|
});
|
|
|
|
var metadata = graph.container.__data__[0].metadata;
|
|
|
|
// Use e.value instead of y, y is a formated string and parsing to number fails
|
|
var percentage = ((e.value/sum)*100).toFixed(2);
|
|
var unit = (metadata && metadata.unit) ? metadata.unit : graphOptions.unit;
|
|
|
|
return "<h3>" + key + "</h3>"
|
|
+ "<p>" + commasFixed2(e.value) + " " + unit
|
|
+ " - " + percentage + "%" + "<br />"
|
|
+ " (of " + commasFixed2(sum) + " " + unit +")" + "</p>";
|
|
}
|
|
});
|
|
|
|
/* Add on click events */
|
|
var svg = d3.select("#" + elementId + " svg");
|
|
|
|
if (onClick && !graphOptions.clickFiltersMap) {
|
|
|
|
svg.classed("clickable", true);
|
|
|
|
chart.pie.dispatch.on("elementClick", function(e) {
|
|
var color;
|
|
|
|
svg.selectAll(".nv-slice").each(function(d, i) {
|
|
if (i === e.index) {
|
|
color = d3.select(this).attr("fill");
|
|
e["color"] = color;
|
|
return;
|
|
}
|
|
});
|
|
|
|
onClick(e);
|
|
});
|
|
}
|
|
|
|
if (graphOptions.clickFiltersMap
|
|
&& graphOptions.showOnMap
|
|
&& graphOptions.showOnMap(datum[0].metadata)) {
|
|
|
|
svg.classed("clickable", true);
|
|
|
|
chart.pie.dispatch.on("elementClick", function(e) {
|
|
|
|
drawMap(reportOptions.hasDetailedMap, graphOptions.getMapObjects([e.point]));
|
|
|
|
if (onClick) // forward the other click event
|
|
onClick(e);
|
|
});
|
|
}
|
|
|
|
svg.datum(datum)
|
|
.transition()
|
|
.duration(config.transitionDuration)
|
|
.call(chart);
|
|
|
|
nv.utils.windowResize(chart.update);
|
|
//nv.utils.windowResize(updateChartHeight);
|
|
nv.utils.windowResize(function() {
|
|
if (graphOptions.legend) {
|
|
decorateKeys(elementId);
|
|
}
|
|
if (datum[0].key) {
|
|
if (graphOptions.donut)
|
|
drawDonutLabel(elementId, datum[0].key)
|
|
else
|
|
drawPieLabel(elementId, datum[0].key)
|
|
}
|
|
});
|
|
|
|
//svg.select(".nv-pie")
|
|
// .attr("filter", "url(#dropShadow)");
|
|
|
|
return chart;
|
|
},
|
|
callback: function() {
|
|
applyDefaultStyle(elementId);
|
|
|
|
if (graphOptions.legend) {
|
|
decorateKeys(elementId);
|
|
}
|
|
if (datum[0].key) {
|
|
if (graphOptions.donut)
|
|
drawDonutLabel(elementId, datum[0].key)
|
|
else
|
|
drawPieLabel(elementId, datum[0].key)
|
|
}
|
|
|
|
var svg = d3.select("#" + elementId + " svg");
|
|
if (graphOptions.showOnMap && graphOptions.showOnMap(datum[0].metadata)) {
|
|
|
|
if (!graphOptions.mapKeepColours) {
|
|
svg.selectAll(".nv-slice").each(function(d, i) {
|
|
datum[0].values[i]["Colour"] = d3.select(this).attr("fill");
|
|
});
|
|
}
|
|
//else
|
|
// datum[0].values.map(function(d) { d["Colour"] = ""; return d;);
|
|
|
|
if (graphOptions.drawMapByDefault && graphOptions.getMapObjects(datum[0].values))
|
|
drawMap(reportOptions.hasDetailedMap, graphOptions.getMapObjects(datum[0].values));
|
|
}
|
|
},
|
|
});
|
|
}
|
|
|
|
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)
|
|
.attr("fill", "#999999")
|
|
.style("font-family", "Chalet-LondonSixty")
|
|
.style("font-size", "20px")
|
|
.style("line-height", "18px");
|
|
}
|
|
|
|
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)
|
|
.attr("fill", "#999999")
|
|
.style("font-family", "Chalet-LondonSixty")
|
|
.style("font-size", "14px")
|
|
.style("line-height", "14px");
|
|
}
|
|
|
|
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/2)
|
|
.attr("ry", margin/2)
|
|
.attr("pointer-events", "none")
|
|
.attr("fill", "transparent")
|
|
.attr("stroke", "#aaa")
|
|
.attr("stroke-width", "1px")
|
|
.attr("stroke-opacity", "1")
|
|
};
|
|
|
|
function applyDefaultStyle(elementID) {
|
|
var svg = d3.select("#" + elementID + " svg");
|
|
|
|
svg.selectAll("g.nv-slice text")
|
|
.attr("stroke", "none")
|
|
.attr("stroke-width", "0")
|
|
.style("font-size", "smaller");
|
|
|
|
svg.selectAll("g.nv-bar text")
|
|
.attr("fill", "#000000")
|
|
.attr("stroke", "none")
|
|
.attr("stroke-width", "0")
|
|
.style("font-size", "smaller")
|
|
|
|
svg.selectAll("g.nv-slice rect")
|
|
.style("fill", "transparent")
|
|
.style("stroke", "none")
|
|
.attr("stroke-width", "0")
|
|
|
|
svg.selectAll("g.nv-axis path")
|
|
.attr("stroke", "#000000")
|
|
.attr("stroke-width", "1")
|
|
}
|
|
|
|
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.breakdown.getValue(d); },
|
|
getX: function(d) {return reportOptions.mapGetX(d); },
|
|
getY: function(d) {return reportOptions.mapGetY(d); },
|
|
//getX: function(d) {return d.StartCoordinates.X; },
|
|
//getY: function(d) {return d.StartCoordinates.Y; },
|
|
getColour: function(d) {return d.Colour;},
|
|
getTooltipContent: reportOptions.mapTooltipContent,
|
|
}
|
|
|
|
function drawHorizBarchart(datum, elementId, graphOptions, onClick) {
|
|
if (graphOptions.sortByValueDesc) {
|
|
datum[0].values.sort(function(a, b) {
|
|
return (graphOptions.getValue(a) < graphOptions.getValue(b)) ? 1 : -1;
|
|
});
|
|
}
|
|
|
|
if (graphOptions.getSortingValueAsc) {
|
|
datum[0].values = datum[0].values.sort(function(a, b) {
|
|
return (graphOptions.getSortingValueAsc(a) < graphOptions.getSortingValueAsc(b)) ? -1 : 1;
|
|
});
|
|
}
|
|
|
|
nv.addGraph({
|
|
generate: function() {
|
|
var chart = nv.models.multiBarHorizontalChart()
|
|
.x(function(d) { return graphOptions.getName(d); })
|
|
.y(function(d) { return graphOptions.getValue(d); })
|
|
.margin({top: 20, right: 20, bottom: 50, left: graphOptions.leftMargin})
|
|
.showValues(true)
|
|
.tooltips(false)
|
|
.showControls(false)
|
|
.showLegend(false);
|
|
|
|
chart.yAxis
|
|
.axisLabel(graphOptions.getYLabel(datum[0]))
|
|
.tickFormat(d3.format(".02f"));
|
|
|
|
d3.select("#" + elementId + " svg")
|
|
.datum(datum)
|
|
.transition()
|
|
.duration(config.transitionDuration)
|
|
.call(chart);
|
|
|
|
nv.utils.windowResize(chart.update);
|
|
|
|
return chart;
|
|
},
|
|
callback: function() {
|
|
applyDefaultStyle(elementId);
|
|
|
|
if (graphOptions.matchColoursFromPieElement) {
|
|
matchColours(graphOptions.matchColoursFromPieElement, elementId);
|
|
}
|
|
|
|
if (graphOptions.addUnitsToBarchart) {
|
|
addUnitsToBarchart(elementId, graphOptions.unit);
|
|
}
|
|
|
|
}
|
|
});
|
|
}
|
|
|
|
function matchColours(piechartID, barchartID) {
|
|
|
|
var colours = [];
|
|
d3.select("#" + piechartID + " svg").selectAll(".nv-slice").each(function(d, i) {
|
|
colours.push(d3.select(this).attr("fill"));
|
|
});
|
|
|
|
d3.select("#" + barchartID + " svg").selectAll(".nv-bar").each(function(d, i) {
|
|
d3.select(this).attr("fill", colours[i]);
|
|
d3.select(this).attr("stroke", "none");
|
|
});
|
|
|
|
}
|
|
|
|
function addUnitsToBarchart(barchartID, unit) {
|
|
|
|
d3.select("#" + barchartID + " svg").selectAll(".nv-bar text").each(function(d, i) {
|
|
var originalText = d3.select(this).text();
|
|
d3.select(this).text(function() {
|
|
return (unit.trim() == "$") ? (unit + originalText) : (originalText + unit);
|
|
});
|
|
});
|
|
|
|
}
|
|
|
|
return {
|
|
drawPiechart: drawPiechart,
|
|
drawHorizBarchart: drawHorizBarchart,
|
|
};
|
|
|
|
};
|