在chartjs中的堆栈条形图上创建倒置边框半径

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

大家好,我正在使用最新的图表。我怎样才能在条形图中实现这种倒置的边框半径?请帮忙。预先感谢。

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'
  }]
}

这是我当前的数据。

chart.js
1个回答
0
投票

chart.js的堆积条形图已经 做大部分事情。

创建所描述的圆形边框的第一步, 就是将

borderRadius
设置为一个对象,所以内部的bars 也有圆角,例如,
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>

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