Friday, 29 January 2021

Doughnut pie hybrid d3 version 4

I have an old doughnut hybrid pie chart/bubble chart combo working on d3v3.

enter image description here

//doughnut bubble chart v3 https://jsfiddle.net/ajevh5wf/

var $this = $('body');

var w = 300,
  h = 300;
var radius = Math.min(w, h) / 2;

var svg = d3.select($this[0])
  .append("svg")
  .attr("width", w)
  .attr("height", h)
  .append("g")

svg.append("g")
  .attr("class", "slices");
svg.append("g")
  .attr("class", "placeholders");


var pie = d3.layout.pie()
  .sort(null)
  .value(function(d) {
    return d.value;
  });

var arc = d3.svg.arc()
  .outerRadius(radius * 0.85)
  .innerRadius(radius * 0.83);

var arc2 = d3.svg.arc()
  .outerRadius(radius - 10)
  .innerRadius(0);

var outerArc = d3.svg.arc()
  .innerRadius(radius * 0.9)
  .outerRadius(radius * 0.9);

svg.attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");


function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}


var data = [{
  "group": "<5",
  "value": 1000,
  "children": [{
    "group": "<5",
    "label": "Mel",
    "value": 1000,
    "totalGroupValue": 1000
  }]
}, {
  "group": "5-13",
  "value": 1000,
  "children": [{
    "group": "5-13",
    "label": "Erica",
    "value": 1000,
    "totalGroupValue": 1000
  }]
}, {
  "group": "14-17",
  "value": 2000,
  "children": [{
    "group": "14-17",
    "label": "Jessica",
    "value": 1500,
    "totalGroupValue": 2000
  }, {
    "group": "14-17",
    "label": "Jill",
    "value": 500,
    "totalGroupValue": 2000
  }]
}, {
  "group": "18-24",
  "value": 1300,
  "children": [{
    "group": "18-24",
    "label": "Jerry",
    "value": 500,
    "totalGroupValue": 1300
  }, {
    "group": "18-24",
    "label": "Ben",
    "value": 500,
    "totalGroupValue": 1300
  }, {
    "group": "18-24",
    "label": "Billy",
    "value": 150,
    "totalGroupValue": 1300
  }, {
    "group": "18-24",
    "label": "Billy2",
    "value": 150,
    "totalGroupValue": 1300
  }]
}, {
  "group": "25-44",
  "value": 1000,
  "children": [{
    "group": "25-44",
    "label": "Kelly",
    "value": 1000,
    "totalGroupValue": 1000
  }]
}];

$.each(data, function(index, value) {
  value["groupid"] = index;
  $.each(value.children, function(i, v) {
    v["groupid"] = index;
  });
});

//slices
var slice = svg.select(".slices").selectAll("path.slice")
  .data(pie(data));

slice.enter()
  .insert("path")
  .style("fill", function(d) {
    return colores_google(d.data.groupid);
  })
  .attr("class", "slice");

slice
  .transition().duration(1000)
  .attrTween("d", function(d) {
    this._current = this._current || d;
    var interpolate = d3.interpolate(this._current, d);
    this._current = interpolate(0);
    return function(t) {
      return arc(interpolate(t));
    };
  })

slice.exit()
  .remove();
//slices


//placeholder bubbles
var placeholders = svg.select(".placeholders").selectAll("g.placeholder")
  .data(pie(data));

placeholders.enter()
  .insert("g")
  .attr("class", function(d, i) {
    return "placeholder place" + i;
  });

placeholders
  .transition().duration(1000)
  .attr("transform", function(d) {
    return "translate(" + arc2.centroid(d) + ")";
  })

placeholders.exit()
  .remove();
//placeholder bubbles


//bubbles
function bubbledata(data) {
  //loop through data -- and MERGE children
  var childs = [];
  $.each(data, function(index, value) {
    childs.push(value.children);
  });

  return $.extend(true, {}, {
    "children": data
  }); // return deep clone
}


