简体   繁体   English

使用 Chart.js 的条形圆角堆叠条形图

[英]Stacked bar chart with rounded corner of bar using Chart.js

I tried various custom example.我尝试了各种自定义示例。 But they are provide only single data, but I need the very last data with round corner但它们只提供单个数据,但我需要最后一个带圆角的数据

https://jsfiddle.net/ankitkothari/7km2ytjo/2/ https://jsfiddle.net/ankitkothari/7km2ytjo/2/

Please refer the above link for the sample code in that I need the top most data is in round corner not bottom data请参考上面的示例代码链接,因为我需要最顶部的数据在圆角而不是底部数据

Please refer the above link for the sample code in that I need the top most data is in round corner not bottom data.请参考上面的示例代码链接,因为我需要最顶部的数据位于圆角而不是底部数据。

Chart.elements.Rectangle.prototype.draw = function() {
    debugger;
    var ctx = this._chart.ctx;
    var vm = this._view;
    var left, right, top, bottom, signX, signY, borderSkipped, radius;
    var borderWidth = vm.borderWidth;
    // Set Radius Here
    // If radius is large enough to cause drawing errors a max radius is imposed
    var cornerRadius = 10;

    if (!vm.horizontal) {
        // bar
        left = vm.x - vm.width / 2;
        right = vm.x + vm.width / 2;
        top = vm.y;
        bottom = vm.base;
        signX = 1;
        signY = bottom > top? 1: -1;
        borderSkipped = vm.borderSkipped || 'bottom';
    } else {
        // horizontal bar
        left = vm.base;
        right = vm.x;
        top = vm.y - vm.height / 2;
        bottom = vm.y + vm.height / 2;
        signX = right > left? 1: -1;
        signY = 1;
        borderSkipped = vm.borderSkipped || 'left';
    }

    // Canvas doesn't allow us to stroke inside the width so we can
    // adjust the sizes to fit if we're setting a stroke on the line
    if (borderWidth) {
        // borderWidth shold be less than bar width and bar height.
        var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
        borderWidth = borderWidth > barSize? barSize: borderWidth;
        var halfStroke = borderWidth / 2;
        // Adjust borderWidth when bar top position is near vm.base(zero).
        var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
        var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
        var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
        var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
        // not become a vertical line?
        if (borderLeft !== borderRight) {
            top = borderTop;
            bottom = borderBottom;
        }
        // not become a horizontal line?
        if (borderTop !== borderBottom) {
            left = borderLeft;
            right = borderRight;
        }
    }

    ctx.beginPath();
    ctx.fillStyle = vm.backgroundColor;
    ctx.strokeStyle = vm.borderColor;
    ctx.lineWidth = borderWidth;

    // Corner points, from bottom-left to bottom-right clockwise
    // | 1 2 |
    // | 0 3 |
    var corners = [
        [left, bottom],
        [left, top],
        [right, top],
        [right, bottom]
    ];

    // Find first (starting) corner with fallback to 'bottom'
    var borders = ['bottom', 'left', 'top', 'right'];
    var startCorner = borders.indexOf(borderSkipped, 0);
    if (startCorner === -1) {
        startCorner = 0;
    }

    function cornerAt(index) {
        return corners[(startCorner + index) % 4];
    }

    // Draw rectangle from 'startCorner'
    var corner = cornerAt(0);
    ctx.moveTo(corner[0], corner[1]);

    for (var i = 1; i < 4; i++) {
        corner = cornerAt(i);
        nextCornerId = i+1;
        if(nextCornerId == 4){
            nextCornerId = 0
        }

        nextCorner = cornerAt(nextCornerId);

        width = corners[2][0] - corners[1][0];
        height = corners[0][1] - corners[1][1];
        x = corners[1][0];
        y = corners[1][1];

        var radius = cornerRadius;

        // Fix radius being too large
        if(radius > height/2){
            radius = height/2;
        }if(radius > width/2){
            radius = width/2;
        }

        ctx.moveTo(x + radius, y);
        ctx.lineTo(x + width - radius, y);
         ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
        ctx.lineTo(x + width, y + height - radius);
        ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
        ctx.lineTo(x + radius, y + height);
        ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
        ctx.lineTo(x, y + radius);
        ctx.quadraticCurveTo(x, y, x + radius, y);

    }

    ctx.fill();
    if (borderWidth) {
        ctx.stroke();
    }
}; 
 var data = {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                '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)'
            ],
            borderWidth: 5
        },{
            label: '# of Votes',
            data: [20, 5, 10, 15, 12, 13],
            backgroundColor: [
             'rgba(255, 159, 64, 1)',
                'rgba(255, 99, 132, 1)',               
                'rgba(255, 206, 86, 1)',

                'rgba(54, 162, 235, 1)',
                'rgba(153, 102, 255, 1)',
                 'rgba(75, 192, 192, 1)'

            ],
            borderWidth: 5
        }]
    };
