使用带有 ChartJS v3 的 generateLabels 删除图表上的冗余图例
Remove redundant legends on the chart using generateLabels with ChartJS v3
我有如下图表,我只需要一对图例(数据1和数据2)显示在图表上。
在 ChartJS v2 中,我可以使用类似 this 的 generateLabels,但它在 v3 中的工作方式似乎与我正在使用的不同。
在 v3 中是否有使用 generateLabels 实现此目的的简单方法,或者我是否必须更改 DOM 结构?
const trend_options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value, ctx) {
const otherDatasetIndex = ctx.datasetIndex % 2 === 0 ? ctx.datasetIndex + 1 : ctx.datasetIndex - 1;
const total = ctx.chart.data.datasets[otherDatasetIndex].data[ctx.dataIndex] + value;
return `${(value / total * 100).toFixed()}%`;
},
font: {
weight: "bold"
},
color: "#fff",
display: function(context) {
let index = context.dataIndex;
let value = context.dataset.data[index];
return value > 0; // display labels with a value greater than 0
}
},
},
scales: {
x: {
stacked: true
},
y: {
stacked: true,
suggestedMax: 15,
ticks: {
beginAtZero: true,
stepSize: 5,
}
}
},
};
const app_data_trend = [{
label: 'data 1',
data: [3, 4, 5, 6, 4, 4, 4],
backgroundColor: '#007bff',
stack: 'Stack 0',
},
{
label: 'data 2',
data: [3, 4, 5, 4, 3, 2, 3],
backgroundColor: '#6DB526',
stack: 'Stack 0',
},
{
label: 'data 1',
data: [4, 4, 4, 3, 2, 5, 4],
backgroundColor: '#007bff',
stack: 'Stack 1',
},
{
label: 'data 2',
data: [4, 2, 5, 2, 3, 3, 4],
backgroundColor: '#6DB526',
stack: 'Stack 1',
},
{
label: 'data 1',
data: [2, 4, 5, 2, 4, 5, 3],
backgroundColor: '#007bff',
stack: 'Stack 2',
},
{
label: 'data 2',
data: [1, 1, 2, 4, 4, 3, 5],
backgroundColor: '#6DB526',
stack: 'Stack 2',
},
]
const ctx8 = document.getElementById("tsa-applications-trending");
const chart8 = new Chart(ctx8, {
plugins: [ChartDataLabels],
type: 'bar',
data: {
labels: ['person1', 'person2', 'person3', 'person4'],
datasets: app_data_trend
},
options: trend_options,
});
.chart-container{
position: relative; height:80vh; width:80vw
}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0"></script>
<div class="chart-container">
<canvas id="tsa-applications-trending"></canvas>
</div>
options.plugins.legend.labels.generateLabels
仍然可以在 Chart.js v3 中使用。对于您的情况,这可能如下所示:
generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
datasetIndex: i,
text: l,
fillStyle: chart.data.datasets[i].backgroundColor,
strokeStyle: chart.data.datasets[i].backgroundColor,
hidden: chart.getDatasetMeta(i).hidden
}))
const trend_options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value, ctx) {
const otherDatasetIndex = ctx.datasetIndex % 2 === 0 ? ctx.datasetIndex + 1 : ctx.datasetIndex - 1;
const total = ctx.chart.data.datasets[otherDatasetIndex].data[ctx.dataIndex] + value;
return `${(value / total * 100).toFixed()}%`;
},
font: {
weight: "bold"
},
color: "#fff",
display: function(context) {
let index = context.dataIndex;
let value = context.dataset.data[index];
return value > 0; // display labels with a value greater than 0
}
},
legend: {
labels: {
generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
datasetIndex: i,
text: l,
fillStyle: chart.data.datasets[i].backgroundColor,
strokeStyle: chart.data.datasets[i].backgroundColor,
hidden: chart.getDatasetMeta(i).hidden
}))
}
},
},
scales: {
x: {
stacked: true
},
y: {
stacked: true,
suggestedMax: 15,
ticks: {
beginAtZero: true,
stepSize: 5,
}
}
},
};
const app_data_trend = [{
label: 'data 1',
data: [3, 4, 5, 6, 4, 4, 4],
backgroundColor: '#007bff',
stack: 'Stack 0',
},
{
label: 'data 2',
data: [3, 4, 5, 4, 3, 2, 3],
backgroundColor: '#6DB526',
stack: 'Stack 0',
},
{
label: 'data 1',
data: [4, 4, 4, 3, 2, 5, 4],
backgroundColor: '#007bff',
stack: 'Stack 1',
},
{
label: 'data 2',
data: [4, 2, 5, 2, 3, 3, 4],
backgroundColor: '#6DB526',
stack: 'Stack 1',
},
{
label: 'data 1',
data: [2, 4, 5, 2, 4, 5, 3],
backgroundColor: '#007bff',
stack: 'Stack 2',
},
{
label: 'data 2',
data: [1, 1, 2, 4, 4, 3, 5],
backgroundColor: '#6DB526',
stack: 'Stack 2',
},
]
const ctx8 = document.getElementById("tsa-applications-trending");
const chart8 = new Chart(ctx8, {
plugins: [ChartDataLabels],
type: 'bar',
data: {
labels: ['person1', 'person2', 'person3', 'person4'],
datasets: app_data_trend
},
options: trend_options,
});
.chart-container {
position: relative;
height: 80vh;
width: 80vw
}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0"></script>
<div class="chart-container">
<canvas id="tsa-applications-trending"></canvas>
</div>
该方法的问题在于,显示的 legend
元素仍然仅与单个数据集相关联。如果你还想 show/hide 其他数据集,你还需要定义一个 legend.onClick
函数,类似于 this answer.
中的函数
我有如下图表,我只需要一对图例(数据1和数据2)显示在图表上。
在 ChartJS v2 中,我可以使用类似 this 的 generateLabels,但它在 v3 中的工作方式似乎与我正在使用的不同。
在 v3 中是否有使用 generateLabels 实现此目的的简单方法,或者我是否必须更改 DOM 结构?
const trend_options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value, ctx) {
const otherDatasetIndex = ctx.datasetIndex % 2 === 0 ? ctx.datasetIndex + 1 : ctx.datasetIndex - 1;
const total = ctx.chart.data.datasets[otherDatasetIndex].data[ctx.dataIndex] + value;
return `${(value / total * 100).toFixed()}%`;
},
font: {
weight: "bold"
},
color: "#fff",
display: function(context) {
let index = context.dataIndex;
let value = context.dataset.data[index];
return value > 0; // display labels with a value greater than 0
}
},
},
scales: {
x: {
stacked: true
},
y: {
stacked: true,
suggestedMax: 15,
ticks: {
beginAtZero: true,
stepSize: 5,
}
}
},
};
const app_data_trend = [{
label: 'data 1',
data: [3, 4, 5, 6, 4, 4, 4],
backgroundColor: '#007bff',
stack: 'Stack 0',
},
{
label: 'data 2',
data: [3, 4, 5, 4, 3, 2, 3],
backgroundColor: '#6DB526',
stack: 'Stack 0',
},
{
label: 'data 1',
data: [4, 4, 4, 3, 2, 5, 4],
backgroundColor: '#007bff',
stack: 'Stack 1',
},
{
label: 'data 2',
data: [4, 2, 5, 2, 3, 3, 4],
backgroundColor: '#6DB526',
stack: 'Stack 1',
},
{
label: 'data 1',
data: [2, 4, 5, 2, 4, 5, 3],
backgroundColor: '#007bff',
stack: 'Stack 2',
},
{
label: 'data 2',
data: [1, 1, 2, 4, 4, 3, 5],
backgroundColor: '#6DB526',
stack: 'Stack 2',
},
]
const ctx8 = document.getElementById("tsa-applications-trending");
const chart8 = new Chart(ctx8, {
plugins: [ChartDataLabels],
type: 'bar',
data: {
labels: ['person1', 'person2', 'person3', 'person4'],
datasets: app_data_trend
},
options: trend_options,
});
.chart-container{
position: relative; height:80vh; width:80vw
}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.0.0/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0"></script>
<div class="chart-container">
<canvas id="tsa-applications-trending"></canvas>
</div>
options.plugins.legend.labels.generateLabels
仍然可以在 Chart.js v3 中使用。对于您的情况,这可能如下所示:
generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
datasetIndex: i,
text: l,
fillStyle: chart.data.datasets[i].backgroundColor,
strokeStyle: chart.data.datasets[i].backgroundColor,
hidden: chart.getDatasetMeta(i).hidden
}))
const trend_options = {
responsive: true,
maintainAspectRatio: false,
plugins: {
datalabels: {
formatter: function(value, ctx) {
const otherDatasetIndex = ctx.datasetIndex % 2 === 0 ? ctx.datasetIndex + 1 : ctx.datasetIndex - 1;
const total = ctx.chart.data.datasets[otherDatasetIndex].data[ctx.dataIndex] + value;
return `${(value / total * 100).toFixed()}%`;
},
font: {
weight: "bold"
},
color: "#fff",
display: function(context) {
let index = context.dataIndex;
let value = context.dataset.data[index];
return value > 0; // display labels with a value greater than 0
}
},
legend: {
labels: {
generateLabels: chart => chart.data.labels.slice(0, 2).map((l, i) => ({
datasetIndex: i,
text: l,
fillStyle: chart.data.datasets[i].backgroundColor,
strokeStyle: chart.data.datasets[i].backgroundColor,
hidden: chart.getDatasetMeta(i).hidden
}))
}
},
},
scales: {
x: {
stacked: true
},
y: {
stacked: true,
suggestedMax: 15,
ticks: {
beginAtZero: true,
stepSize: 5,
}
}
},
};
const app_data_trend = [{
label: 'data 1',
data: [3, 4, 5, 6, 4, 4, 4],
backgroundColor: '#007bff',
stack: 'Stack 0',
},
{
label: 'data 2',
data: [3, 4, 5, 4, 3, 2, 3],
backgroundColor: '#6DB526',
stack: 'Stack 0',
},
{
label: 'data 1',
data: [4, 4, 4, 3, 2, 5, 4],
backgroundColor: '#007bff',
stack: 'Stack 1',
},
{
label: 'data 2',
data: [4, 2, 5, 2, 3, 3, 4],
backgroundColor: '#6DB526',
stack: 'Stack 1',
},
{
label: 'data 1',
data: [2, 4, 5, 2, 4, 5, 3],
backgroundColor: '#007bff',
stack: 'Stack 2',
},
{
label: 'data 2',
data: [1, 1, 2, 4, 4, 3, 5],
backgroundColor: '#6DB526',
stack: 'Stack 2',
},
]
const ctx8 = document.getElementById("tsa-applications-trending");
const chart8 = new Chart(ctx8, {
plugins: [ChartDataLabels],
type: 'bar',
data: {
labels: ['person1', 'person2', 'person3', 'person4'],
datasets: app_data_trend
},
options: trend_options,
});
.chart-container {
position: relative;
height: 80vh;
width: 80vw
}
<script src="https://cdn.jsdelivr.net/npm/chart.js@3.7.1/dist/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels@2.0.0"></script>
<div class="chart-container">
<canvas id="tsa-applications-trending"></canvas>
</div>
该方法的问题在于,显示的 legend
元素仍然仅与单个数据集相关联。如果你还想 show/hide 其他数据集,你还需要定义一个 legend.onClick
函数,类似于 this answer.