/* polar layout */ (function() { var RADIUS, W, arc_generator, bl, bm, br, color, data, dist_scale, height, inner_radius_scale, max, max_dist, pie, pies, polar, polar_data, polar_layout, radius_scale, rand2_6, side, svg, ul, um, ur, width; polar = function() { var angle, self; angle = null; self = function(data) { angle = 2 * Math.PI / data.length; data.forEach(function(d, i) { return d.angle = data.length > 2 ? i * angle : (i - 0.25) * angle; }); return data; }; self.angle = function() { return angle; }; return self; }; /* --- */ rand2_6 = function() { return 2 + Math.round(Math.random() * 6); }; data = d3.range(rand2_6()).map(function(d) { return { category: "cat_" + d, value: Math.random() }; }); console.log(data); max = d3.max(data, function(d) { return d.value; }); width = 960; height = 500; side = Math.min(width, height); RADIUS = side / 4 - 20; polar_layout = polar(); polar_data = polar_layout(data); console.log(polar_data); svg = d3.select("body").append("svg").attr("width", width).attr("height", height).append('g').attr({ transform: "translate(" + (width / 2) + ", " + (height / 2) + ")" }); ul = svg.append("g").attr({ transform: "translate(" + (-side / 2) + ", " + (-side / 4) + ")" }); um = svg.append("g").attr({ transform: "translate(0, " + (-side / 4) + ")" }); ur = svg.append("g").attr({ transform: "translate(" + (+side / 2) + ", " + (-side / 4) + ")" }); bl = svg.append("g").attr({ transform: "translate(" + (-side / 2) + ", " + (+side / 4) + ")" }); bm = svg.append("g").attr({ transform: "translate(0, " + (+side / 4) + ")" }); br = svg.append("g").attr({ transform: "translate(" + (+side / 2) + ", " + (+side / 4) + ")" }); color = d3.scale.ordinal().range(["#1b9e77", "#d95f02", "#7570b3", "#e7298a", "#66a61e", "#e6ab02", "#a6761d", "#666666"]); pie = d3.layout.pie().sort(null).value(function(d) { return d.value; }); arc_generator = d3.svg.arc().innerRadius(0).outerRadius(RADIUS); ul.selectAll('.arc').data(pie(data)).enter().append('path').attr({ "class": 'arc', d: arc_generator, fill: function(d, i) { return color(i); } }); radius_scale = d3.scale.linear().domain([0, max]).range([0, RADIUS]); inner_radius_scale = d3.scale.linear().domain([0, max]).range([RADIUS * 0.4, RADIUS]); arc_generator = d3.svg.arc().innerRadius(function(d) { return inner_radius_scale(max - d.value); }).outerRadius(function(d) { return radius_scale(max); }).startAngle(function(d) { return d.angle - polar_layout.angle() / 2; }).endAngle(function(d) { return d.angle + polar_layout.angle() / 2; }); pies = um.selectAll('.arc').data(polar_data); pies.enter().append('path').attr({ "class": 'arc', d: arc_generator, fill: function(count, klass) { return color(klass); } }); max_dist = RADIUS / (1 + Math.sin(polar_layout.angle() / 2)); dist_scale = d3.scale.sqrt().domain([0, max]).range([0, max_dist]); bm.selectAll('.bubble').data(polar_data).enter().append('circle').attr({ "class": 'bubble', cx: function(d) { return dist_scale(d.value) * Math.cos(d.angle - Math.PI / 2); }, cy: function(d) { return dist_scale(d.value) * Math.sin(d.angle - Math.PI / 2); }, r: function(d) { return dist_scale(d.value) * Math.sin(polar_layout.angle() / 2); }, fill: function(d, i) { return color(i); } }); radius_scale = d3.scale.sqrt().domain([0, max]).range([0, RADIUS]); arc_generator = d3.svg.arc().innerRadius(0).outerRadius(function(d) { return radius_scale(d.value); }).startAngle(function(d) { return d.angle - polar_layout.angle() / 2; }).endAngle(function(d) { return d.angle + polar_layout.angle() / 2; }); bl.selectAll('.arc').data(polar_data).enter().append('path').attr({ "class": 'arc', d: arc_generator, fill: function(d, i) { return color(i); } }); max_dist = RADIUS / (1 + Math.sin(polar_layout.angle() / 2)); dist_scale = d3.scale.sqrt().domain([0, max]).range([0, max_dist]); br.selectAll('.petal').data(polar_data).enter().append('path').attr({ "class": 'petal', d: function(d) { var far_x, far_y, l, r, theta, theta_a, theta_b; r = dist_scale(d.value) * Math.sin(polar_layout.angle() / 2); l = dist_scale(d.value) * Math.cos(polar_layout.angle() / 2); theta = d.angle - Math.PI / 2; if (l === 0) { far_x = (dist_scale(d.value) + r) * Math.cos(theta); far_y = (dist_scale(d.value) + r) * Math.sin(theta); return "M0 0 A" + r + " " + r + " 0 1 1 " + far_x + " " + far_y + " A" + r + " " + r + " 0 1 1 0 0"; } theta_a = theta - polar_layout.angle() / 2; theta_b = theta + polar_layout.angle() / 2; return "M0 0 L" + (l * Math.cos(theta_a)) + " " + (l * Math.sin(theta_a)) + " A" + r + " " + r + " 0 1 1 " + (l * Math.cos(theta_b)) + " " + (l * Math.sin(theta_b)) + " z"; }, fill: function(d, i) { return color(i); } }); W = 8; dist_scale = d3.scale.linear().domain([0, max]).range([0, RADIUS]); ur.selectAll('.stick').data(polar_data).enter().append('path').attr({ "class": 'stick', d: function(d) { var b_x, b_y, c_x, c_y, d_x, d_y, delta, e_x, e_y, fx, fy, nx, ny, theta; theta = d.angle; delta = W / 2 / Math.tan(polar_layout.angle() / 2); nx = delta * Math.sin(theta); ny = -delta * Math.cos(theta); b_x = nx - W / 2 * Math.cos(theta); b_y = ny - W / 2 * Math.sin(theta); e_x = nx + W / 2 * Math.cos(theta); e_y = ny + W / 2 * Math.sin(theta); fx = dist_scale(d.value) * Math.sin(theta); fy = -dist_scale(d.value) * Math.cos(theta); c_x = fx - W / 2 * Math.cos(theta); c_y = fy - W / 2 * Math.sin(theta); d_x = fx + W / 2 * Math.cos(theta); d_y = fy + W / 2 * Math.sin(theta); return "M0 0 L" + b_x + " " + b_y + " L" + c_x + " " + c_y + " L" + d_x + " " + d_y + " L" + e_x + " " + e_y + " z"; }, fill: function(d, i) { return color(i); } }); }).call(this);