var options = {
elements:{ point: {
     radius:25,
     hoverRadius:35,
     pointStyle:'rectRounded'
    }},
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                },
                stacked : true,
                radius:25
            }],
            xAxes: [{
                ticks: {
                    beginAtZero:true
                },
                stacked : true,

            }]
        }
    };




var ctxBar = document.getElementById("myChart");
var myBarChart = new Chart(ctxBar, {
    type: 'bar',
    data: data,
    options: options
});

I changed your fiddle so only the top rectangle borders are round.我改变了你的小提琴,所以只有顶部的矩形边框是圆形的。 The trick is to use the chart's getDatasetMeta to check for visibility state of rectangles and decide depending if it is the last visible om stack.诀窍是使用图表的 getDatasetMeta 来检查矩形的可见性状态,并根据它是否是最后一个可见的 om 堆栈来决定。

This will only work for your example data of two datasets but could be changed to work with an arbitrary amount as well.这仅适用于您的两个数据集的示例数据,但也可以更改为使用任意数量的数据。

https://jsfiddle.net/a6m34c01/ https://jsfiddle.net/a6m34c01/


EDIT: Handle abritrary count of data.编辑:处理数据的 abritrary 计数。

https://jsfiddle.net/a6m34c01/8/ https://jsfiddle.net/a6m34c01/8/

