我使用JSFiddle用Chartjs创建了一个水平条形图。我能够对其进行调整,使它看起来非常接近最终版本,如您在此处看到的:https://jsfiddle.net/coder_jb/pLec5hqn/
但是,当我尝试在Web开发IDE中使用它时,我遇到了竖线垂直间距的问题。我花了比我更愿意承认的时间来追踪差异,并且最终归结为Chartjs版本。可以正常工作的版本使用2.7.1版本,但JSFiddle中使用2.7.2版本(https://jsfiddle.net/coder_jb/3tnrzeLq/4/)的相同代码将压缩竖线间距。因此,或者我在早期版本中编码有问题并很幸运,或者在2.7.2版本中可能损坏了某些内容。知道为什么会这样吗?
好(使用Chartjs 2.7.1):
let ctx = document.getElementById("canvas").getContext("2d");
let barChart = null;
let barData = [
25, 20, 13, 24, 15, 26, 17, 28, 19, 30,
11, 32, 13, 34, 15, 35, 16, 37, 18, 39
];
let barTooltips = [
"host_1 (127.0.0.1) eth33", "host_1 (127.0.0.1) eth34",
"host_2 (127.0.0.2) eth33", "host_2 (127.0.0.2) eth34",
"host_3 (127.0.0.3) eth34", "host_3 (127.0.0.3) eth35",
"host_4 (127.0.0.4) eth7", "host_4 (127.0.0.4) eth8",
"host_5 (127.0.0.5) eth9", "host_5 (127.0.0.5) eth10",
"host_5 (127.0.0.5) eth11", "host_5 (127.0.0.5) eth12",
"host_5 (127.0.0.5) eth13", "host_5 (127.0.0.5) eth14",
"host_6 (127.0.0.6) eth15", "host_7 (127.0.0.7) eth16",
"host_8 (127.0.0.8) eth17", "host_8 (127.0.0.8) eth18",
"host_9 (127.0.0.9) eth19", "host_9 (127.0.0.9) eth20"
];
let rcBackgroundColors = [
'#00b0ff', '#43a047',
'#ff8f00', '#c62828',
'#df00f9', '#ffea00',
'#4e342e', '#2979ff',
'#00e676', '#ffc400',
'#5cbae6', '#b6d957',
'#fac364', '#8cd3ff',
'#d998cb', '#f2d249',
'#93b9c6', '#cc5a8',
'#52bacc', '#dbdb46'
];
let ticYlabels = [];
let ticYlabelsHidden = [];
function updateTicYlabelsHidden(ticLabel) {
if (ticLabel) {
if (ticYlabelsHidden.includes(ticLabel)) {
ticYlabelsHidden.splice(ticYlabelsHidden.indexOf(ticLabel), 1);
//ticYlabels.push(ticLabel);
} else {
ticYlabelsHidden.push(ticLabel);
}
}
initializeTicYlabels();
}
function initializeTicYlabels() {
ticYlabels = [];
for (let n = 0; n < barTooltips.length; ++n) {
let label = barTooltips[n].split(" ");
label.shift();
let ticLabel = label.join(' ');
if (!ticYlabelsHidden.includes(ticLabel))
ticYlabels.push(ticLabel);
}
}
initializeTicYlabels();
let barBackgroundColor = [];
let maxColors = 20;
let barDataSets = [];
for (let n = 0; n < barTooltips.length; ++n) {
barBackgroundColor.push(rcBackgroundColors[n % maxColors]);
barDataSets[n] = {
label: [ticYlabels[n]],
data: [barData[n]],
backgroundColor: rcBackgroundColors[n % maxColors],
borderColor: rcBackgroundColors[n % maxColors],
borderWidth: 2,
hoverBorderWidth: 0
};
}
let xMax = Math.max(...barData);
xMax += xMax / 10;
let pktSrcBarChartConfig = {
animation: false,
responsive: true,
maintainAspectRatio: false,
type: 'horizontalBar',
data: {
datasets: barDataSets,
labels: ticYlabels,
},
options: {
barValueSpacing: 10,
tooltips: {
mode: 'y',
callbacks: {
title: function() {
return '';
},
label: function(tooltipItem) {
return barTooltips[tooltipItem.index] + ': ' + tooltipItem.xLabel + ' KB/sec';
}
}
},
legend: false,
legendCallback: function(chart) {
let text = [];
text.push('<ul class="' + chart.id + '-legend">');
for (let i = 0; i < chart.data.datasets.length; i++) {
text.push('<li><i class="fa fa-1x fa-check-square" style="color: ' + chart.data.datasets[i].backgroundColor + ';">');
if (chart.data.datasets[i].label) {
text.push(' <span style="color: black; font-size: 16px; font-family: ubuntu monospace">' + chart.data.datasets[i].label);
}
text.push('</i></li>');
}
text.push('</ul>');
return text.join('');
},
title: {
display: true,
text: 'Bandwidth',
fontWeight: 'bold',
fontFamily: 'Ubuntu',
fontSize: 18,
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: 'KB/sec',
fontWeight: 'bold',
fontFamily: 'Ubuntu',
fontSize: 18,
},
ticks: {
min: 0,
suggestedMax: xMax,
beginAtZero: true,
},
gridLines: {
offsetGridLines: true
}
}],
yAxes: [{
//id: 'ip',
//type: 'category',
barPercentage: 0.8,
categoryPercentage: 1,
maxBarThickness: 30,
scaleLabel: {
display: true,
labelString: 'Packet Source',
fontWeight: 'bold',
fontFamily: 'Ubuntu',
fontSize: 18,
},
}]
},
plugins: {
datalabels: {
align: 'end',
anchor: 'end',
formatter: function(value, context) {
return value;
},
display: function(context) {
return context.chart.isDatasetVisible(context.datasetIndex);
}
}
}
}
}
function legendClickCallback(event) {
event = event || window.event;
let target = event.target || event.srcElement;
while (target.nodeName !== 'LI') {
target = target.parentElement;
}
let parent = target.parentElement;
let chartId = parseInt(parent.classList[0].split("-")[0], 10);
let chart = Chart.instances[chartId];
let index = Array.prototype.slice.call(parent.children).indexOf(target);
if (chart.isDatasetVisible(index)) {
target.classList.add('hiddenItem');
target.firstChild.classList.remove('fa-check-square');
target.firstChild.classList.add('fa-square');
chart.data.datasets[index].hidden = true;
} else {
target.classList.remove('hiddenItem');
target.firstChild.classList.remove('fa-square');
target.firstChild.classList.add('fa-check-square');
chart.data.datasets[index].hidden = false;
}
updateTicYlabelsHidden(target.innerText.trim());
barChart.data.labels = ticYlabels;
barChart.update();
}
barChart = new Chart(ctx, pktSrcBarChartConfig);
// Generate custom html legend with checkboxes instead of colored rectangles
let myLegendContainer = document.getElementById("legendDiv");
myLegendContainer.innerHTML = barChart.generateLegend();
// Bind onClick event to all LI-tags of the legend
let legendItems = myLegendContainer.getElementsByTagName('li');
for (let i = 0; i < legendItems.length; i += 1) {
legendItems[i].addEventListener("click", legendClickCallback, false);
}
[class="0-legend"] {
list-style: none;
cursor: pointer;
padding-left: 0;
display: table-row;
}
[class="0-legend"] li {
display: inline-block;
padding: 0 5px;
}
[class="0-legend"] li.hiddenItem span {
text-decoration: line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.1/Chart.bundle.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<div id="legendDiv" class="noselect"></div>
<div id="container" style="width:95%;">
<canvas id="canvas"></canvas>
</div>
不良(使用Chartjs 2.7.2):
let ctx = document.getElementById("canvas").getContext("2d");
let barChart = null;
let barData = [
25, 20, 13, 24, 15, 26, 17, 28, 19, 30,
11, 32, 13, 34, 15, 35, 16, 37, 18, 39
];
let barTooltips = [
"host_1 (127.0.0.1) eth33", "host_1 (127.0.0.1) eth34",
"host_2 (127.0.0.2) eth33", "host_2 (127.0.0.2) eth34",
"host_3 (127.0.0.3) eth34", "host_3 (127.0.0.3) eth35",
"host_4 (127.0.0.4) eth7", "host_4 (127.0.0.4) eth8",
"host_5 (127.0.0.5) eth9", "host_5 (127.0.0.5) eth10",
"host_5 (127.0.0.5) eth11", "host_5 (127.0.0.5) eth12",
"host_5 (127.0.0.5) eth13", "host_5 (127.0.0.5) eth14",
"host_6 (127.0.0.6) eth15", "host_7 (127.0.0.7) eth16",
"host_8 (127.0.0.8) eth17", "host_8 (127.0.0.8) eth18",
"host_9 (127.0.0.9) eth19", "host_9 (127.0.0.9) eth20"
];
let rcBackgroundColors = [
'#00b0ff', '#43a047',
'#ff8f00', '#c62828',
'#df00f9', '#ffea00',
'#4e342e', '#2979ff',
'#00e676', '#ffc400',
'#5cbae6', '#b6d957',
'#fac364', '#8cd3ff',
'#d998cb', '#f2d249',
'#93b9c6', '#cc5a8',
'#52bacc', '#dbdb46'
];
let ticYlabels = [];
let ticYlabelsHidden = [];
function updateTicYlabelsHidden(ticLabel) {
if (ticLabel) {
if (ticYlabelsHidden.includes(ticLabel)) {
ticYlabelsHidden.splice(ticYlabelsHidden.indexOf(ticLabel), 1);
//ticYlabels.push(ticLabel);
} else {
ticYlabelsHidden.push(ticLabel);
}
}
initializeTicYlabels();
}
function initializeTicYlabels() {
ticYlabels = [];
for (let n = 0; n < barTooltips.length; ++n) {
let label = barTooltips[n].split(" ");
label.shift();
let ticLabel = label.join(' ');
if (!ticYlabelsHidden.includes(ticLabel))
ticYlabels.push(ticLabel);
}
}
initializeTicYlabels();
let barBackgroundColor = [];
let maxColors = 20;
let barDataSets = [];
for (let n = 0; n < barTooltips.length; ++n) {
barBackgroundColor.push(rcBackgroundColors[n % maxColors]);
barDataSets[n] = {
label: [ticYlabels[n]],
data: [barData[n]],
backgroundColor: rcBackgroundColors[n % maxColors],
borderColor: rcBackgroundColors[n % maxColors],
borderWidth: 2,
hoverBorderWidth: 0
};
}
let xMax = Math.max(...barData);
xMax += xMax / 10;
let pktSrcBarChartConfig = {
animation: false,
responsive: true,
maintainAspectRatio: false,
type: 'horizontalBar',
data: {
datasets: barDataSets,
labels: ticYlabels,
},
options: {
barValueSpacing: 10,
tooltips: {
mode: 'y',
callbacks: {
title: function() {
return '';
},
label: function(tooltipItem) {
return barTooltips[tooltipItem.index] + ': ' + tooltipItem.xLabel + ' KB/sec';
}
}
},
legend: false,
legendCallback: function(chart) {
let text = [];
text.push('<ul class="' + chart.id + '-legend">');
for (let i = 0; i < chart.data.datasets.length; i++) {
text.push('<li><i class="fa fa-1x fa-check-square" style="color: ' + chart.data.datasets[i].backgroundColor + ';">');
if (chart.data.datasets[i].label) {
text.push(' <span style="color: black; font-size: 16px; font-family: ubuntu monospace">' + chart.data.datasets[i].label);
}
text.push('</i></li>');
}
text.push('</ul>');
return text.join('');
},
title: {
display: true,
text: 'Bandwidth',
fontWeight: 'bold',
fontFamily: 'Ubuntu',
fontSize: 18,
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: 'KB/sec',
fontWeight: 'bold',
fontFamily: 'Ubuntu',
fontSize: 18,
},
ticks: {
min: 0,
suggestedMax: xMax,
beginAtZero: true,
},
gridLines: {
offsetGridLines: true
}
}],
yAxes: [{
//id: 'ip',
//type: 'category',
barPercentage: 0.8,
categoryPercentage: 1,
maxBarThickness: 30,
scaleLabel: {
display: true,
labelString: 'Packet Source',
fontWeight: 'bold',
fontFamily: 'Ubuntu',
fontSize: 18,
},
}]
},
plugins: {
datalabels: {
align: 'end',
anchor: 'end',
formatter: function(value, context) {
return value;
},
display: function(context) {
return context.chart.isDatasetVisible(context.datasetIndex);
}
}
}
}
}
function legendClickCallback(event) {
event = event || window.event;
let target = event.target || event.srcElement;
while (target.nodeName !== 'LI') {
target = target.parentElement;
}
let parent = target.parentElement;
let chartId = parseInt(parent.classList[0].split("-")[0], 10);
let chart = Chart.instances[chartId];
let index = Array.prototype.slice.call(parent.children).indexOf(target);
if (chart.isDatasetVisible(index)) {
target.classList.add('hiddenItem');
target.firstChild.classList.remove('fa-check-square');
target.firstChild.classList.add('fa-square');
chart.data.datasets[index].hidden = true;
} else {
target.classList.remove('hiddenItem');
target.firstChild.classList.remove('fa-square');
target.firstChild.classList.add('fa-check-square');
chart.data.datasets[index].hidden = false;
}
updateTicYlabelsHidden(target.innerText.trim());
barChart.data.labels = ticYlabels;
barChart.update();
}
barChart = new Chart(ctx, pktSrcBarChartConfig);
// Generate custom html legend with checkboxes instead of colored rectangles
let myLegendContainer = document.getElementById("legendDiv");
myLegendContainer.innerHTML = barChart.generateLegend();
// Bind onClick event to all LI-tags of the legend
let legendItems = myLegendContainer.getElementsByTagName('li');
for (let i = 0; i < legendItems.length; i += 1) {
legendItems[i].addEventListener("click", legendClickCallback, false);
}
[class="0-legend"] {
list-style: none;
cursor: pointer;
padding-left: 0;
display: table-row;
}
[class="0-legend"] li {
display: inline-block;
padding: 0 5px;
}
[class="0-legend"] li.hiddenItem span {
text-decoration: line-through;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<div id="legendDiv" class="noselect"></div>
<div id="container" style="width:95%;">
<canvas id="canvas"></canvas>
</div>