html canvas - 扩大圆环图上的笔划宽度

html canvas - enlarge stroke width on donut chart

我关注了一个 jsfiddle:http://jsfiddle.net/RgLAU/1/

并制作了甜甜圈图。现在,甜甜圈图上有非常细的白色笔划,将甜甜圈的每个部分分开。例如,在下图中,您可以(勉强)看到甜甜圈有 6 个部分,用白色笔画描绘。

我的问题是我想在不增加图表整体厚度的情况下增加这些线条的粗细,这样中断看起来更像这样:

这是我的 JS。非常感谢任何帮助。:

var donutVm = this;

donutVm.donutHeight = donutVm.donutHeightConfig || 150;
donutVm.donutWidth = donutVm.donutWidthConfig || 150;
donutVm.donutRadius = donutVm.donutRadiusConfig || 50;

if (CommunityConfig.conversionContestActionId) {
    ActionService.get({ id: CommunityConfig.conversionContestActionId, type: 'action' }).$promise.then(function (response) {
        if (CommunityConfig.conversionContestConversionCountTarget) donutVm.totalConversions = CommunityConfig.conversionContestConversionCountTarget;
        var action = response;
        if (action.linkReference) {
            action.getContextFromLinkReference(action.linkReference, function (error, context) {
                var conversionsMade = context.conversionCount;

                var canvas  = document.getElementById("chart");
                var chart = canvas.getContext("2d");

                function drawDonutChart(canvas)
                {
                    donutVm.x, donutVm.y, donutVm.radius, donutVm.lineWidth, donutVm.strokeStyle, donutVm.from, donutVm.to = null;
                    donutVm.set = function( x, y, radius, from, to, lineWidth, strokeStyle) {
                        donutVm.x = x;
                        donutVm.y = y;
                        donutVm.radius = radius;
                        donutVm.from = from;
                        donutVm.to = to;
                        donutVm.lineWidth = lineWidth;
                        donutVm.strokeStyle = strokeStyle;
                    };

                    donutVm.draw = function(data) {
                        canvas.beginPath();
                        canvas.lineWidth = donutVm.lineWidth;
                        canvas.strokeStyle = donutVm.strokeStyle;
                        canvas.arc(donutVm.x, donutVm.y, donutVm.radius, donutVm.from, donutVm.to);
                        canvas.stroke();
                        var numberOfParts = data.numberOfParts;
                        var parts = data.parts.pt;
                        var colors = data.colors.cs;
                        var df = 1.5 * Math.PI;

                        for(var i = 0; i < numberOfParts; i++) {
                            canvas.beginPath();
                            canvas.strokeStyle = colors[i];
                            canvas.arc(donutVm.x, donutVm.y, donutVm.radius, df, df + (Math.PI * 2) * (parts[i] / 100));
                            canvas.stroke();
                            df += (Math.PI * 2) * (parts[i] / 100);
                        }
                    }
                }

                var sections = {"pt": []};
                var sectionColors = {"cs": []};
                var emptyColor = "lightgrey";
                var madeColor = CommunityConfig.styles.buttonColor;
                var sectionPercentage = 100/donutVm.totalConversions;

                if (conversionsMade == donutVm.totalConversions) {
                    for (var y = 0; y < conversionsMade; y++) {
                        sectionColors.cs.push(emptyColor);
                    }
                } else {
                    for (var y = 0; y < conversionsMade; y++) {
                        sectionColors.cs.push(madeColor);
                    }

                    while (sectionColors.cs.length < donutVm.totalConversions) {
                        sectionColors.cs.push(emptyColor);
                    }
                }

                for (var i = 0; i < donutVm.totalConversions; i++){
                    sections.pt.push(sectionPercentage);
                }

                var data = {
                    numberOfParts: donutVm.totalConversions,
                    parts: sections,
                    colors: sectionColors
                };

                var drawDonut = new drawDonutChart(chart);
                donutVm.set(canvas.width / 2, canvas.height / 2, donutVm.donutRadius, 0, Math.PI*2, 10, "#fff");
                donutVm.draw(data);
                donutVm.donutFinished = true;

一种方法是在为截面绘制圆弧时使用较小的角度。
在这个 fiddle 中,我将每个部分缩小了 1% 以便有可见的间隙:http://jsfiddle.net/a7mh9wcv/

canvas.arc(this.x, this.y, this.radius, df, df + (Math.PI * 2) * ((parts[i] - 1) / 100));

另一种方法是将间隙实际绘制为线:http://jsfiddle.net/jq2nhate/

这必须在绘制部分之后完成,这样部分就不会覆盖间隙。

一个简单的方法是在所有部分之间添加一个 space,方法是将所有部分减少一小部分。当然,这意味着您必须检查最小百分比才能显示项目的弧线。我没有花太多时间做出完整的解决方案。

您还需要:

  1. 添加一些对最小弧长的检查
  2. 在 "set function"
  3. 中设置另一个间距

下面是我在你分享的JsFiddlelink中测试的(看使用canvas.arc函数的那一行:"df + (Math.PI * 2) * ((parts[i] - 0.5) / 100)"):

var canvas  = document.getElementById("chart");
    var chart = canvas.getContext("2d");

    function drawdountChart(canvas)
    {

        this.x , this.y , this.radius , this.lineWidth , this.strockStyle , this.from , this.to = null;
        this.set = function( x, y, radius, from, to, lineWidth, strockStyle)
        {
            this.x = x;
            this.y = y;
            this.radius = radius;
            this.from=from;
            this.to= to;
            this.lineWidth = lineWidth;
            this.strockStyle = strockStyle; 
        }

        this.draw = function(data)
        {
            canvas.beginPath();
            canvas.lineWidth = this.lineWidth;
            canvas.strokeStyle = this.strockStyle;
            canvas.arc(this.x , this.y , this.radius , this.from , this.to);
            canvas.stroke();
            var numberOfParts = data.numberOfParts;
            var parts = data.parts.pt;
            var colors = data.colors.cs;
            var df = 0;
            for(var i = 0; i<numberOfParts; i++)
            {
                canvas.beginPath();
                canvas.strokeStyle = colors[i];
                canvas.arc(this.x, this.y, this.radius, df, df + (Math.PI * 2) * ((parts[i] - 0.5) / 100));
                canvas.stroke();
                df += (Math.PI * 2) * (parts[i] / 100);
            }
        }
    }
    var data = 
        {
            numberOfParts: 4,
            parts:{"pt": [20 , 30 , 25 , 25]},//percentage of each parts 
            colors:{"cs": ["red", "green", "blue", "yellow"]}//color of each part
        };

    var drawDount = new drawdountChart(chart);
    drawDount.set(150, 150, 100, 0, Math.PI*2, 20, "#fff");
    drawDount.draw(data);

我基本上删除了所有部分的一半,但保持 "df" 变量不变。

像这样的东西应该可以工作:

var donutVm = this;

donutVm.donutHeight = donutVm.donutHeightConfig || 150;
donutVm.donutWidth = donutVm.donutWidthConfig || 150;
donutVm.donutRadius = donutVm.donutRadiusConfig || 50;

if (CommunityConfig.conversionContestActionId) {
    ActionService.get({ id: CommunityConfig.conversionContestActionId, type: 'action' }).$promise.then(function (response) {
        if (CommunityConfig.conversionContestConversionCountTarget) donutVm.totalConversions = CommunityConfig.conversionContestConversionCountTarget;
        var action = response;
        if (action.linkReference) {
            action.getContextFromLinkReference(action.linkReference, function (error, context) {
                var conversionsMade = context.conversionCount;

                var canvas  = document.getElementById("chart");
                var chart = canvas.getContext("2d");

                function drawDonutChart(canvas)
                {
                    donutVm.x, donutVm.y, donutVm.radius, donutVm.lineWidth, donutVm.strokeStyle, donutVm.from, donutVm.to = null;
                    donutVm.set = function( x, y, radius, from, to, lineWidth, strokeStyle) {
                        donutVm.x = x;
                        donutVm.y = y;
                        donutVm.radius = radius;
                        donutVm.from = from;
                        donutVm.to = to;
                        donutVm.lineWidth = lineWidth;
                        donutVm.strokeStyle = strokeStyle;
                    };

                    donutVm.draw = function(data) {
                        canvas.beginPath();
                        canvas.lineWidth = donutVm.lineWidth;
                        canvas.strokeStyle = donutVm.strokeStyle;
                        canvas.arc(donutVm.x, donutVm.y, donutVm.radius, donutVm.from, donutVm.to);
                        canvas.stroke();
                        var numberOfParts = data.numberOfParts;
                        var parts = data.parts.pt;
                        var colors = data.colors.cs;
                        var spacer = 2 * 0.05
                        var df = (1.5 + spacer) * Math.PI;

                        for(var i = 0; i < numberOfParts; i++) {
                            canvas.beginPath();
                            canvas.strokeStyle = colors[i];
                            canvas.arc(donutVm.x, donutVm.y, donutVm.radius, df, df + (Math.PI * 2) * (parts[i] / 100) - (2 * spacer);
                            canvas.stroke();
                            df += (Math.PI * 2) * ((parts[i] / 100) + (2 * spacer));
                        }
                    }
                }

                var sections = {"pt": []};
                var sectionColors = {"cs": []};
                var emptyColor = "lightgrey";
                var madeColor = CommunityConfig.styles.buttonColor;
                var sectionPercentage = 100/donutVm.totalConversions;

                if (conversionsMade == donutVm.totalConversions) {
                    for (var y = 0; y < conversionsMade; y++) {
                        sectionColors.cs.push(emptyColor);
                    }
                } else {
                    for (var y = 0; y < conversionsMade; y++) {
                        sectionColors.cs.push(madeColor);
                    }

                    while (sectionColors.cs.length < donutVm.totalConversions) {
                        sectionColors.cs.push(emptyColor);
                    }
                }

                for (var i = 0; i < donutVm.totalConversions; i++){
                    sections.pt.push(sectionPercentage);
                }

                var data = {
                    numberOfParts: donutVm.totalConversions,
                    parts: sections,
                    colors: sectionColors
                };

                var drawDonut = new drawDonutChart(chart);
                donutVm.set(canvas.width / 2, canvas.height / 2, donutVm.donutRadius, 0, Math.PI*2, 10, "#fff");
                donutVm.draw(data);
                donutVm.donutFinished = true;