Chart.js v2: space between doughnut inside doughnut

我的未来我决定 提交于 2019-12-02 13:31:50

问题


I am using chart.js v2.5.0. I put doughnut inside doughnut.

I want the disdance between 2 doughnuts(A) to be larger without affecting the distance between slices inside the same doughnut(B).

Please see the following image:

Currently I am using the property borderWidth. However, this also affects the width of B.

Please see the following code:

options: {
                elements: {
                    arc: {
                        borderWidth: 18,
                    },
                },
                cutoutPercentage: 60,
                responsive: true,
            }

I want the doughnuts to look like this:


回答1:


The only way to achieve this is to extend the existing doughnut controller and overwrite the update method with your own logic for determining the spacing.

Here is an example demonstrating how you would do this. With this implementation, I added a new doughnut chart option property called datasetRadiusBuffer that controls the white space between each dataset.

var helpers = Chart.helpers;

// this option will control the white space between embedded charts when there is more than 1 dataset
helpers.extend(Chart.defaults.doughnut, {
  datasetRadiusBuffer: 0
});

Chart.controllers.doughnut = Chart.controllers.doughnut.extend({
  update: function(reset) {
    var me = this;
    var chart = me.chart,
        chartArea = chart.chartArea,
        opts = chart.options,
        arcOpts = opts.elements.arc,
        availableWidth = chartArea.right - chartArea.left - arcOpts.borderWidth,
        availableHeight = chartArea.bottom - chartArea.top - arcOpts.borderWidth,
        minSize = Math.min(availableWidth, availableHeight),
        offset = {
          x: 0,
          y: 0
        },
        meta = me.getMeta(),
        cutoutPercentage = opts.cutoutPercentage,
        circumference = opts.circumference;

    // If the chart's circumference isn't a full circle, calculate minSize as a ratio of the width/height of the arc
    if (circumference < Math.PI * 2.0) {
      var startAngle = opts.rotation % (Math.PI * 2.0);
      startAngle += Math.PI * 2.0 * (startAngle >= Math.PI ? -1 : startAngle < -Math.PI ? 1 : 0);
      var endAngle = startAngle + circumference;
      var start = {x: Math.cos(startAngle), y: Math.sin(startAngle)};
      var end = {x: Math.cos(endAngle), y: Math.sin(endAngle)};
      var contains0 = (startAngle <= 0 && 0 <= endAngle) || (startAngle <= Math.PI * 2.0 && Math.PI * 2.0 <= endAngle);
      var contains90 = (startAngle <= Math.PI * 0.5 && Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 2.5 && Math.PI * 2.5 <= endAngle);
      var contains180 = (startAngle <= -Math.PI && -Math.PI <= endAngle) || (startAngle <= Math.PI && Math.PI <= endAngle);
      var contains270 = (startAngle <= -Math.PI * 0.5 && -Math.PI * 0.5 <= endAngle) || (startAngle <= Math.PI * 1.5 && Math.PI * 1.5 <= endAngle);
      var cutout = cutoutPercentage / 100.0;
      var min = {x: contains180 ? -1 : Math.min(start.x * (start.x < 0 ? 1 : cutout), end.x * (end.x < 0 ? 1 : cutout)), y: contains270 ? -1 : Math.min(start.y * (start.y < 0 ? 1 : cutout), end.y * (end.y < 0 ? 1 : cutout))};
      var max = {x: contains0 ? 1 : Math.max(start.x * (start.x > 0 ? 1 : cutout), end.x * (end.x > 0 ? 1 : cutout)), y: contains90 ? 1 : Math.max(start.y * (start.y > 0 ? 1 : cutout), end.y * (end.y > 0 ? 1 : cutout))};
      var size = {width: (max.x - min.x) * 0.5, height: (max.y - min.y) * 0.5};
      minSize = Math.min(availableWidth / size.width, availableHeight / size.height);
      offset = {x: (max.x + min.x) * -0.5, y: (max.y + min.y) * -0.5};
    }

    chart.borderWidth = me.getMaxBorderWidth(meta.data);
    chart.outerRadius = Math.max((minSize - chart.borderWidth) / 2, 0);
    chart.innerRadius = Math.max(cutoutPercentage ? (chart.outerRadius / 100) * (cutoutPercentage) : 0, 0);
    chart.radiusLength = ((chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount()) + 25;
    chart.offsetX = offset.x * chart.outerRadius;
    chart.offsetY = offset.y * chart.outerRadius;

    meta.total = me.calculateTotal();

    me.outerRadius = chart.outerRadius - (chart.radiusLength * me.getRingIndex(me.index));
    me.innerRadius = Math.max(me.outerRadius - chart.radiusLength, 0);

    // factor in the radius buffer if the chart has more than 1 dataset
    if (me.index > 0) {
      me.outerRadius -= opts.datasetRadiusBuffer;
      me.innerRadius -= opts.datasetRadiusBuffer;
    }

    helpers.each(meta.data, function(arc, index) {
      me.updateElement(arc, index, reset);
    });
  },
});

You can see a live example at this codepen.




回答2:


To make it work with the latest ChartJS 2.7.2, I've just copied the source as suggested from https://github.com/chartjs/Chart.js/blob/master/src/controllers/controller.doughnut.js. Then I added the patch:

if (me.index > 0) {
  me.outerRadius -= opts.datasetRadiusBuffer;
  me.innerRadius -= opts.datasetRadiusBuffer;
}

Everything was working as expected.



来源:https://stackoverflow.com/questions/43202276/chart-js-v2-space-between-doughnut-inside-doughnut

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!