甜甜圈在一个方向上有圆形边缘,各段之间有白色边框

问题描述 投票:0回答:1

Chart js Donut 段不向一个方向显示。第一个和最后一个部分未按预期工作 enter image description here

期望:需要图表 js 甜甜圈圆形段显示在一个方向上,段之间有白色边框 enter image description here

代码

    // Create a custom Doughnut type with rounded segments
    Chart.defaults.RoundedDoughnut = Chart.helpers.clone(Chart.defaults.doughnut);
    Chart.controllers.RoundedDoughnut = Chart.controllers.doughnut.extend({
      draw: function(ease) {
        var ctx = this.chart.ctx;
        var easingDecimal = ease || 1;
        var arcs = this.getMeta().data;
        var borderWidth = 20; // Width of the white border for space between segments
        Chart.helpers.each(arcs, function(arc, i) {
          var vm = arc._view;
          var startAngle = vm.startAngle;
          var endAngle = vm.endAngle;
          var radius = (vm.outerRadius + vm.innerRadius) / 2;
          var thickness = (vm.outerRadius - vm.innerRadius) / 2;
          ctx.save();
          ctx.translate(vm.x, vm.y);
          // Draw each arc segment with a white border to create spacing
          ctx.beginPath();
          ctx.arc(0, 0, radius, startAngle, endAngle);
          ctx.lineWidth = thickness * 2 + borderWidth; // Increase width to add border
          ctx.strokeStyle = '#FFFFFF'; // Set border color to white
          ctx.lineCap = 'round'; // Ensure all segments are rounded on both ends
          ctx.stroke();
          // Draw inner colored arc over the white border to make it look like a gap
          ctx.beginPath();
          ctx.arc(0, 0, radius, startAngle, endAngle);
          ctx.lineWidth = thickness * 2;
          ctx.strokeStyle = vm.backgroundColor; // Set segment color
          ctx.stroke();

          ctx.restore();
        });
      }
    });
    // Initialize the chart
    window.onload = function() {
      new Chart(document.getElementById('usersChart'), {
        type: 'RoundedDoughnut',
        data: {
          datasets: [{
            data: [10, 10, 10, 10, 10, 10, 10, 10], // Adjust data values for even segments
            backgroundColor: [
              '#5da4e7', '#8fbbe7', '#addbf0', '#4b8de7',
              '#4da466', '#8ec486', '#b3dba8', '#63b571'
            ],
            borderWidth: 0
          }]
        },
        options: {
          cutoutPercentage: 70,
          tooltips: {
            enabled: false
          } // Optional: Disable tooltips to prevent hover issues
        }
      });
    };
<canvas id="usersChart" width="400" height="400"></canvas>
javascript jquery chart.js donut-chart
1个回答
1
投票

您应该指定您正在使用的chart.js版本,以防它不是 最新的,但似乎不是,因为您的代码 自定义控制器与最新 v4 版本的 Chart.js 不兼容。

无论如何,问题是概念性的,即圆形“甲板”的想法 卡”,每张卡都被下一张卡部分覆盖,无法实现 通过抽整张牌,因为这种方法必然有一张牌 完全可见,一张卡两端都被覆盖。

另一种选择是抽半张牌,这会起作用,除了在 当扇区的大小非常小时的情况 - 那么可见 半扇区太多,扇区会错误重叠。

最好的解决方案似乎是实际绘制重叠部分,使用

context.fill
函数,填充半圆,而不是
context.stroke
非常粗的弧线,末端呈圆形。

这是该想法的实现,使用最新的 Chart.js v4 兼容 控制器;应该很容易使其适应旧版本:

class RoundedDoughnut extends Chart.controllers.doughnut {
    static id = "roundedDoughnut";
    draw(...args) {
        super.draw(...args);

        const ctx = this.chart.ctx;
        const arcs = this.getMeta().data;
        const borderWidth = 10;
        const borderColor = 'white';

        if(arcs.length === 0){
            return;
        }

        ctx.save();

        const arc = arcs[0];
        ctx.strokeStyle = borderColor;
        ctx.lineWidth = borderWidth;
        ctx.beginPath();
        ctx.arc(arc.x, arc.y, arc.innerRadius, 0, 2*Math.PI);
        ctx.stroke();
        ctx.beginPath();
        ctx.arc(arc.x, arc.y, arc.outerRadius, 0, 2*Math.PI);
        ctx.stroke();

        for(const arc of arcs){
            const startAngle = arc.startAngle,
                radius = (arc.outerRadius + arc.innerRadius) / 2,
                thickness = (arc.outerRadius - arc.innerRadius) / 2 - borderWidth;
            const x0 = arc.x + radius * Math.cos(startAngle),
                y0 = arc.y + radius * Math.sin(startAngle);
            ctx.beginPath();
            ctx.arc(x0, y0, thickness, Math.PI + startAngle, 2*Math.PI + startAngle);
            ctx.lineTo(x0 - thickness * Math.cos(startAngle), y0 - thickness * Math.sin(startAngle));
            ctx.fillStyle = arc.options.backgroundColor;
            ctx.strokeStyle = arc.options.backgroundColor;
            ctx.lineWidth = borderWidth;
            ctx.fill();
            ctx.stroke();

            ctx.beginPath();
            ctx.arc(x0, y0, thickness + borderWidth, Math.PI + startAngle, 2*Math.PI + startAngle);
            ctx.strokeStyle = borderColor;
            ctx.stroke();
        }
        ctx.restore();

    }
}

Chart.registry.controllers.register(RoundedDoughnut)

new Chart(document.getElementById('usersChart'), {
    type: 'roundedDoughnut',
    data: {
        datasets: [{
            data: [10, 10, 10, 10, 10, 10, 10, 10], // Adjust data values for even segments
            backgroundColor: [
                '#5da4e7', '#8fbbe7', '#addbf0', '#4b8de7',
                '#4da466', '#8ec486', '#b3dba8', '#63b571'
            ],
            borderWidth: 0
        }]
    },
    options: {
        cutoutPercentage: 70,
        layout:{
            padding: 10
        },
        plugins: {
            tooltip: {
                enabled: false
            } // Optional: Disable tooltips to prevent hover issues
        }
    }
});
<div style="width:400px; height: 400px">
<canvas id="usersChart"></canvas>
</div>

<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

© www.soinside.com 2019 - 2024. All rights reserved.