ChartJS 2.0 - Huddle Pie Chart Shortcuts

I need to draw diagrams with many values ​​(some of them are close) and long signs of values. Values ​​should be displayed on a chart (not in legends). I use the following plugin to display labels:

var drawItemsValuesPlugin = {
    afterDraw: function(chartInstance) {

        var ctx = chartInstance.chart.ctx;

        // render the value of the chart above the bar
        ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
        ctx.textAlign    = 'center';
        ctx.textBaseline = 'bottom';        
        ctx.strokeStyle = 'black';
        ctx.font = "bold 11pt Arial";
        ctx.lineWidth = 0.3;

        chartInstance.data.datasets.forEach(function (dataset) {
                for (var i = 0; i < dataset.data.length; i++) {    
                    var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
                        total = dataset._meta[Object.keys(dataset._meta)[0]].total,
                        mid_radius = model.innerRadius + (model.outerRadius - model.innerRadius)/2,
                        start_angle = model.startAngle,
                        end_angle = model.endAngle,
                        mid_angle = start_angle + (end_angle - start_angle)/2;

                    var fact = (chartInstance.config.type == 'pie'?
                        (i%2==0?1:1.6):
                        (i%2==0?0.9:1.1)
                    );
                    var x = mid_radius * fact * Math.cos(mid_angle);
                    var y = mid_radius * fact * Math.sin(mid_angle);

                    ctx.fillStyle = '#fff';

                    var label = chartInstance.config.data.labels[i];
                    var percent = String(Math.round(dataset.data[i]/total*100)) + "%";
                    ctx.fillText(label, model.x + x, model.y + y);
                    ctx.strokeText(label, model.x + x, model.y + y);
                    // Display percent in another line, line break doesn't work for fillText
                    ctx.fillText(dataset.data[i] + ' ('+percent+')', model.x + x, model.y + y + 15);
                    ctx.strokeText(dataset.data[i] + ' ('+percent+')', model.x + x, model.y + y + 15);
                }
            });
    }
};

But I ran into the following problem:

enter image description here

The value icons are huddle. A simple solution places labels on the diagram, as shown in the figure below:

enter image description here

How can I get these shortcut positions using a JS 2.0 chart?

+4
source share
3 answers

NOTE: the code below does not work. just a layout.

x,y = 0,0 = middle of pie chart / middle of the circle

// these 4 points = part of the donut pie.

xa[1],ya[1] = x,y point on the outside of circle.
xb[1],yb[1] = x,y point on the outside of circle.
xc[1],yc[1] = x,y point on the inside of circle.
xd[1],yd[1] = x,y point on the inside of circle.

//

xab[1],yab[1] = x,y point on the outside circle, between xa,ya and xb,yb

// .

function somefunc(){
  //i do know how to do this. 
}

// , .

var label_height_pixel[1] = //no idea how to figure this out
var find_middle_of_text[1] = label_height_pixel[1] / 2;

// , , .

//ok , x, y.

xab[1],yab[1] and x,y
var xtext[1],ytext[1] = outer_circle_radius + find_middle_of_text[1] + padding

for, . . , . .

my_next_height[2] = outer_circle_radius + label_height_pixel[1] + find_middle_of_text[2] + padding
my_next_height[3] = outer_circle_radius + label_height_pixel[1] + label_height_pixel[2] + find_middle_of_text[3] + padding
my_next_height[4] = outer_circle_radius + label_height_pixel[1] + label_height_pixel[2] + label_height_pixel[3] + find_middle_of_text[3] + padding

if/then/else ., , x . my_next_height [] .

.

, , , . , , .

x, y z. , , . mid_radius, , , , x, y.

0

, , charjs

$.plot('#placeholder', data, {
    series: {
        pie: {
            show: true
        }
    },
    legend: {
        show: false
    }
});
0

. - . ( ), :

  • , , . , .
  • Chart.js 2 (, 2.3.1). Chart.js Dropbox, layout.padding, ( ).
  • , , .

.

. ( , ) , . , -, . , , . layout.padding , . . , ( ) ( , ).

