|
//////////////////////////////////////////////////////////// |
|
//////////////////////// Set-up //////////////////////////// |
|
//////////////////////////////////////////////////////////// |
|
|
|
//How many pixels should the two halves be pulled apart |
|
var pullOutSize; |
|
|
|
var screenWidth = $(window).innerWidth(), |
|
mobileScreen = (screenWidth > 500 ? false : true); |
|
|
|
var margin = {left: 50, top: 10, right: 50, bottom: 10}, |
|
width = Math.min(screenWidth, 800) - margin.left - margin.right, |
|
height = (mobileScreen ? 300 : Math.min(screenWidth, 800)*5/6) - margin.top - margin.bottom; |
|
|
|
var svg = d3.select("#chart").append("svg") |
|
.attr("width", (width + margin.left + margin.right)) |
|
.attr("height", (height + margin.top + margin.bottom)); |
|
|
|
var wrapper = svg.append("g").attr("class", "chordWrapper") |
|
.attr("transform", "translate(" + (width / 2 + margin.left) + "," + (height / 2 + margin.top) + ")");; |
|
|
|
var outerRadius = Math.min(width, height) / 2 - (mobileScreen ? 80 : 100), |
|
innerRadius = outerRadius * 0.95, |
|
opacityDefault = 0.7, //default opacity of chords |
|
opacityLow = 0.02; //hover opacity of those chords not hovered over |
|
|
|
//How many pixels should the two halves be pulled apart |
|
pullOutSize = (mobileScreen? 20 : 50) |
|
|
|
////////////////////////////////////////////////////// |
|
//////////////////// Titles on top /////////////////// |
|
////////////////////////////////////////////////////// |
|
|
|
var titleWrapper = svg.append("g").attr("class", "chordTitleWrapper"), |
|
titleOffset = mobileScreen ? 15 : 40, |
|
titleSeparate = mobileScreen ? 30 : 0; |
|
|
|
//Title top left |
|
titleWrapper.append("text") |
|
.attr("class","title left") |
|
.style("font-size", mobileScreen ? "12px" : "16px" ) |
|
.attr("x", (width/2 + margin.left - outerRadius - titleSeparate)) |
|
.attr("y", titleOffset) |
|
.text("Team dat het ticket initieel ontvangt"); |
|
titleWrapper.append("line") |
|
.attr("class","titleLine left") |
|
.attr("x1", (width/2 + margin.left - outerRadius - titleSeparate)*0.6) |
|
.attr("x2", (width/2 + margin.left - outerRadius - titleSeparate)*1.4) |
|
.attr("y1", titleOffset+8) |
|
.attr("y2", titleOffset+8); |
|
//Title top right |
|
titleWrapper.append("text") |
|
.attr("class","title right") |
|
.style("font-size", mobileScreen ? "12px" : "16px" ) |
|
.attr("x", (width/2 + margin.left + outerRadius + titleSeparate)) |
|
.attr("y", titleOffset) |
|
.text("Team dat het ticket oplost"); |
|
titleWrapper.append("line") |
|
.attr("class","titleLine right") |
|
.attr("x1", (width/2 + margin.left - outerRadius - titleSeparate)*0.6 + 2*(outerRadius + titleSeparate)) |
|
.attr("x2", (width/2 + margin.left - outerRadius - titleSeparate)*1.4 + 2*(outerRadius + titleSeparate)) |
|
.attr("y1", titleOffset+8) |
|
.attr("y2", titleOffset+8); |
|
|
|
//////////////////////////////////////////////////////////// |
|
////////////////////////// Data //////////////////////////// |
|
//////////////////////////////////////////////////////////// |
|
|
|
var Names = ["Domein LoFi","Domein HR","Domein ICTS","Fac. Communicatie/samenwerking","Domein Onderzoek","Servicepunt","Ondersteuning Lokale Infrastructuur","Other", "", |
|
"Other.in","Domein onderwijs.in","CCBI.in","Servicepunt.in","Domein ICTS.in","Domein LoFi.in","Domein HR.in",""]; |
|
|
|
var respondents = 5429, //Total number of respondents (i.e. the number that make up the total group |
|
emptyPerc = 0.5, //What % of the circle should become empty |
|
emptyStroke = Math.round(respondents*emptyPerc); |
|
var matrix = [ |
|
[0, 0,0,0,0,0,0,0, 0, 22, 5, 1, 823, 1, 1326, 13, 0], // Domein LoFi |
|
[0, 0,0,0,0,0,0,0, 0, 8, 3, 17, 344, 8, 2, 1345, 0], // Domein HR |
|
[0, 0,0,0,0,0,0,0, 0, 17, 15, 1, 104, 1263, 29, 7, 0], // Domein ICTS |
|
[0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 0, 15, 0], // Fac. Communicatie/samenwerking |
|
[0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 1, 10, 1, 0], // Domein Onderzoek |
|
[0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 2, 2, 6, 0], // Servicepunt |
|
[0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 0, 3, 6, 0], // Ondersteuning Lokale Infrastructuur |
|
[0, 0,0,0,0,0,0,0, 0, 0, 0, 0, 0, 6, 13, 10, 0], // Other |
|
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,emptyStroke], //dummyBottom |
|
[22, 8, 17, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0, 0], //Other.in |
|
[5, 3, 15, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0, 0], //Domein onderwijs.in |
|
[1, 17, 1, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0, 0], //CCBI.in |
|
[823, 344, 104, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0,0, 0], //Servicepunt.in |
|
[1, 8, 1263, 0, 1, 2, 0, 6, 0, 0,0,0,0,0,0,0, 0], //Domein ICTS.in |
|
[1326, 2, 29, 0, 10, 2, 3, 13, 0, 0,0,0,0,0,0,0, 0], //Domein LoFi.in |
|
[13, 1345, 7, 15, 1, 6, 6, 10, 0, 0,0,0,0,0,0,0, 0], //Domein HR.in |
|
[0,0,0,0,0,0,0,0,emptyStroke,0,0,0,0,0,0,0,0] //dummyTop |
|
]; |
|
//Calculate how far the Chord Diagram needs to be rotated clockwise to make the dummy |
|
//invisible chord center vertically |
|
var offset = (2 * Math.PI) * (emptyStroke/(respondents + emptyStroke))/4; |
|
|
|
//Custom sort function of the chords to keep them in the original order |
|
var chord = customChordLayout() //d3.layout.chord() |
|
.padding(.02) |
|
.sortChords(d3.descending) //which chord should be shown on top when chords cross. Now the biggest chord is at the bottom |
|
.matrix(matrix); |
|
|
|
var arc = d3.svg.arc() |
|
.innerRadius(innerRadius) |
|
.outerRadius(outerRadius) |
|
.startAngle(startAngle) //startAngle and endAngle now include the offset in degrees |
|
.endAngle(endAngle); |
|
|
|
var path = stretchedChord() //Call the stretched chord function |
|
.radius(innerRadius) |
|
.startAngle(startAngle) |
|
.endAngle(endAngle); |
|
|
|
//////////////////////////////////////////////////////////// |
|
//////////////////// Draw outer Arcs /////////////////////// |
|
//////////////////////////////////////////////////////////// |
|
|
|
var g = wrapper.selectAll("g.group") |
|
.data(chord.groups) |
|
.enter().append("g") |
|
.attr("class", "group") |
|
.on("mouseover", fade(opacityLow)) |
|
.on("mouseout", fade(opacityDefault)); |
|
|
|
g.append("path") |
|
.style("stroke", function(d,i) { return (Names[i] === "" ? "none" : "#00A1DE"); }) |
|
.style("fill", function(d,i) { return (Names[i] === "" ? "none" : "#00A1DE"); }) |
|
.style("pointer-events", function(d,i) { return (Names[i] === "" ? "none" : "auto"); }) |
|
.attr("d", arc) |
|
.attr("transform", function(d, i) { //Pull the two slices apart |
|
d.pullOutSize = pullOutSize * ( d.startAngle + 0.001 > Math.PI ? -1 : 1); |
|
return "translate(" + d.pullOutSize + ',' + 0 + ")"; |
|
}); |
|
|
|
//////////////////////////////////////////////////////////// |
|
////////////////////// Append Names //////////////////////// |
|
//////////////////////////////////////////////////////////// |
|
|
|
//The text also needs to be displaced in the horizontal directions |
|
//And also rotated with the offset in the clockwise direction |
|
g.append("text") |
|
.each(function(d) { d.angle = ((d.startAngle + d.endAngle) / 2) + offset;}) |
|
.attr("dy", ".35em") |
|
.attr("class", "titles") |
|
.style("font-size", mobileScreen ? "8px" : "10px" ) |
|
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; }) |
|
.attr("transform", function(d,i) { |
|
var c = arc.centroid(d); |
|
return "translate(" + (c[0] + d.pullOutSize) + "," + c[1] + ")" |
|
+ "rotate(" + (d.angle * 180 / Math.PI - 90) + ")" |
|
+ "translate(" + 20 + ",0)" |
|
+ (d.angle > Math.PI ? "rotate(180)" : "") |
|
}) |
|
.text(function(d,i) { return Names[i]; }) |
|
.call(wrapChord, 100); |
|
|
|
//////////////////////////////////////////////////////////// |
|
//////////////////// Draw inner chords ///////////////////// |
|
//////////////////////////////////////////////////////////// |
|
|
|
wrapper.selectAll("path.chord") |
|
.data(chord.chords) |
|
.enter().append("path") |
|
.attr("class", "chord") |
|
.style("stroke", "none") |
|
//.style("fill", "#C4C4C4") |
|
.style("fill", "url(#gradientLinearPerLine)") //An SVG Gradient to give the impression of a flow from left to right |
|
.style("opacity", function(d) { return (Names[d.source.index] === "" ? 0 : opacityDefault); }) //Make the dummy strokes have a zero opacity (invisible) |
|
.style("pointer-events", function(d,i) { return (Names[d.source.index] === "" ? "none" : "auto"); }) //Remove pointer events from dummy strokes |
|
.attr("d", path) |
|
.on("mouseover", fadeOnChord) |
|
.on("mouseout", fade(opacityDefault)); |
|
|
|
//////////////////////////////////////////////////////////// |
|
////////////////// Extra Functions ///////////////////////// |
|
//////////////////////////////////////////////////////////// |
|
|
|
//Include the offset in de start and end angle to rotate the Chord diagram clockwise |
|
function startAngle(d) { return d.startAngle + offset; } |
|
function endAngle(d) { return d.endAngle + offset; } |
|
|
|
// Returns an event handler for fading a given chord group |
|
function fade(opacity) { |
|
return function(d, i) { |
|
wrapper.selectAll("path.chord") |
|
.filter(function(d) { return d.source.index != i && d.target.index != i && Names[d.source.index] != ""; }) |
|
.transition() |
|
.style("opacity", opacity); |
|
}; |
|
}//fade |
|
|
|
// Fade function when hovering over chord |
|
function fadeOnChord(d) { |
|
var chosen = d; |
|
wrapper.selectAll("path.chord") |
|
.transition() |
|
.style("opacity", function(d) { |
|
if (d.source.index == chosen.source.index && d.target.index == chosen.target.index) { |
|
return opacityDefault; |
|
} else { |
|
return opacityLow; |
|
}//else |
|
}); |
|
}//fadeOnChord |
|
|
|
/*Taken from http://bl.ocks.org/mbostock/7555321 |
|
//Wraps SVG text*/ |
|
function wrapChord(text, width) { |
|
text.each(function() { |
|
var text = d3.select(this), |
|
words = text.text().split(/\s+/).reverse(), |
|
word, |
|
line = [], |
|
lineNumber = 0, |
|
lineHeight = 1.1, // ems |
|
y = 0, |
|
x = 0, |
|
dy = parseFloat(text.attr("dy")), |
|
tspan = text.text(null).append("tspan").attr("x", x).attr("y", y).attr("dy", dy + "em"); |
|
|
|
while (word = words.pop()) { |
|
line.push(word); |
|
tspan.text(line.join(" ")); |
|
if (tspan.node().getComputedTextLength() > width) { |
|
line.pop(); |
|
tspan.text(line.join(" ")); |
|
line = [word]; |
|
tspan = text.append("tspan").attr("x", x).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); |
|
} |
|
} |
|
}); |
|
}//wrapChord |
|
|
|
//iFrame handler |
|
var pymChild = new pym.Child(); |
|
pymChild.sendHeight() |
|
setTimeout(function() { pymChild.sendHeight(); },5000); |
|
|