Inspiration from Mike Bostock's chord diagram examples and others. Also the API reference layout for the chord layout.
forked from SkiWether's block: Chord diagram showing co-occurrences.
| license: mit |
Inspiration from Mike Bostock's chord diagram examples and others. Also the API reference layout for the chord layout.
forked from SkiWether's block: Chord diagram showing co-occurrences.
| <!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 = [ "Makanan", "Gadget", "Rumah tangga", "Alat kantor", "Handphone" ]; | |
| 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> |