Chart.js icon indicating copy to clipboard operation
Chart.js copied to clipboard

PackedCircle

Open Offbeatmammal opened this issue 2 years ago • 4 comments

Feature Proposal

I have a need for a PackedCircle chart - similar to a TreeMap but arbitrary sized circles clustered around a center (my use case only requires a single level rather than nested)

have found them supported in a number of other libraries, and while they are not as space efficient as treemaps, it's something I keep getting requests to support in the internal dashboard I maintain

Possible Implementation

had started a discussion on https://github.com/kurkle/chartjs-chart-treemap/issues/15 and as well as the packing solution they use found this https://stackoverflow.com/a/21612877/1569675 (not DS3 specific, just a canvas implementation). As an interim, I might experiment with using this logic and then using it to populate a bubble chart, though it doesn't assign a 'center of gravity' to the middle of the box which would be a more desirable behavior

Offbeatmammal avatar Aug 10 '23 00:08 Offbeatmammal

With some carefull own logic with creating the bubbles you could create this already using a bubble chart. But if you want it as an chart type that does that logic for you I think it would suit better as an external chart type and not something for the core

LeeLenaleee avatar Aug 10 '23 08:08 LeeLenaleee

With some carefull own logic with creating the bubbles you could create this already using a bubble chart. But if you want it as an chart type that does that logic for you I think it would suit better as an external chart type and not something for the core

agreed, it's probably not core. I've got close using the sample I linked, but getting the returned X,Y, and Radius scaled to fit into the canvas is making my head hurt! Sample code here in case it's of use to anyone (and hopefully someone points to where I'm going wrong) - at the moment there's still sometimes gaps or overlay of the circles that I don't see in the jsfiddle, and bubbles get clipped at the edge of the canvas.

 <canvas id="canvas" style="width:450px; height:450px;"></canvas>

// include the calculation code from https://jsfiddle.net/TDzVE/

  var radiuses = [];
  for(var i=0; i<15; i++) {
    radiuses.push(Math.random() * (200) + 1)
  }
    
  var packer = new Packer (radiuses, 1);

  var chart = $("#canvas")

  var margin_factor = 0.1;
  var mx = chart.width() * margin_factor / 2;
  var my = chart.height() * margin_factor / 2;
  dx=Number(packer.w)/2
  dy=Number(packer.h)/2
  var zx = chart.width() / packer.w;
  var zy = chart.height() / packer.h;
  var zoom = zx < zy ? zx : zy;

  datapoints = [];
  for (var i=0; i<packer.list.length;i++) {
    circle = packer.list[i]
    datapoints.push({'x':(circle.c.x+dx)*zoom+mx, 'y':(circle.c.y+dy)*zoom+my, 'r':circle.r*zoom}) 
  }

  const data = {
    datasets: [
      {
        label: 'Dataset 1',
        data: datapoints,
        backgroundColor: "rgba(123,123,123,1)",
      },
    ]
  };

  var myBarChart = new Chart(chart, {
    type: 'bubble',
    data: data,
    options: {
      responsive : false,
      maintainAspectRatio : true,
      layout : {
        autoPadding : false,
      },
      scales: {
                      x: {
                        ticks: {display: false,},
                        grid: { display: false },
                        border: {display: false}
                      },
                      y: {display:false,
                          ticks: {display: false,},
                          grid: { display: false, },
                          border: {display: false}
                        }
                  },    
      plugins: {
        legend: {display: false,},
        title: {display: false,}
      }
    },
  })


Offbeatmammal avatar Aug 10 '23 08:08 Offbeatmammal

another, clunky, solution using the D3 v3 layout.pack algorithm https://stackoverflow.com/a/76911169/1569675

Offbeatmammal avatar Aug 16 '23 07:08 Offbeatmammal

Would love this as well

jmtimper avatar Sep 11 '23 02:09 jmtimper