Chart JS Chartjs-plugin-datalabels 获取数据集标签并显示

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

我目前正在尝试 chartjs-plugin-datalabels,并且我正在尝试将折线图上的标签设置为底部轴上的特定日期。

示例展示了如何为每2个点设置标签,所以我有一个基本的想法从哪里开始。但我想要的是在特定点上显示诸如“大事件”之类的自定义标签,我可以在其中与轴点名称的数据集标签进行匹配。

因此,如果轴数据点标签等于“2018 年 10 月”,请在图表上添加一个特定标签,注明“此处为重大事件”。

图表示例:

var linuxonly = document.getElementById('linuxonly');
    var Chartlinuxonly = new Chart(linuxonly, {
    type: 'line',
    plugins: [ChartDataLabels],
    data: {
    labels: ['Sep-2018','Oct-2018','Nov-2018','Dec-2018','Jan-2019','Feb-2019','Mar-2019','Apr-2019','May-2019','Jun-2019','Jul-2019','Aug-2019','Sep-2019','Oct-2019','Nov-2019','Dec-2019','Jan-2020','Feb-2020','Mar-2020','Apr-2020','May-2020','Jun-2020','Jul-2020','Aug-2020','Sep-2020','Oct-2020','Nov-2020','Dec-2020','Jan-2021','Feb-2021','Mar-2021','Apr-2021','May-2021','Jun-2021','Jul-2021','Aug-2021','Sep-2021','Oct-2021','Nov-2021','Dec-2021','Jan-2022','Feb-2022','Mar-2022','Apr-2022','May-2022','Jun-2022','Jul-2022','Aug-2022','Sep-2022','Oct-2022','Nov-2022','Dec-2022','Jan-2023','Feb-2023','Mar-2023','Apr-2023','May-2023','Jun-2023','Jul-2023','Aug-2023','Sep-2023','Oct-2023','Nov-2023','Dec-2023','Jan-2024'],
    datasets: [
    {
        label: 'Linux',
        lineTension: 0,
        fill: false,
        data: [0.78, 0.72, 0.80, 0.82, 0.82, 0.77, 0.82, 0.81, 0.84, 0.76, 0.79, 0.80, 0.83, 0.83, 0.81, 0.83, 0.90, 0.83, 0.87, 0.89, 0.91, 0.88, 0.86, 0.89, 0.94, 0.90, 0.90, 0.78, 0.91, 0.81, 0.85, 0.85, 0.86, 0.89, 1.00, 1.02, 1.05, 1.13, 1.16, 1.11, 1.06, 1.02, 1.00, 1.14, 1.12, 1.18, 1.23, 1.27, 1.23, 1.28, 1.44, 1.38, 1.38, 1.27, 0.84, 1.32, 1.47, 1.44, 1.96, 1.82, 1.63, 1.39, 1.91, 1.97, 1.95],
        backgroundColor: '#0C7BDC',
        borderColor: '#0C7BDC',
        borderWidth: 1,
       trendlineLinear: {
            style: '#DC267F',
            lineStyle: 'dotted',
            width: 2
        }
    }]
        },
        options: {
            legend: {
                display: true
            },
            responsive: true,
            maintainAspectRatio: false,
    scales: {
    yAxes: [{
        ticks: {
        beginAtZero:true
        },
                    scaleLabel: {
                display: true,
                labelString: 'Percentage of Steam users'
            }
    }]
    },
            tooltips:
            {
                callbacks: {
                    label: function(tooltipItem, data) {
        var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
                        var label = data.datasets[tooltipItem.datasetIndex].label;
        return label + ' ' + value + '%';
            }
            },
            },
            plugins: {
            datalabels: {
    display: function(context) {
    console.log(context)

}
}
}
    }
    });
chart.js
1个回答
2
投票

正如我怀疑的那样(在评论中),日期来自

x
轴,因此识别正确的数据点有点复杂 在数据标签中
formatter
。你必须使用第二个参数,我称之为
ctx

options: {
    plugins: {
        datalabels: {
            formatter: function(value, ctx) {
                return ctx.chart.data.labels[ctx.dataIndex] === 'Aug-2019' ?
                    'Big Event' : null;
            },
            // other datalabels options.
        }
    }
}

这是基于您的代码的代码片段,适用于 Chart.js v4,并带有此

formatter
和其他一些 Chart.js 选项。我还制作了半径 所选点较大,以便您可以看到它是哪一个并决定标签的锚定和对齐。

