Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Chart.js v2.6: Add arrows to pie chart output values

I am using Chart.js v2.6 to output a pie chart. The data is obtained from MySQL database. The chart renders properly, but I need to add arrows to data values as shown in the screenshot below.

Example pie chart with arrows:

pie chart

Below is my code to output pie chart using Chart.js:

var chartdata_order_status = {
    labels: status,
    datasets: [{
        label: 'Order status',
        backgroundColor: ["#00b0f0","#92d050","#ffc000","#ff6dd9"],
        data: count_status
    }]
};

var pieGraph = new Chart(ctx3, {
    type: 'pie',
    data: chartdata_country_orders,
    options: {
        pieceLabel: {
            mode: 'value',
            position: 'outside',
            fontColor: '#000',
            format: function (value) {
                return '$' + value;
            }
        },
        title: {
            display: true,
            text: 'Total Sales by Country - Top 5',
            fontSize: 15,
            fontStyle: 'bold'
        },
        legend: {
            display: true,
            position: 'bottom',
        },
    } 
});

I have not included the PHP code for obtaining data from the MySQLtable.

like image 454
akshithMarolie Avatar asked Jul 27 '17 13:07

akshithMarolie


Video Answer


2 Answers

You can now use Chart.PieceLabel.js and get labels outside the slices.s,

DEMO

angular.module("app", ["chart.js"]).controller("ChartCtrl", function($scope) {

    $scope.labels = ["January", "February", "March", "April", "May", "June", "July"];

    $scope.data = [65, 59, 80, 81, 56, 55, 40];

    $scope.options = {
      pieceLabel: {
        render: 'label',
        fontColor: '#000',
        position: 'outside',
        segment: true
      }
    };

});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.2.1/Chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.js"></script>
<script src="https://cdn.jsdelivr.net/angular.chartjs/latest/angular-chart.js"></script>
<script src="https://rawgit.com/beaver71/Chart.PieceLabel.js/master/build/Chart.PieceLabel.min.js"></script>
<div ng-app="app" ng-controller="ChartCtrl">
  <canvas id="pie" class="chart chart-pie"
         chart-data="data" chart-labels="labels" chart-options="options">
  </canvas> 
</div>
like image 141
Sajeetharan Avatar answered Oct 17 '22 03:10

Sajeetharan


For chartjs 3.xx you can try this