The demo is also available below, but it cannot load the JavaScript file from Dropbox (while JSFiddle should not fail - when the CDN version of Chart.js is updated, I update all the links):

var drawItemsValuesPlugin = {
  afterDraw: function(chartInstance) {

    var ctx = chartInstance.chart.ctx;

    // render the value of the chart above the bar
    ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
    ctx.textAlign = 'center';
    ctx.textBaseline = 'bottom';
    ctx.strokeStyle = 'black';
    ctx.font = "bold 11pt Arial";
    ctx.lineWidth = 0.3;

    chartInstance.data.datasets.forEach(function(dataset) {
      for (var i = 0; i < dataset.data.length; i++) {
        var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
          total = dataset._meta[Object.keys(dataset._meta)[0]].total,
          mid_radius = model.innerRadius + (2.4 * model.outerRadius - model.innerRadius) / 2,
          start_angle = model.startAngle,
          end_angle = model.endAngle,
          mid_angle = start_angle + (end_angle - start_angle) / 2;

        var mid_radius2 = 0.92 * (model.innerRadius + (2.4 * model.outerRadius - model.innerRadius) / 2);

        var fact = i % 2 == 0 ? 1.00 : 1.15;

        var x = mid_radius * fact * Math.cos(mid_angle);
        var y = mid_radius * fact * Math.sin(mid_angle);

        var myX = mid_radius2 * fact * Math.cos(mid_angle);
        var myY = mid_radius2 * fact * Math.sin(mid_angle);

        var myX2 = 0.91 * mid_radius2 * 1 * Math.cos(mid_angle);
        var myY2 = 0.91 * mid_radius2 * 1 * Math.sin(mid_angle);

        ctx.lineWidth = 2;
        ctx.beginPath();
        ctx.moveTo(model.x + myX2, model.y + myY2);
        ctx.strokeStyle = '#232323';
        ctx.lineTo(model.x + myX, model.y + myY);
        ctx.stroke();
        ctx.strokeStyle = 'black';
        ctx.fillStyle = '#454545';
        ctx.lineWidth = 0.3;

        var label = chartInstance.config.data.labels[i];
        var percent = String(Math.round(dataset.data[i] / total * 100)) + "%";
        ctx.fillText(label, model.x + x, model.y + y);
        ctx.strokeText(label, model.x + x, model.y + y);
        // Display percent in another line, line break doesn't work for fillText
        ctx.fillText(dataset.data[i] + ' (' + percent + ')', model.x + x, model.y + y + 15);
        ctx.strokeText(dataset.data[i] + ' (' + percent + ')', model.x + x, model.y + y + 15);
      }
    });
  }
};

Chart.pluginService.register(drawItemsValuesPlugin);

var ctx = document.getElementById("myChart");

var myChart = new Chart(ctx, {
  type: 'pie',
  data: {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
    datasets: [{
      data: [15, 1, 1, 1, 45, 1],
      backgroundColor: [
        'rgba(255, 99, 132, 0.2)',
        'rgba(54, 162, 235, 0.2)',
        'rgba(255, 206, 86, 0.2)',
        'rgba(75, 192, 192, 0.2)',
        'rgba(153, 102, 255, 0.2)',
        'rgba(255, 159, 64, 0.2)'
      ],
      borderColor: [
        'rgba(255,99,132,1)',
        'rgba(54, 162, 235, 1)',
        'rgba(255, 206, 86, 1)',
        'rgba(75, 192, 192, 1)',
        'rgba(153, 102, 255, 1)',
        'rgba(255, 159, 64, 1)'
      ],
      borderWidth: 1
    }]
  },
  options: {
    legend: {
      display: false
    },
    layout: {
      padding: 140
    }
  }
});
<script src="https://dl.dropboxusercontent.com/s/yju3s0dqe32um2k/Chart.min.js"></script>
<canvas id="myChart" width="400" height="400"></canvas>
Run codeHide result
0
source

Source: https://habr.com/ru/post/1657141/


All Articles