【问题标题】:Chart.js Doughnut with rounded edges and text centeredChart.js 圆角边缘和文本居中的甜甜圈
【发布时间】:2016-09-19 22:14:37
【问题描述】:

我正在尝试实现类似于本文here的圆角,但结合中心的文本,到目前为止我有下面的代码,但我不确定如何结合这两种想法

任何帮助将不胜感激!

图片如下所示,带有文字图片的甜甜圈:

我的代码如下在甜甜圈内生成文本。

Chart.types.Doughnut.extend({
   name: "DoughnutTextInside",
   showTooltip: function() {
       this.chart.ctx.save();
       Chart.types.Doughnut.prototype.showTooltip.apply(this, arguments);
       this.chart.ctx.restore();
},
draw: function() {
    Chart.types.Doughnut.prototype.draw.apply(this, arguments);

    var width = this.chart.width,
        height = this.chart.height;

    var fontSize = (height / 114).toFixed(2);
    this.chart.ctx.font = fontSize + "em Lato";
    this.chart.ctx.textBaseline = "middle";

    var text = "40%",
        textX = Math.round((width - this.chart.ctx.measureText(text).width) / 2),
        textY = height / 2;

    this.chart.ctx.fillText(text, textX, textY);
   }
});

var data = [{
   label: "Wins %",
   value: 120,
   color: "#2ecc71"
}, {
   label: "Losses %",
   value: 240,
   color: "#dddddd"
}, {
   value: 0,
   color: "#888888"
}];

var DoughnutTextInsideChart = new Chart($('#myChart')  [0].getContext('2d')).DoughnutTextInside(data, {
   responsive: true,
   segmentShowStroke: false,
   animationEasing: "easeInOutQuint",
});

