我目前正在尝试 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)
}
}
}
}
});
正如我怀疑的那样(在评论中),日期来自
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>