function setBubbleChart(width, index, data) {

  //_create bubble
  var diameter = width / 2; //take half/width

  var bubs = svg.select(".place" + index).append("g")
    .attr("class", "bubs");

  bubs.attr("transform", "translate(" + -diameter / 2 + "," + -diameter / 2 + ")");

  var bubble = d3.layout.pack()
    .size([diameter, diameter])
    .value(function(d) {
      return d.value;
    })
    .padding(3);

  //_create bubble
  var data = bubbledata(data);

  var nodes = bubble.nodes(data)
    .filter(function(d) {
      return !d.children;
    }); // filter out the outer bubble


  var bubbles = bubs.selectAll('circle')
    .data(nodes);

  bubbles.enter()
    .insert("circle")
    .attr('transform', function(d) {
      return 'translate(' + d.x + ',' + d.y + ')';
    })
    .attr('r', function(d) {
      return d.r;
    })
    .style("fill", function(d) {
      return colores_google(d.groupid);
    });

  bubbles = bubbles.transition()
    .transition()
    .duration(250)
    .attr('transform', function(d) {
      return 'translate(' + d.x + ',' + d.y + ')';
    })
    .attr('r', function(d) {
      return d.r;
    })
    .ease('sine');

}

//loop through data and for EACH children array paint dots.
$.each(data, function(index, value) {
  setBubbleChart(100, index, value.children);
});
//custom bubble chart
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.17/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

//doughnut bubble chart v4 - not working https://jsfiddle.net/4rdj0fze/1/

var $this = $('body');


var data = [{
  "group": "<5",
  "value": 1000,
  "children": [{
    "group": "<5",
    "label": "Mel",
    "value": 1000,
    "totalGroupValue": 1000
  }]
}, {
  "group": "5-13",
  "value": 1000,
  "children": [{
    "group": "5-13",
    "label": "Erica",
    "value": 1000,
    "totalGroupValue": 1000
  }]
}, {
  "group": "14-17",
  "value": 2000,
  "children": [{
    "group": "14-17",
    "label": "Jessica",
    "value": 1500,
    "totalGroupValue": 2000
  }, {
    "group": "14-17",
    "label": "Jill",
    "value": 500,
    "totalGroupValue": 2000
  }]
}, {
  "group": "18-24",
  "value": 1300,
  "children": [{
    "group": "18-24",
    "label": "Jerry",
    "value": 500,
    "totalGroupValue": 1300
  }, {
    "group": "18-24",
    "label": "Ben",
    "value": 500,
    "totalGroupValue": 1300
  }, {
    "group": "18-24",
    "label": "Billy",
    "value": 150,
    "totalGroupValue": 1300
  }, {
    "group": "18-24",
    "label": "Billy2",
    "value": 150,
    "totalGroupValue": 1300
  }]
}, {
  "group": "25-44",
  "value": 1000,
  "children": [{
    "group": "25-44",
    "label": "Kelly",
    "value": 1000,
    "totalGroupValue": 1000
  }]
}];

var width = 300,
  height = 300;

var color = d3.scaleOrdinal()
  .range(["#eb6383", "#fa9191", "#ffe9c5", "#b4f2e1"]);


var margin = {
    top: 20,
    right: 5,
    bottom: 30,
    left: 20
  },
  width = width - margin.left - margin.right,
  height = height - margin.top - margin.bottom;

var svg = d3.select($this[0])
  .append("svg")
  .attr("width", width + margin.left + margin.right)
  .attr("height", height + margin.top + margin.bottom)
  .append("g")
  .attr('class', 'doughnutbubblechart')
  .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

var doughnutbubble = svg.append('g').attr('class', 'doughnutbubble');


var radius = Math.min(width, height) / 2;

doughnutbubble.append("g")
  .attr("class", "slices");

doughnutbubble.append("g")
  .attr("class", "placeholders");


var pie = d3.pie()
  .sort(null)
  .value(function(d) {
    return d.value;
  });

var arc = d3.arc()
  .outerRadius(radius * 0.85)
  .innerRadius(radius * 0.83);

var arc2 = d3.arc()
  .outerRadius(radius - 10)
  .innerRadius(0);

var outerArc = d3.arc()
  .innerRadius(radius * 0.9)
  .outerRadius(radius * 0.9);

doughnutbubble.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");


function colores_google(n) {
  var colores_g = ["#f7b363", "#448875", "#c12f39", "#2b2d39", "#f8dd2f"];
  return colores_g[n % colores_g.length];
}



$.each(data, function(index, value) {
  value["groupid"] = index;
  $.each(value.children, function(i, v) {
    v["groupid"] = index;
  });
});

//slices
var slice = doughnutbubble.select(".slices").selectAll("path.slice")
  .data(pie(data));

slice.enter()
  .insert("path")
  .style("fill", function(d) {
    return colores_google(d.data.groupid);
  })
  .attr("class", "slice")
  .transition().duration(1000)
  .attrTween("d", function(d) {
    this._current = this._current || d;
    var interpolate = d3.interpolate(this._current, d);
    this._current = interpolate(0);
    return function(t) {
      return arc(interpolate(t));
    };
  })