new Chart('linuxonly', {
    type: 'line',
    plugins: [ChartDataLabels],
    data: {
        labels: ['Sep-2018','Oct-2018','Nov-2018','Dec-2018','Jan-2019','Feb-2019','Mar-2019','Apr-2019','May-2019','Jun-2019','Jul-2019','Aug-2019','Sep-2019','Oct-2019','Nov-2019','Dec-2019','Jan-2020','Feb-2020','Mar-2020','Apr-2020','May-2020','Jun-2020','Jul-2020','Aug-2020','Sep-2020','Oct-2020','Nov-2020','Dec-2020','Jan-2021','Feb-2021','Mar-2021','Apr-2021','May-2021','Jun-2021','Jul-2021','Aug-2021','Sep-2021','Oct-2021','Nov-2021','Dec-2021','Jan-2022','Feb-2022','Mar-2022','Apr-2022','May-2022','Jun-2022','Jul-2022','Aug-2022','Sep-2022','Oct-2022','Nov-2022','Dec-2022','Jan-2023','Feb-2023','Mar-2023','Apr-2023','May-2023','Jun-2023','Jul-2023','Aug-2023','Sep-2023','Oct-2023','Nov-2023','Dec-2023','Jan-2024'],
        datasets: [
            {
                label: 'Linux',
                lineTension: 0,
                fill: false,
                data: [0.78, 0.72, 0.80, 0.82, 0.82, 0.77, 0.82, 0.81, 0.84, 0.76, 0.79, 0.80, 0.83, 0.83, 0.81, 0.83, 0.90, 0.83, 0.87, 0.89, 0.91, 0.88, 0.86, 0.89, 0.94, 0.90, 0.90, 0.78, 0.91, 0.81, 0.85, 0.85, 0.86, 0.89, 1.00, 1.02, 1.05, 1.13, 1.16, 1.11, 1.06, 1.02, 1.00, 1.14, 1.12, 1.18, 1.23, 1.27, 1.23, 1.28, 1.44, 1.38, 1.38, 1.27, 0.84, 1.32, 1.47, 1.44, 1.96, 1.82, 1.63, 1.39, 1.91, 1.97, 1.95],
                backgroundColor: '#0C7BDC',
                borderColor: '#0C7BDC',
                borderWidth: 1,
                // trendlineLinear: {
                //     style: '#DC267F',
                //     lineStyle: 'dotted',
                //     width: 2
                // }
            }]
    },
    options: {
        legend: {
            display: true
        },
        responsive: true,
        maintainAspectRatio: false,
        pointRadius: function(ctx){
            return ctx.chart.data.labels[ctx.dataIndex] === 'Aug-2019' ? 8 : 3
        },
        scales: {
            y: {
                ticks: {
                    beginAtZero:true
                },
                title: {
                    display: true,
                    text: 'Percentage of Steam users'
                }
            }
        },
        tooltips:
            {
                callbacks: {
                    label: function(tooltipItem, data) {
                        var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
                        var label = data.datasets[tooltipItem.datasetIndex].label;
                        return label + ' ' + value + '%';
                    }
                },
            },
        plugins: {
            datalabels: {
                formatter: function(value, ctx) {
                     return ctx.chart.data.labels[ctx.dataIndex] === 'Aug-2019' ? 'Big Event' : null;
                 },
                font:{
                    size: 20
                },
                align: 'top',
                offset: 10,
                borderWidth: 1,
                borderColor: '#000',
                backgroundColor: 'rgba(255, 255, 255, 0.2)'
            }
        }
    }
});
<div style="height: 90vh">
    <canvas id="linuxonly" style="background: rgba(192, 192, 192, 0.5)">
    </canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.2.0/chartjs-plugin-datalabels.min.js" integrity="sha512-JPcRR8yFa8mmCsfrw4TNte1ZvF1e3+1SdGMslZvmrzDYxS69J7J49vkFL8u6u8PlPJK+H3voElBtUCzaXj+6ig==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

另一种解决方案是使用自定义插件。这比使用 Chartjs-plugin-datalabels 更复杂,但它支持更大范围的样式选项。

这是这种方法的草图。我将这个插件命名为

specialLabel
,它本质上借鉴了
afterDraw
处理程序中的画布,也就是说,它在另一个之后绘制 图表的元素已完成。

function draw_arrow(ctx, x0, y0, x1, y1) {
    // from https://stackoverflow.com/a/70873674/16466946
    const width = 3;
    const head_len = 9;
    const head_angle = Math.PI / 8;
    const angle = Math.atan2(y1 - y0, x1 - x0);

    /* Adjust the point */
    x1 -= width * Math.cos(angle);
    y1 -= width * Math.sin(angle);
    ctx.lineWidth = 3;
    ctx.beginPath();
    ctx.moveTo(x0, y0);
    ctx.lineTo(x1, y1);
    ctx.stroke();

    ctx.beginPath();
    ctx.lineTo(x1, y1);
    ctx.lineTo(x1 - head_len * Math.cos(angle - head_angle), y1 - head_len * Math.sin(angle - head_angle));
    ctx.lineTo(x1 - head_len * Math.cos(angle + head_angle), y1 - head_len * Math.sin(angle + head_angle));
    ctx.closePath();
    ctx.stroke();
    ctx.fill();
}


