Files
2025-09-29 00:52:08 +02:00

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,
};
};