slice.exit()
  .remove();
//slices


//placeholder bubbles
var placeholders = doughnutbubble.select(".placeholders").selectAll("g.placeholder")
  .data(pie(data));

placeholders.enter()
  .insert("g")
  .attr("class", function(d, i) {
    return "placeholder place" + i;
  })
  .transition().duration(1000)
  .attr("transform", function(d) {
    return "translate(" + arc2.centroid(d) + ")";
  })

placeholders.exit()
  .remove();
//placeholder bubbles


//bubbles
function bubbledata(data) {
  //loop through data -- and MERGE children
  var childs = [];
  $.each(data, function(index, value) {
    childs.push(value.children);
  });

  return $.extend(true, {}, {
    "children": data
  }); // return deep clone
}


function setBubbleChart(width, index, data) {

  //_create bubble
  var diameter = width / 2; //take half/width

  var bubs = doughnutbubble.select(".place" + index).append("g")
    .attr("class", "bubs");

  bubs.attr("transform", "translate(" + -diameter / 2 + "," + -diameter / 2 + ")");


  //var data = bubbledata(data);



  //console.log("data", data);
  ///

  var force = d3.forceSimulation();

  var foci = {
    x: 150,
    y: 150
  }

  var data = funnelData(data, width, height)
    .map(function(d) {
      d.foci = foci;
      return d;
    })

  force.nodes(data);


  var bubbles = bubs.append("g")
    .attr("class", "bubbles")

  var nodes = bubbles.selectAll("circle")
    .data(data)
    .enter()
    .append('circle')
    .attr('r', 1)
    .attr('fill', function(d, i) {
      return color(i);
    });

  // Update                
  nodes.transition()
    .delay(300)
    .duration(1000)
    .attr("r", function(d) {
      return d.value * (width / 6) / 100;
    });

  force.on("tick", function() {
    data.forEach(cluster);
    data.forEach(collide(0.1));

    nodes.attr("cx", function(d) {
        return d.x;
      })
      .attr("cy", function(d) {
        return d.y;
      })
  });

  function funnelData(data, width, height) {
    function getRandom(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    var max_amount = d3.max(data, function(d) {
      return parseInt(d.value)
    })
    var radius_scale = d3.scalePow().exponent(0.5).domain([0, max_amount]).range([2, 85])

    data.forEach(function(elem, index) {
      elem.radius = radius_scale(elem.value) * .8;
      elem.all = 'all';
      elem.x = getRandom(0, width);
      elem.y = getRandom(0, height);
    });

    return data;
  }

  function cluster(d, i) {
    var f = d.foci;
    var k = 0.55;
    d.y += (f.y - d.y) * k * force.alpha()
    d.x += (f.x - d.x) * k * force.alpha()
  }

  var maxRadius = d3.max(data, function(d) {
    return d.radius;
  })
  var padding = 4;

  function collide(alpha) {
    var quadtree = d3.quadtree().x(function(d) {
      return d.x;
    }).y(function(d) {
      return d.y;
    }).extent([
      [-1, -1],
      [width + 1, height + 1]
    ]).addAll(data);

    return function(d) {
      var r = d.radius + maxRadius + padding,
        nx1 = d.x - r,
        nx2 = d.x + r,
        ny1 = d.y - r,
        ny2 = d.y + r;
      quadtree.visit(function(quad, x1, y1, x2, y2) {
        if (!quad.length && (quad.data !== d)) {
          var x = d.x - quad.data.x,
            y = d.y - quad.data.y,
            l = Math.sqrt(x * x + y * y),
            r = d.radius + quad.data.radius + padding;


          if (l < r) {
            l = (l - r) / l * alpha;

            d.x -= x *= l;
            d.y -= y *= l;
            quad.data.x += x;
            quad.data.y += y;
          }
        }
        return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
      });
    };
  }



}


//loop through data and for EACH children array paint dots.
$.each(data, function(index, value) {
  setBubbleChart(100, index, value.children);
});
//custom bubble chart
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

---bubblechart v4 working - https://jsfiddle.net/of48xjar/

but when I try and add this bubblechartv4 code to the base v4 -- I can't seem to get the bubbles to render properly in the placeholders or the sizes -- and I think in the old version3 had to exclude the parent level to ensure it just renders children bubbles.



from Doughnut pie hybrid d3 version 4

No comments:

Post a Comment