【发布时间】:2021-09-14 12:29:16
【问题描述】:
首先,我想说我是一个学生学习编程大约一个月,所以期待看到很多错误。
我正在使用 ChartJs 库中的图表的网站上工作。此图表使用的数据是通过对服务器的请求获取的。我正在努力每隔 X 秒向服务器发出请求,因此图表上显示的数据会自动更新,而无需刷新或执行任何操作。
我想说我已经完成了大部分工作,但我对 ChartJs 有疑问。我有图表和对服务器的请求,都在一个函数中,然后我调用windows.onload。我使用setInterval 每 5 秒调用一次此函数,实际上这有效,但我收到此错误:
未捕获的错误:画布已在使用中。 ID 为“0”的图表必须是 在画布可以重复使用之前被销毁。
所以我明白发生了什么,我试图在同一个canvas 元素上一遍又一遍地创建图表,这当然行不通。我已经看到了destroy() 方法和update() 方法,但是我还没有找到适合我的具体情况的解决方案。如果有人能告诉我在这种情况下如何做到这一点的任何想法,我将不胜感激。代码如下:
let serverData;
let stundenGesamt;
let date;
const url = 'https://urlsample.de/'; // Hidden the actual URL as it is the actual server from my company
const chart = document.getElementById("multie-pie-chart");
// Function that calculates the workdays passed up until today
const workdaysCount = () =>
[...new Array(new Date().getDate())]
.reduce((acc, _, monthDay) => {
const date = new Date()
date.setDate(1+monthDay)
![0, 6].includes(date.getDay()) && acc++
return acc
}, 0)
window.onload = function() {
chartRender(); // Calling the function that renders the chart
setInterval(chartRender, 5000); // Rendering the chart every 5 seconds
};
let chartRender = () => {
console.log('test');
let http = new XMLHttpRequest();
http.open("GET", url);
http.setRequestHeader('key', 'key-sample'); // Hidden the actual key as it is from the actual server from my company
http.onload = () => {
// Parsing the JSON file and storing it into a variable (Console.Log() to make sure it works)
serverData = JSON.parse(http.responseText);
console.log(serverData);
stundenGesamt = serverData.abzurechnen.gesamt; // Storing the value of total hours from the database in a variable
Chart.register(ChartDataLabels);
// Basic UI of the pie chart
const data = {
labels: ['Summe', 'Noch um Ziel zu erreichen', 'Arbeitstage', 'Verbleibende Tage im Monat'],
datasets: [
{
backgroundColor: ['#5ce1e6', '#2acaea'],
data: [stundenGesamt, (800 - stundenGesamt)]
},
{
backgroundColor: ['#cd1076', '#8b0a50'],
data: [workdaysCount(), (22 - workdaysCount())]
},
]
};
// Configuration of the pie chart
let outterChart = new Chart(chart, {
type: 'pie',
data: data,
options: {
responsive: true,
plugins: {
datalabels: {
font: {
weight: 'bold',
size: 20
},
color: 'white',
formatter: (val, chart) => {
const totalDatasetSum = chart.chart.data.datasets[chart.datasetIndex].data.reduce((a, b) => (a + b), 0);
const percentage = val * 100 / totalDatasetSum;
const roundedPercentage = Math.round(percentage * 100) / 100
return `${roundedPercentage}%`
}
},
legend: {
labels: {
color: 'white',
font: {
size: 14,
family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
weight: 'bold'
},
generateLabels: function(chart) {
// Get the default label list
const original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
const labelsOriginal = original.call(this, chart);
// Build an array of colors used in the datasets of the chart
var datasetColors = chart.data.datasets.map(function(e) {
return e.backgroundColor;
});
datasetColors = datasetColors.flat();
// Modify the color and hide state of each label
labelsOriginal.forEach(label => {
// Change the color to match the dataset
label.fillStyle = datasetColors[label.index];
});
return labelsOriginal;
}
},
onClick: function(mouseEvent, legendItem, legend) {
// toggle the visibility of the dataset from what it currently is
legend.chart.getDatasetMeta(
legendItem.datasetIndex
).hidden = legend.chart.isDatasetVisible(legendItem.datasetIndex);
legend.chart.update();
}
},
tooltip: {
callbacks: {
label: function(context) {
const labelIndex = (context.datasetIndex * 2) + context.dataIndex;
return context.chart.data.labels[labelIndex] + ': ' + context.formattedValue;
}
}
},
}
},
});
};
http.send();
};
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Redmine Monitor</title>
</head>
<body>
<div class="container">
<canvas id="multie-pie-chart" height="200" width="200"></canvas>
<div class="titles">
<h3>Ziel: 800 Stunden</h3>
<h3>Monat: September</h3>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<script src="script.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
</body>
</html>
let serverData;
let stundenGesamt;
let date;
let outterChart;
const chart = document.getElementById("multie-pie-chart");
// Function that calculates the workdays passed up until today
const workdaysCount = () =>
[...new Array(new Date().getDate())]
.reduce((acc, _, monthDay) => {
const date = new Date()
date.setDate(1+monthDay)
![0, 6].includes(date.getDay()) && acc++
return acc
}, 0)
window.onload = function() {
chartRender(); // Calling the function that renders the chart
// setInterval(chartRender, 5000); // Rendering the chart every 5 seconds
};
let chartRender = () => {
Chart.register(ChartDataLabels);
// Basic UI of the pie chart
const data = {
labels: ['Summe', 'Noch um Ziel zu erreichen', 'Arbeitstage', 'Verbleibende Tage im Monat'],
datasets: [
{
backgroundColor: ['#5ce1e6', '#2acaea'],
data: [476.5, (800 - 476.5)] //Instead of 476.5, it would be the variable stundenGesamt, which contains the number of hours worked until this moment, which has been extracted from the server through the JSON file that has been parsed into the serverData variable. These variables are not available in the code snippet as I had to remove part of the codes to make it work, but you can see them on the code I posted above, which is the most accurante one. This code snippet is only used to display the graph and how it is structured
},
{
backgroundColor: ['#cd1076', '#8b0a50'],
data: [workdaysCount(), (22 - workdaysCount())]
},
]
};
// Configuration of the pie chart
outterChart = new Chart(chart, {
type: 'pie',
data: data,
options: {
responsive: true,
plugins: {
datalabels: {
font: {
weight: 'bold',
size: 20
},
color: 'white',
formatter: (val, chart) => {
const totalDatasetSum = chart.chart.data.datasets[chart.datasetIndex].data.reduce((a, b) => (a + b), 0);
const percentage = val * 100 / totalDatasetSum;
const roundedPercentage = Math.round(percentage * 100) / 100
return `${roundedPercentage}%`
}
},
legend: {
labels: {
color: 'white',
font: {
size: 14,
family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
weight: 'bold'
},
generateLabels: function(chart) {
// Get the default label list
const original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
const labelsOriginal = original.call(this, chart);
// Build an array of colors used in the datasets of the chart
var datasetColors = chart.data.datasets.map(function(e) {
return e.backgroundColor;
});
datasetColors = datasetColors.flat();
// Modify the color and hide state of each label
labelsOriginal.forEach(label => {
// Change the color to match the dataset
label.fillStyle = datasetColors[label.index];
});
return labelsOriginal;
}
},
onClick: function(mouseEvent, legendItem, legend) {
// toggle the visibility of the dataset from what it currently is
legend.chart.getDatasetMeta(
legendItem.datasetIndex
).hidden = legend.chart.isDatasetVisible(legendItem.datasetIndex);
legend.chart.update();
}
},
tooltip: {
callbacks: {
label: function(context) {
const labelIndex = (context.datasetIndex * 2) + context.dataIndex;
return context.chart.data.labels[labelIndex] + ': ' + context.formattedValue;
}
}
},
}
},
});
};
body {
font-family: Arial, Helvetica, sans-serif;
background-color: #343E59;
}
.container {
display: flex;
width: 800px;
margin: auto;
flex-direction: column-reverse;
justify-content: center;
color: white;
}
.titles {
display: flex;
justify-content: space-evenly;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Redmine Monitor</title>
</head>
<body>
<div class="container">
<canvas id="multie-pie-chart" height="200" width="200"></canvas>
<div class="titles">
<h3>Ziel: 800 Stunden</h3>
<h3>Monat: September</h3>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.5.1/chart.min.js"></script>
<script src="script.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/2.0.0/chartjs-plugin-datalabels.js"></script>
</body>
</html>
【问题讨论】:
标签: javascript canvas graph charts