Chart.elements.Rectangle.prototype.draw = function() {
    debugger;
    var ctx = this._chart.ctx;
    var vm = this._view;
    var left, right, top, bottom, signX, signY, borderSkipped, radius;
    var borderWidth = vm.borderWidth;
    // Set Radius Here
    // If radius is large enough to cause drawing errors a max radius is imposed
    var cornerRadius = 10;

    if (!vm.horizontal) {
        // bar
        left = vm.x - vm.width / 2;
        right = vm.x + vm.width / 2;
        top = vm.y;
        bottom = vm.base;
        signX = 1;
        signY = bottom > top? 1: -1;
        borderSkipped = vm.borderSkipped || 'bottom';
    } else {
        // horizontal bar
        left = vm.base;
        right = vm.x;
        top = vm.y - vm.height / 2;
        bottom = vm.y + vm.height / 2;
        signX = right > left? 1: -1;
        signY = 1;
        borderSkipped = vm.borderSkipped || 'left';
    }

    // Canvas doesn't allow us to stroke inside the width so we can
    // adjust the sizes to fit if we're setting a stroke on the line
    if (borderWidth) {
        // borderWidth shold be less than bar width and bar height.
        var barSize = Math.min(Math.abs(left - right), Math.abs(top - bottom));
        borderWidth = borderWidth > barSize? barSize: borderWidth;
        var halfStroke = borderWidth / 2;
        // Adjust borderWidth when bar top position is near vm.base(zero).
        var borderLeft = left + (borderSkipped !== 'left'? halfStroke * signX: 0);
        var borderRight = right + (borderSkipped !== 'right'? -halfStroke * signX: 0);
        var borderTop = top + (borderSkipped !== 'top'? halfStroke * signY: 0);
        var borderBottom = bottom + (borderSkipped !== 'bottom'? -halfStroke * signY: 0);
        // not become a vertical line?
        if (borderLeft !== borderRight) {
            top = borderTop;
            bottom = borderBottom;
        }
        // not become a horizontal line?
        if (borderTop !== borderBottom) {
            left = borderLeft;
            right = borderRight;
        }
    }

    ctx.beginPath();
    ctx.fillStyle = vm.backgroundColor;
    ctx.strokeStyle = vm.borderColor;
    ctx.lineWidth = borderWidth;

    // Corner points, from bottom-left to bottom-right clockwise
    // | 1 2 |
    // | 0 3 |
    var corners = [
        [left, bottom],
        [left, top],
        [right, top],
        [right, bottom]
    ];

    // Find first (starting) corner with fallback to 'bottom'
    var borders = ['bottom', 'left', 'top', 'right'];
    var startCorner = borders.indexOf(borderSkipped, 0);
    if (startCorner === -1) {
        startCorner = 0;
    }

    function cornerAt(index) {
        return corners[(startCorner + index) % 4];
    }

    // Draw rectangle from 'startCorner'
    var corner = cornerAt(0);
    ctx.moveTo(corner[0], corner[1]);

    for (var i = 1; i < 4; i++) {
        corner = cornerAt(i);
        nextCornerId = i+1;
        if(nextCornerId == 4){
            nextCornerId = 0
        }

        nextCorner = cornerAt(nextCornerId);

        width = corners[2][0] - corners[1][0];
        height = corners[0][1] - corners[1][1];
        x = corners[1][0];
        y = corners[1][1];

        var radius = cornerRadius;

        // Fix radius being too large
        if(radius > height/2){
            radius = height/2;
        }if(radius > width/2){
            radius = width/2;
        }



        var lastVisible = 0;
        for(var findLast=0, findLastTo=this._chart.data.datasets.length;findLast<findLastTo;findLast++) {
            if (!this._chart.getDatasetMeta(findLast).hidden) {
            lastVisible =findLast;
          }
        }
        var rounded = this._datasetIndex  === lastVisible;

        if (rounded) {
          ctx.moveTo(x + radius, y);
          ctx.lineTo(x + width - radius, y);
          ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
          ctx.lineTo(x + width, y + height);
          ctx.lineTo(x, y + height);
          ctx.lineTo(x, y + radius);
          ctx.quadraticCurveTo(x, y, x + radius, y);
        } else {
          ctx.moveTo(x, y);
          ctx.lineTo(x + width, y);
          ctx.lineTo(x + width, y + height );
          ctx.lineTo(x , y + height);
          ctx.lineTo(x, y );
        }

    }

    ctx.fill();
    if (borderWidth) {
        ctx.stroke();
    }
}; 
 var data = {
    labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
        datasets: [{
            label: '# of Votes',
            data: [12, 19, 3, 5, 2, 3],
            backgroundColor: [
                '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)'
            ],
            borderWidth: 5
        },{
            label: '# of Votes',
            data: [20, 5, 10, 15, 12, 13],
            backgroundColor: [
             'rgba(255, 159, 64, 1)',
                'rgba(255, 99, 132, 1)',               
                'rgba(255, 206, 86, 1)',

                'rgba(54, 162, 235, 1)',
                'rgba(153, 102, 255, 1)',
                 'rgba(75, 192, 192, 1)'

            ],
            borderWidth: 5
        }]
    };
var options = {
elements:{ point: {
     radius:25,
     hoverRadius:35,
     pointStyle:'rectRounded'
    }},
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero:true
                },
                stacked : true,
                radius:25
            }],
            xAxes: [{
                ticks: {
                    beginAtZero:true
                },
                stacked : true,

            }]
        }
    };




var ctxBar = document.getElementById("myChart");
var myBarChart = new Chart(ctxBar, {
    type: 'bar',
    data: data,
    options: options
});

This will be added in the next major release.这将在下一个主要版本中添加。 https://www.chartjs.org/docs/master/charts/bar#borderradius https://www.chartjs.org/docs/master/charts/bar#borderradius

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM