Inspiration from Mike Bostock's chord diagram examples and others. Also the API reference layout for the chord layout.
Last active
August 29, 2015 14:26
-
-
Save SkiWether/f2afd0b8a8bacb4f24c8 to your computer and use it in GitHub Desktop.
Chord diagram showing co-occurrences.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<meta charset="utf-8"> | |
<!-- affinity group data, circle rotation, auto-resize svg image, chord function, configuration --> | |
<title>Open Chord Shared Ad Blocks</title> | |
<script src="http://d3js.org/d3.v3.min.js"></script> | |
<style> | |
#visual { | |
font: 14px sans-serif; | |
} | |
.chord path { | |
fill-opacity: .67; | |
stroke: #000; | |
stroke-width: .5px; | |
} | |
@media only screen and (min-device-width: 320px) and (max-device-width: 568px) { | |
#visual { | |
-webkit-user-select: none; | |
font-size: 1.2em; | |
} | |
} | |
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) { | |
#visual { | |
-webkit-user-select: none; | |
} | |
} | |
</style> | |
<body> | |
<script> | |
var visual = document.getElementById("visual"); | |
// shared ad blocks between 7-Up, A&W, Coke, Dr Pepper, Pepsi brands | |
var matrix = [ | |
[ 5, 0, 1, 1, 3 ], | |
[ 0, 0, 0, 1, 0 ], | |
[ 1, 0, 1, 1, 0 ], | |
[ 1, 1, 1, 2, 0 ], | |
[ 3, 0, 0, 0, 3 ] | |
]; | |
var array = [ "7-Up", "A&W", "Coke", "Dr Pepper", "Pepsi" ]; | |
var rotation = -0.7; | |
var chord_options = { | |
"gnames": array, | |
"rotation": rotation, | |
"colors": ["#034e7b","#feb24c","#b10026","#238443","#fdbb84","#ffffb2","#fed976"] | |
}; | |
function Chord(container, options, matrix) { | |
// initialize the chord configuration variables | |
var config = { | |
width: 640, | |
height: 560, | |
rotation: 0, | |
textgap: 26, | |
colors: ["#7fc97f", "#beaed4", "#fdc086", "#ffff99", "#386cb0", "#f0027f", "#bf5b17", "#666666"] | |
}; | |
// add options to the chord configuration object | |
if (options) { | |
extend(config, options); | |
} | |
// set chord visualization variables from the configuration object | |
var offset = Math.PI * config.rotation, | |
width = config.width, | |
height = config.height, | |
textgap = config.textgap, | |
colors = config.colors; | |
// set viewBox and aspect ratio to enable a resize of the visual dimensions | |
var viewBoxDimensions = "0 0 " + width + " " + height, | |
aspect = width / height; | |
if (config.gnames) { | |
gnames = config.gnames; | |
} else { | |
// make a list of names | |
gnames = []; | |
for (var i=97; i<matrix.length; i++) { | |
gnames.push(String.fromCharCode(i)); | |
} | |
} | |
// start the d3 magic | |
var chord = d3.layout.chord() | |
.padding(.05) | |
.sortSubgroups(d3.descending) | |
.matrix(matrix); | |
var innerRadius = Math.min(width, height) * .31, | |
outerRadius = innerRadius * 1.1; | |
var fill = d3.scale.ordinal() | |
.domain(d3.range(matrix.length-1)) | |
.range(colors); | |
var svg = d3.select("body").append("svg") | |
.attr("id", "visual") | |
.attr("viewBox", viewBoxDimensions) | |
.attr("preserveAspectRatio", "xMinYMid") // add viewBox and preserveAspectRatio | |
.attr("width", width) | |
.attr("height", height) | |
.append("g") | |
.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); | |
var g = svg.selectAll("g.group") | |
.data(chord.groups) | |
.enter().append("svg:g") | |
.attr("class", "group"); | |
g.append("svg:path") | |
.style("fill", function(d) { return fill(d.index); }) | |
.style("stroke", function(d) { return fill(d.index); }) | |
.attr("id", function(d, i) { return "group" + d.index; }) | |
.attr("d", d3.svg.arc().innerRadius(innerRadius).outerRadius(outerRadius).startAngle(startAngle).endAngle(endAngle)) | |
.on("mouseover", fade(.1)) | |
.on("mouseout", fade(1)); | |
g.append("svg:text") | |
.each(function(d) {d.angle = ((d.startAngle + d.endAngle) / 2) + offset; }) | |
.attr("dy", ".35em") | |
.attr("text-anchor", function(d) { return d.angle > Math.PI ? "end" : null; }) | |
.attr("transform", function(d) { | |
return "rotate(" + (d.angle * 180 / Math.PI - 90) + ")" | |
+ "translate(" + (outerRadius + textgap) + ")" | |
+ (d.angle > Math.PI ? "rotate(180)" : ""); | |
}) | |
.text(function(d) { return gnames[d.index]; }); | |
svg.append("g") | |
.attr("class", "chord") | |
.selectAll("path") | |
.data(chord.chords) | |
.enter().append("path") | |
.attr("d", d3.svg.chord().radius(innerRadius).startAngle(startAngle).endAngle(endAngle)) | |
.style("fill", function(d) { return fill(d.source.index); }) | |
.style("opacity", 1) | |
.append("svg:title") | |
.text(function(d) { | |
return d.source.value + " " + gnames[d.source.index] + " shared with " + gnames[d.target.index]; | |
}); | |
// helper functions start here | |
function startAngle(d) { | |
return d.startAngle + offset; | |
} | |
function endAngle(d) { | |
return d.endAngle + offset; | |
} | |
function extend(a, b) { | |
for( var i in b ) { | |
a[ i ] = b[ i ]; | |
} | |
} | |
// Returns an event handler for fading a given chord group. | |
function fade(opacity) { | |
return function(g, i) { | |
svg.selectAll(".chord path") | |
.filter(function(d) { return d.source.index != i && d.target.index != i; }) | |
.transition() | |
.style("opacity", opacity); | |
}; | |
} | |
window.onresize = function() { | |
var targetWidth = (window.innerWidth < width)? window.innerWidth : width; | |
var svg = d3.select("#visual") | |
.attr("width", targetWidth) | |
.attr("height", targetWidth / aspect); | |
} | |
} | |
window.onload = function() { | |
Chord(visual, chord_options, matrix); | |
} | |
d3.select(self.frameElement).style("height", "600px"); | |
</script> | |
<h1>Shared Ad Blocks by Brand</h1> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment