block by nitaku 70da709633904c6de9d9

Pie vs. pie

Full Screen

-

index.js

/* polar layout
*/


(function() {
  var RADIUS, arc_generator, bl, br, color, data, height, max, outer_polygon_generator, pie, polar, polar_data, polar_layout, polygon_generator, radius_scale, rand2_6, side, svg, ul, 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 / 4) + ", " + (-side / 4) + ")"
  });

  ur = svg.append("g").attr({
    transform: "translate(" + (+side / 4) + ", " + (-side / 4) + ")"
  });

  bl = svg.append("g").attr({
    transform: "translate(" + (-side / 4) + ", " + (+side / 4) + ")"
  });

  br = svg.append("g").attr({
    transform: "translate(" + (+side / 4) + ", " + (+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);
    }
  });

  outer_polygon_generator = d3.svg.line().x(function(d) {
    return RADIUS * Math.cos(d.angle - Math.PI / 2);
  }).y(function(d) {
    return RADIUS * Math.sin(d.angle - Math.PI / 2);
  });

  ur.append("path").datum(polar_data).attr({
    "class": 'outer_polygon',
    d: function(ds) {
      return outer_polygon_generator(ds) + 'z';
    }
  });

  ur.selectAll(".radius").data(polar_data).enter().append("path").attr('class', 'radius').attr("d", function(d) {
    return "M0 0 L" + (RADIUS * Math.cos(d.angle - Math.PI / 2)) + " " + (RADIUS * Math.sin(d.angle - Math.PI / 2));
  });

  polygon_generator = d3.svg.line().x(function(d) {
    return RADIUS / max * d.value * Math.cos(d.angle - Math.PI / 2);
  }).y(function(d) {
    return RADIUS / max * d.value * Math.sin(d.angle - Math.PI / 2);
  });

  ur.append('path').datum(polar_data).attr({
    "class": 'polygon',
    d: function(ds) {
      return polygon_generator(ds) + 'z';
    }
  });

  ur.selectAll(".dot").data(polar_data).enter().append("circle").attr('class', 'dot').attr({
    cx: function(d) {
      return "" + (RADIUS / max * d.value * Math.cos(d.angle - Math.PI / 2));
    },
    cy: function(d) {
      return "" + (RADIUS / max * d.value * Math.sin(d.angle - Math.PI / 2));
    },
    r: 4,
    fill: function(d, i) {
      return color(i);
    }
  });

  radius_scale = d3.scale.linear().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);
    }
  });

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

  br.selectAll('.arc').data(polar_data).enter().append('path').attr({
    "class": 'arc',
    d: arc_generator,
    fill: function(d, i) {
      return color(i);
    }
  });

}).call(this);

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="description" content="Pie vs. pie" />
  <title>Pie vs. pie</title>
  <link rel="stylesheet" href="index.css">
  <script src="//d3js.org/d3.v3.min.js"></script>
</head>
<body>
  <script src="index.js"></script>
</body>
</html>

index.coffee

### polar layout ###
polar = () ->
  # defaults
  #scale = d3.scale.linear
  angle = null
  
  self = (data) ->
    angle = 2*Math.PI/data.length
    
    data.forEach (d, i) ->
      d.angle = if data.length > 2 then i * angle else (i-0.25) * angle
      
    return data
  
  self.angle = () ->
    return angle
  
  return self
    
### --- ###

rand2_6 = () -> 2 + Math.round(Math.random() * 6)

data = d3.range(rand2_6()).map (d) -> { category: "cat_#{d}", value: Math.random() }
console.log data

max = d3.max(data, (d) -> 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/4}, #{-side/4})"
    
ur = svg.append("g")
    .attr
      transform: "translate(#{+side/4}, #{-side/4})"
    
bl = svg.append("g")
    .attr
      transform: "translate(#{-side/4}, #{+side/4})"
    
br = svg.append("g")
    .attr
      transform: "translate(#{+side/4}, #{+side/4})"

color = d3.scale.ordinal()
  .range(["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"])
  

# pie chart
pie = d3.layout.pie()
  .sort(null)
  .value((d) -> 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: (d, i) -> color(i)
      
# radar chart
outer_polygon_generator = d3.svg.line()
  .x((d) -> RADIUS*Math.cos(d.angle-Math.PI/2))
  .y((d) -> RADIUS*Math.sin(d.angle-Math.PI/2))

ur.append("path")
  .datum(polar_data)
    .attr
      class: 'outer_polygon'
      d: (ds) -> outer_polygon_generator(ds) + 'z'
      
ur.selectAll(".radius")
    .data(polar_data)
  .enter().append("path")
    .attr('class','radius')
    .attr("d", (d) -> "M0 0 L#{RADIUS*Math.cos(d.angle-Math.PI/2)} #{RADIUS*Math.sin(d.angle-Math.PI/2)}")
    
polygon_generator = d3.svg.line()
  .x((d) -> RADIUS/max*d.value*Math.cos(d.angle-Math.PI/2))
  .y((d) -> RADIUS/max*d.value*Math.sin(d.angle-Math.PI/2))
  
ur.append('path')
    .datum(polar_data)
    .attr
      class: 'polygon'
      d: (ds) -> polygon_generator(ds) + 'z'
      
ur.selectAll(".dot")
    .data(polar_data)
  .enter().append("circle")
    .attr('class','dot')
    .attr
      cx: (d) -> "#{RADIUS/max*d.value*Math.cos(d.angle-Math.PI/2)}"
      cy: (d) -> "#{RADIUS/max*d.value*Math.sin(d.angle-Math.PI/2)}"
      r: 4
      fill: (d, i) -> color(i) 
      
# polar chart
radius_scale = d3.scale.linear()
  .domain([0, max])
  .range([0, RADIUS])
      
arc_generator = d3.svg.arc()
  .innerRadius(0)
  .outerRadius((d) -> radius_scale(d.value))
  .startAngle((d) -> d.angle - polar_layout.angle()/2)
  .endAngle((d) -> d.angle + polar_layout.angle()/2)
  
bl.selectAll('.arc')
    .data(polar_data)
  .enter().append('path')
    .attr
      class: 'arc'
      d: arc_generator
      fill: (d, i) -> color(i)
      
# polar area chart
radius_scale = d3.scale.sqrt()
  .domain([0, max])
  .range([0, RADIUS])
      
arc_generator = d3.svg.arc()
  .innerRadius(0)
  .outerRadius((d) -> radius_scale(d.value))
  .startAngle((d) -> d.angle - polar_layout.angle()/2)
  .endAngle((d) -> d.angle + polar_layout.angle()/2)
  
br.selectAll('.arc')
    .data(polar_data)
  .enter().append('path')
    .attr
      class: 'arc'
      d: arc_generator
      fill: (d, i) -> color(i)
      

index.css

svg {
  background-color: white;
}
.arc {
  stroke-width: 1;
  stroke: white;
  stroke-linejoin: round;
}
.radius {
  stroke: gray;
  stroke-dasharray: 3 3;
}
.polygon {
  fill: #DDD;
  fill-opacity: 0.5;
  stroke: gray;
}
.outer_polygon {
  fill: none;
  stroke: gray;
  stroke-dasharray: 3 3;
}
.dot {
  stroke: white;
}