ChartJS 在堆栈条形图上创建倒边框半径

4sup72z8  于 9个月前  发布在  Chart.js
关注(0)|答案(1)|浏览(74)

我用的是最新的ChartJS。如何在条形图中实现这种倒边框半径?

const myData = {
  labels: ["1 Jan", "2 Jan", "3 Jan", "4 Jan", "5 Jan", "6 Jan", "7 Jan", "8 Jan"],
  datasets: [{
    label: 'Employee',
    backgroundColor: background_1,
    data: [12, 59, 5, 56, 58, 12, 59, 87, 45],
    borderRadius: 100,
    barPercentage: 0.5, // Adjust this value to change the width of the bars
    categoryPercentage: 0.3,
    borderColor: 'white',
    borderWidth: 1
  }, {
    label: 'Engineer',
    backgroundColor: background_2,
    data: [12, 59, 5, 56, 58, 12, 59, 85, 23],
    borderRadius: 100,
    barPercentage: 0.5, // Adjust this value to change the width of the bars
    categoryPercentage: 0.3,
    borderColor: 'white',
    borderWidth: 1,
    borderSkipped: 'middle'
  }]
}

这是我目前的数据。

tct7dpnv

tct7dpnv1#

chart.js的堆叠条形图已经完成了大部分工作。
创建所述圆形边框的第一步是将borderRadius设置为对象,因此内部条也会获得圆角,例如,borderRadius: {topLeft: 100, topRight: 100, bottomLeft: 100, bottomRight: 100}而不是borderRadius: 100,请参阅文档中有关堆叠图表的borderRadius的提示。
然后,我们将不得不在第一条下延伸第二条(或在相同符号和堆栈的前一条下延伸第n条),这样你就可以在第二条的底部获得“负半径”效果。
这可以通过一个插件来实现,例如在afterDatasetUpdate处理程序中进行计算。
必须保留关于前一个条形图的信息,区分正域和负域,并通过堆栈ID进行索引。所有这些都是细节,最好在代码中看到。

const pluginStackRounded = {// inline plugin, no id
    afterDatasetUpdate(chart, context){
        const plugin = this;
        if(chart.width && chart.height){
            const barElements = context.meta.data,// or chart.getDatasetMeta(context.index).data;
                stackId = context.meta.stack,
                values = context.meta._parsed;
            if(context.index === 0){
                plugin._maxExtension = {};
            }
            if(!plugin._maxExtension[stackId]){
                plugin._maxExtension[stackId] = {
                    positive: Array(values.length).fill(null),
                    negative: Array(values.length).fill(null)
                };
            }

            barElements.forEach(
                (barElement, i) => {
                    const barWidth = barElement.$animations?.width?._active
                            && barElement.$animations?.width._to || barElement.width,
                        barBase = barElement.$animations?.base?._active &&
                            barElement.$animations.base._to || barElement.base,
                        barY = barElement.$animations?.base?._active &&
                            barElement.$animations.y._to || barElement.y,
                        isNegative = barY > barBase; //values[i].y < 0;
                    const maxExtension = 
                        plugin._maxExtension[stackId][isNegative ? "negative" : "positive"][i];
                    if(maxExtension !== null){
                        if(barElement.options.$shared){
                            barElement.options = Object.assign({$shared: false}, barElement.options);
                            barElement.options.borderRadius = Object.assign({}, 
                                barElement.options.borderRadius);
                        }
                        if(!isNegative){
                            barElement.options.borderRadius.bottomLeft = 1;
                            barElement.options.borderRadius.bottomRight = 1;
                        }
                        else{
                            barElement.options.borderRadius.topLeft = 1
                            barElement.options.borderRadius.topRight = 1
                        }
                        if(barElement.$animations?.base?._active){
                            barElement.$animations.base._to = isNegative ?
                                Math.max(barBase - barWidth / 2, maxExtension) :
                                Math.min(barBase + barWidth / 2, maxExtension);
                        }
                        else{
                            barElement.base = isNegative ?
                                Math.max(barElement.base - barWidth, maxExtension) :
                                Math.min(barElement.base + barWidth, maxExtension);
                        }
                    }

                    // update maxExtension for the next dataset
                    const barHeight = barElement.$animations?.height?._active &&
                        barElement.$animations.height._to || barElement.height;
                    if(isNegative){
                        plugin._maxExtension[stackId].negative[i] = barBase + barHeight/2;
                    }
                    else{
                        plugin._maxExtension[stackId].positive[i] = barBase - barHeight/2;
                    }
                }
            );
        }
    }
};

const myData = {
    labels: ["1 Jan", "2 Jan", "3 Jan", "4 Jan", "5 Jan", "6 Jan", "7 Jan", "8 Jan", "9 Jan"],
    datasets: [
        {
            label: 'Employee',
            backgroundColor: '#6fd',
            data: [12, 59, 5, 56, 58, 12, 59, 87, 45],
            stack: "A"
        },
        {
            label: 'Engineer',
            backgroundColor: '#fd6',
            data: [12, 59, 5, 56, 58, 12, 59, 85, 23],
            stack: "A"
        }
    ]
};

const config = {
    type: 'bar',
    data: myData,
    plugins:[pluginStackRounded],
    options: {
        responsive: true,
        datasets: {
            bar: {
                barPercentage: 0.25,
                borderRadius: {topLeft: 100, topRight: 100, bottomLeft: 100, bottomRight: 100},
                borderSkipped: false,
                borderColor: 'white',
                borderWidth: 1
            }
        },
        scales:{
            y:{
                ticks: {
                    stepSize: 20 // for easy verification on the grid
                }
            }
        },
        plugins: {
            legend: {
                position: 'top',
            }
        }
    },
};

new Chart(document.querySelector('#chart1'), config);
<div style="min-height: 60vh">
    <canvas id="chart1">
    </canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.js" integrity="sha512-6HrPqAvK+lZElIZ4mZ64fyxIBTsaX5zAFZg2V/2WT+iKPrFzTzvx6QAsLW2OaLwobhMYBog/+bvmIEEGXi0p1w==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

相关问题