var ctx = document.getElementById("myChart");
  var data = [61, 10, 28];
  const getSuitableY = (y, yArray = [], direction) => {
    let result = y;
    yArray.forEach((existedY) => {
      if (existedY - 14 < result && existedY + 14 > result) {
        if (direction === "right") {
          result = existedY + 14;
        } else {
          result = existedY - 14;
        }
      }
    });
    return result;
  };

  const getOriginPoints = (source, center, l) => {
    // console.log(source, center, l)

    let a = {x: 0, y: 0};
    var dx = (center.x - source.x) / l
    var dy = (center.y - source.y) / l
    a.x = center.x + l * dx
    a.y = center.y + l * dy
    return a
  };
  const options = {
    plugins: {
      legend: {
        display: true,
        position: "bottom"
      },
    },
    layout: {
      padding: {
        top: 30,
        left: 0,
        right: 0,
        bottom: 30
      }
    }
  };
  const plugins = [
    {
      afterDraw: (chart) => {
        const ctx = chart.ctx;
        ctx.save();
        ctx.font = "10px 'Averta Std CY'";
        const leftLabelCoordinates = [];
        const rightLabelCoordinates = [];
        const chartCenterPoint = {
          x:
            (chart.chartArea.right - chart.chartArea.left) / 2 +
            chart.chartArea.left,
          y:
            (chart.chartArea.bottom - chart.chartArea.top) / 2 +
            chart.chartArea.top
        };
        chart.config.data.labels.forEach((label, i) => {
          const meta = chart.getDatasetMeta(0);
          const arc = meta.data[i];
          const dataset = chart.config.data.datasets[0];

          // Prepare data to draw
          // important point 1
          const centerPoint = arc.getCenterPoint();
          let color = chart.config._config.data.datasets[0].backgroundColor[i];
          let labelColor = chart.config._config.data.datasets[0].backgroundColor[i];


          const angle = Math.atan2(
            centerPoint.y - chartCenterPoint.y,
            centerPoint.x - chartCenterPoint.x
          );
          // important point 2, this point overlapsed with existed points
          // so we will reduce y by 14 if it's on the right
          // or add by 14 if it's on the left
          let originPoint = getOriginPoints(chartCenterPoint, centerPoint, arc.outerRadius)
          const point2X =
            chartCenterPoint.x + Math.cos(angle) * (centerPoint.x < chartCenterPoint.x ? arc.outerRadius + 10 : arc.outerRadius + 10);
          let point2Y =
            chartCenterPoint.y + Math.sin(angle) * (centerPoint.y < chartCenterPoint.y ? arc.outerRadius + 15 : arc.outerRadius + 15);

          let suitableY;
          if (point2X < chartCenterPoint.x) {
            // on the left
            suitableY = getSuitableY(point2Y, leftLabelCoordinates, "left");
          } else {
            // on the right

            suitableY = getSuitableY(point2Y, rightLabelCoordinates, "right");
          }

          point2Y = suitableY;

          let value = dataset.data[i];
          // if (dataset.polyline && dataset.polyline.formatter) {
          //   value = dataset.polyline.formatter(value);
          // }
          let edgePointX = point2X < chartCenterPoint.x ? chartCenterPoint.x - arc.outerRadius - 10 : chartCenterPoint.x + arc.outerRadius + 10;

          if (point2X < chartCenterPoint.x) {
            leftLabelCoordinates.push(point2Y);
          } else {
            rightLabelCoordinates.push(point2Y);
          }

          //DRAW CODE
          // first line: connect between arc's center point and outside point
          ctx.lineWidth = 2;
          ctx.strokeStyle = color;
          ctx.beginPath();
          ctx.moveTo(originPoint.x, originPoint.y);
          ctx.lineTo(point2X, point2Y);
          ctx.stroke();
          // second line: connect between outside point and chart's edge
          ctx.beginPath();
          ctx.moveTo(point2X, point2Y);
          ctx.lineTo(edgePointX, point2Y);
          ctx.stroke();
          //fill custom label
          const labelAlignStyle =
            edgePointX < chartCenterPoint.x ? "right" : "left";
          const labelX = edgePointX < chartCenterPoint.x ? edgePointX : edgePointX + 0;
          const labelY = point2Y + 7;
          ctx.textAlign = labelAlignStyle;
          ctx.textBaseline = "bottom";
          ctx.font = "bold 12px Lato";
          // ctx.fillStyle = labelColor;
          ctx.fillText(value, labelX, labelY);
        });
        ctx.restore();
      }
    }
  ];

  var myChart = new Chart(ctx, {
    type: 'pie',
    plugins: plugins,
    options: options,
    data: {
      labels: ["Red", "Blue", "Yellow", "Green", "Greek", "Greek"],
      datasets: [
        {
          label: "# of Votes",
          data: [30, 1, .4, 2, 0.3, 80],
          backgroundColor: [
            "rgba(255, 99, 132, 0.8)",
            "rgba(54, 162, 235, 0.8)",
            "rgba(255, 206, 86, 0.8)",
            "rgba(75, 192, 192, 0.8)",
            "rgba(153, 102, 255, 0.8)",
            "rgba(75, 192, 192, 0.8)",
            "rgba(255, 159, 64, 0.8)"
          ],
          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)",
            "rgba(75, 192, 192, 1)"
          ],
          borderWidth: 1,
          polyline: {
            //   color: "gray",
            //   labelColor: "gray",
            formatter: (value) => `${value}`
          }
        }
      ]
    }
  });
 .wrapper {
            height: 200px;
            width: 400px;
        }
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.min.js"></script>
    <style>
        .wrapper {
            height: 200px;
            width: 400px;
        }
    </style>
</head>
<body>
<div class="wrapper">
    <canvas id="myChart"></canvas>
</div>

</body>
</html>
`
like image 2
Amit Avatar answered Oct 17 '22 05:10

Amit