【问题讨论】:

    标签: user-interface graph chart.js rounded-corners donut-chart


    【解决方案1】:

    在 v2.1.3 中,您可以使用 pluginService 来执行此操作


    预览


    脚本

    // round corners
    Chart.pluginService.register({
        afterUpdate: function (chart) {
            if (chart.config.options.elements.arc.roundedCornersFor !== undefined) {
                var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor];
                arc.round = {
                    x: (chart.chartArea.left + chart.chartArea.right) / 2,
                    y: (chart.chartArea.top + chart.chartArea.bottom) / 2,
                    radius: (chart.outerRadius + chart.innerRadius) / 2,
                    thickness: (chart.outerRadius - chart.innerRadius) / 2 - 1,
                    backgroundColor: arc._model.backgroundColor
                }
            }
        },
    
        afterDraw: function (chart) {
            if (chart.config.options.elements.arc.roundedCornersFor !== undefined) {
                var ctx = chart.chart.ctx;
                var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor];
                var startAngle = Math.PI / 2 - arc._view.startAngle;
                var endAngle = Math.PI / 2 - arc._view.endAngle;
    
                ctx.save();
                ctx.translate(arc.round.x, arc.round.y);
                console.log(arc.round.startAngle)
                ctx.fillStyle = arc.round.backgroundColor;
                ctx.beginPath();
                ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI);
                ctx.arc(arc.round.radius * Math.sin(endAngle), arc.round.radius * Math.cos(endAngle), arc.round.thickness, 0, 2 * Math.PI);
                ctx.closePath();
                ctx.fill();
                ctx.restore();
            }
        },
    });
    
    // write text plugin
    Chart.pluginService.register({
        afterUpdate: function (chart) {
            if (chart.config.options.elements.center) {
                var helpers = Chart.helpers;
                var centerConfig = chart.config.options.elements.center;
                var globalConfig = Chart.defaults.global;
                var ctx = chart.chart.ctx;
    
                var fontStyle = helpers.getValueOrDefault(centerConfig.fontStyle, globalConfig.defaultFontStyle);
                var fontFamily = helpers.getValueOrDefault(centerConfig.fontFamily, globalConfig.defaultFontFamily);
    
                if (centerConfig.fontSize)
                    var fontSize = centerConfig.fontSize;
                    // figure out the best font size, if one is not specified
                else {
                    ctx.save();
                    var fontSize = helpers.getValueOrDefault(centerConfig.minFontSize, 1);
                    var maxFontSize = helpers.getValueOrDefault(centerConfig.maxFontSize, 256);
                    var maxText = helpers.getValueOrDefault(centerConfig.maxText, centerConfig.text);
    
                    do {
                        ctx.font = helpers.fontString(fontSize, fontStyle, fontFamily);
                        var textWidth = ctx.measureText(maxText).width;
    
                        // check if it fits, is within configured limits and that we are not simply toggling back and forth
                        if (textWidth < chart.innerRadius * 2 && fontSize < maxFontSize)
                            fontSize += 1;
                        else {
                            // reverse last step
                            fontSize -= 1;
                            break;
                        }
                    } while (true)
                    ctx.restore();
                }
    
                // save properties
                chart.center = {
                    font: helpers.fontString(fontSize, fontStyle, fontFamily),
                    fillStyle: helpers.getValueOrDefault(centerConfig.fontColor, globalConfig.defaultFontColor)
                };
            }
        },
        afterDraw: function (chart) {
            if (chart.center) {
                var centerConfig = chart.config.options.elements.center;
                var ctx = chart.chart.ctx;
    
                ctx.save();
                ctx.font = chart.center.font;
                ctx.fillStyle = chart.center.fillStyle;
                ctx.textAlign = 'center';
                ctx.textBaseline = 'middle';
                var centerX = (chart.chartArea.left + chart.chartArea.right) / 2;
                var centerY = (chart.chartArea.top + chart.chartArea.bottom) / 2;
                ctx.fillText(centerConfig.text, centerX, centerY);
                ctx.restore();
            }
        },
    })
    

    然后

        ...
        options: {
            elements: {
                arc: {
                    roundedCornersFor: 0
                },
                center: {
                    // the longest text that could appear in the center
                    maxText: '100%',
                    text: '67%',
                    fontColor: '#FF6684',
                    fontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
                    fontStyle: 'normal',
                    // fontSize: 12,
                    // if a fontSize is NOT specified, we will scale (within the below limits) maxText to take up the maximum space in the center
                    // if these are not specified either, we default to 1 and 256
                    minFontSize: 1,
                    maxFontSize: 256,
                }
            }
        }
    };
    

    如果你不希望它是通用的,你可以去掉一些代码(例如,如果你修复 fontSize,如果你修复索引为 round 等)


    小提琴 - http://jsfiddle.net/cd3fdoy9/

    【讨论】:

    • 在您的代码中,您“禁用”了悬停(分配相同的颜色),是否有办法使其保持启用状态,但将 2 个绘制的圆圈标记为元素的一部分(以便它们正确突出显示)?
    • 有没有办法在中心标签中插入换行符?我看到了你关于工具提示换行符的帖子 (stackoverflow.com/a/37099412/665783),但它不适用于此文本。
    • 我可以问一个愚蠢的问题吗?我应该在哪里添加插件?在使用 npm 安装的 chaart.js 文件中?
    • @user7334203 - 在 Chart.js 文件之后和调用之前绘制图表。
    • 嗨@potatopeelings 在这种情况下它对我有用。但是如果有多个部分,我们怎样才能得到那些圆角呢?
    【解决方案2】:

    我添加了一段代码来更改单击图例时的中心文本。

    afterDraw: function (chart) {
        if (chart.center) {
            var ctx = chart.chart.ctx;
    
            var i,a,s;
            var n = chart;
            var total = 0;
            for(i=0,a=(n.data.datasets||[]).length;a>i;++i){
                s = n.getDatasetMeta(i);
                var x;
                for(x=0; x<s.data.length; x++){
                    if (!s.data[x].hidden)
                        total += n.data.datasets[i].data[x];
                }
            }
    
            ctx.save();
            ctx.font = chart.center.font;
            ctx.fillStyle = chart.center.fillStyle;
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            var centerX = (chart.chartArea.left + chart.chartArea.right) / 2;
            var centerY = (chart.chartArea.top + chart.chartArea.bottom) / 2;
            ctx.fillText(total, centerX, centerY);
            ctx.restore();
        }
    }
    

    小提琴 - http://jsfiddle.net/cd3fdoy9/49/

    【讨论】:

    • 感谢您的调整。 :)
    【解决方案3】:

    稍微修改了代码以处理弧中 arc.borderWidth 的使用(如果使用)。对于 Charts.js 的 2.8 版

    Chart.pluginService.register({
    afterUpdate: function (chart) {
        if (chart.config.options.elements.arc.roundedCornersFor !== undefined) {
            var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor];
            arc.round = {
                x: (chart.chartArea.left + chart.chartArea.right + chart.config.options.elements.arc.borderWidth) / 2,
                y: (chart.chartArea.top + chart.chartArea.bottom) / 2,
                radius: (chart.outerRadius + chart.innerRadius) / 2,
                thickness: (chart.outerRadius - chart.innerRadius - (chart.config.options.elements.arc.borderWidth /2)) / 2 -1,
                backgroundColor: arc._model.backgroundColor
            };
        }
    },
    
    afterDraw: function (chart) {
        if (chart.config.options.elements.arc.roundedCornersFor !== undefined) {
            var ctx = chart.chart.ctx;
            var arc = chart.getDatasetMeta(0).data[chart.config.options.elements.arc.roundedCornersFor];
            var startAngle = Math.PI / 2 - arc._view.startAngle;
            var endAngle = Math.PI / 2 - arc._view.endAngle;
    
            ctx.save();
            ctx.translate(arc.round.x, arc.round.y);
            ctx.fillStyle = arc.round.backgroundColor;
            ctx.beginPath();
            ctx.arc(arc.round.radius * Math.sin(startAngle), arc.round.radius * Math.cos(startAngle), arc.round.thickness, 0, 2 * Math.PI);
            ctx.arc(arc.round.radius * Math.sin(endAngle), arc.round.radius * Math.cos(endAngle), arc.round.thickness, 0, 2 * Math.PI);
            ctx.closePath();
            ctx.fill();
            ctx.restore();
        }
    }
    

    });

    【讨论】:

      【解决方案4】:

      我从事同一个项目并制作这个

        Chart.defaults.RoundedDoughnut = Chart.helpers.clone(Chart.defaults.doughnut);
        const costume = Chart.controllers.doughnut.extend({
          draw(ease) {
            Chart.controllers.doughnut.prototype.draw.call(this, ease);
            const { ctx } = this.chart.chart;
      
            const easingDecimal = ease || 1;
            const arcs = this.getMeta().data;
      
            Chart.helpers.each(arcs, function(arc, index) {
              arc.transition(easingDecimal).draw();
      
              const vm = arc._view;
      
              const radius = (vm.outerRadius + vm.innerRadius) / 2;
              const thickness = (vm.outerRadius - vm.innerRadius - 2) / 2;
              const startAngle = Math.PI - vm.startAngle - Math.PI / 2;
              const angle = Math.PI - vm.endAngle - Math.PI / 2;
      
              if (index % 2 == 1) {
                ctx.save();
                ctx.fillStyle = vm.backgroundColor;
      
                ctx.translate(vm.x, vm.y);
                ctx.beginPath();
                ctx.arc(
                  radius * Math.sin(startAngle),
                  radius * Math.cos(startAngle),
                  thickness,
                  0,
                  2 * Math.PI,
                );
                ctx.fill();
                ctx.fillStyle = vm.backgroundColor;
                ctx.beginPath();
                ctx.arc(
                  radius * Math.sin(angle),
                  radius * Math.cos(angle),
                  thickness,
                  0,
                  2 * Math.PI,
                );
                ctx.fill();
                ctx.restore();
              }
              if (index == 2) {
                ctx.save();
                ctx.fillStyle = arcs[1]._view.backgroundColor;
      
                ctx.translate(vm.x, vm.y);
                ctx.beginPath();
                ctx.arc(
                  radius * Math.sin(startAngle),
                  radius * Math.cos(startAngle),
                  thickness,
                  0,
                  2 * Math.PI,
                );
                ctx.fill();
                ctx.restore();
              }
            });
          },
        });
      
        const deliveredData = {
          labels: ['1', '2', '3', '4'],
          datasets: [
            {
              data: [5, 40, 5, 30],
              backgroundColor: ['#fff', '#ff0000', '#fff', '#ffff00'],
            },
          ],
        };
      
        Chart.controllers.RoundedDoughnut = costume;
        const newChartInstance = new Chart(chartRef.current, {
          type: 'RoundedDoughnut',
          data: deliveredData,
          options: { cutoutPercentage: 75, legend: { display: false }, tooltips: { enabled: false } },
        });
      

      【讨论】:

        猜你喜欢
        • 2016-08-24
        • 1970-01-01
        • 1970-01-01
        • 2014-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多