new Chart('linuxonly', {
    type: 'line',
    plugins: [{
        id: 'specialLabel',
        defaults: {
            offsetX: 30, offsetY: -40,
            textFontSize: 25,
            backgroundColor: 'rgba(255, 255, 255, 0.5)',
            textColor: '#000',
            lineColor: '#444',
            paddingX: 12, paddingY: 6
        },
        afterDraw(chart, _, pluginOptions){
            const {datasetIndex, xValue, text, offsetX, offsetY, textFontSize,
                backgroundColor, textColor, lineColor, paddingX, paddingY } = pluginOptions;

            const dataIndex = chart.data.labels.indexOf(xValue);
            if(dataIndex < 0){
                return;
            }
            const {x, y} = chart.getDatasetMeta(datasetIndex).data[dataIndex];
            const x0 = x + offsetX, y0 = y + offsetY;
            const ctx = chart.ctx;
            ctx.save();

            ctx.strokeStyle = lineColor;
            draw_arrow(ctx, x0, y0, x, y);
            ctx.font = textFontSize + "px serif";
            ctx.textAlign = "center";
            ctx.textBaseline = "bottom";
            ctx.strokeStyle = textColor;
            const labelWidth = ctx.measureText(text).width;
            ctx.fillStyle = backgroundColor;
            ctx.fillRect(x0 - labelWidth/2 - paddingX, y0, labelWidth + 2 * paddingX, -textFontSize - 2 * paddingY);
            ctx.fillStyle = textColor;
            ctx.fillText(text, x0,  y0 - paddingY);
            ctx.lineWidth = 2;
            ctx.strokeStyle = lineColor;
            ctx.strokeRect(x0 - labelWidth/2 - paddingX, y0, labelWidth + 2 * paddingX, -textFontSize - 2 * paddingY);
            ctx.restore();
        }
    }],
    data: {
        labels: ['Sep-2018','Oct-2018','Nov-2018','Dec-2018','Jan-2019','Feb-2019','Mar-2019','Apr-2019','May-2019','Jun-2019','Jul-2019','Aug-2019','Sep-2019','Oct-2019','Nov-2019','Dec-2019','Jan-2020','Feb-2020','Mar-2020','Apr-2020','May-2020','Jun-2020','Jul-2020','Aug-2020','Sep-2020','Oct-2020','Nov-2020','Dec-2020','Jan-2021','Feb-2021','Mar-2021','Apr-2021','May-2021','Jun-2021','Jul-2021','Aug-2021','Sep-2021','Oct-2021','Nov-2021','Dec-2021','Jan-2022','Feb-2022','Mar-2022','Apr-2022','May-2022','Jun-2022','Jul-2022','Aug-2022','Sep-2022','Oct-2022','Nov-2022','Dec-2022','Jan-2023','Feb-2023','Mar-2023','Apr-2023','May-2023','Jun-2023','Jul-2023','Aug-2023','Sep-2023','Oct-2023','Nov-2023','Dec-2023','Jan-2024'],
        datasets: [
            {
                label: 'Linux',
                lineTension: 0,
                fill: false,
                data: [0.78, 0.72, 0.80, 0.82, 0.82, 0.77, 0.82, 0.81, 0.84, 0.76, 0.79, 0.80, 0.83, 0.83, 0.81, 0.83, 0.90, 0.83, 0.87, 0.89, 0.91, 0.88, 0.86, 0.89, 0.94, 0.90, 0.90, 0.78, 0.91, 0.81, 0.85, 0.85, 0.86, 0.89, 1.00, 1.02, 1.05, 1.13, 1.16, 1.11, 1.06, 1.02, 1.00, 1.14, 1.12, 1.18, 1.23, 1.27, 1.23, 1.28, 1.44, 1.38, 1.38, 1.27, 0.84, 1.32, 1.47, 1.44, 1.96, 1.82, 1.63, 1.39, 1.91, 1.97, 1.95],
                backgroundColor: '#0C7BDC',
                borderColor: '#0C7BDC',
                borderWidth: 1,
                // trendlineLinear: {
                //     style: '#DC267F',
                //     lineStyle: 'dotted',
                //     width: 2
                // }
            }]
    },
    options: {
        legend: {
            display: true
        },
        responsive: true,
        maintainAspectRatio: false,
        pointRadius: function(ctx){
            return ctx.chart.data.labels[ctx.dataIndex] === 'Aug-2019' ? 6 : 3
        },
        scales: {
            y: {
                ticks: {
                    beginAtZero:true
                },
                title: {
                    display: true,
                    text: 'Percentage of Steam users'
                }
            }
        },
        tooltips:
            {
                callbacks: {
                    label: function(tooltipItem, data) {
                        var value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
                        var label = data.datasets[tooltipItem.datasetIndex].label;
                        return label + ' ' + value + '%';
                    }
                },
            },
        plugins: {
            specialLabel: {
                datasetIndex: 0,
                xValue: 'Aug-2019',
                text: 'Big Event'
            }
        }
    }
});
<div style="height: 90vh">
    <canvas id="linuxonly" style="background: rgba(192, 192, 192, 0.5)">
    </canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>

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