我有一些线图,全部从 MariaDB 中提取数据,这些数据是从我的 Rpi 零气象站填充的。到目前为止,我已经有一个辅助 y 轴来显示今天的最高值和最低值,但我宁愿将其作为 2 条线放置在图表的左上角。我一直在尝试此处和 Chartjs 文档中找到的几种方法,但无济于事。我该如何让下面的代码在画布上显示文本?
<html>
<head>
<title>Temperatur</title>
<style type="text/css">
body {
font-family: Roboto;
background-color: #242e42;
color: white;
width: 98%;
}
#chart-container {
width: 100%;
height: 100%;
}
</style>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/0.7.0/chartjs-plugin-datalabels.min.js"></script>
</head>
<body>
<div id="chart-container">
<canvas id="tempgraphCanvas" style="width:100%;height:100%;"></canvas>
</div>
<script>
$(document).ready(function () {
showtempGraph();
});
function showtempGraph()
{
{
$.post("temperaturedata.php",
function (data)
{
console.log(data);
var temptime = [];
var temp = [];
for (var i in data) {
temptime.push(data[i].timestamp);
temp.push(data[i].temperature);
}
var tempmin = Math.min(...temp);
var tempmax = Math.max(...temp);
var charttempdata = {
labels: temptime,
datasets: [
{
label: 'Temperatur',
pointRadius: 3,
backgroundColor: 'rgba(26, 137, 245, 0.2)',
borderColor: 'rgba(26, 137, 245, 1)',
hoverBackgroundColor: 'rgba(255, 255, 255, 0)',
hoverBorderColor: 'rgba(255, 255, 255, 0)',
pointBackgroundColor: 'rgba(12, 68, 122,1)',
pointHoverBorderColor: "rgba(255, 255, 255, 0.8)",
data: temp,
datalabels: {
align: function(context) {
return context.active ? 'left' : 'left';
}
}
}
]
};
var graphtempTarget = $("#tempgraphCanvas");
var linetempGraph = new Chart(graphtempTarget, {
type: 'line',
data: charttempdata,
options: {
plugins: {
datalabels: {
backgroundColor: null,
borderColor: null,
borderRadius: function(context) {
return context.active ? 0 :0;
},
borderWidth: 1,
color: 'rgba(255, 255, 255, 1)',
font: {
size: 18,
color: 'rgba(255, 255, 255, 1)'
},
formatter: function(value, context) {
value = Math.round(value * 100) / 100;
if (context.dataIndex === context.dataset.data.length - 1) {
return value + '°C';
} else {
return context.active
? value + '°C'
: ''
}
},
offset: 8,
padding: 0,
textAlign: 'center'
}
},
maintainAspectRatio: false,
tooltips: {
enabled: false,
},
legend: {
display: false,
},
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
displayFormats: {
hour: 'HH:mm'
},
tooltipFormat: 'HH:mm',
},
unit : 'day',
gridLines: {
color: '#999999',
lineWidth: 1
},
ticks: {
fontColor: "#fff",
}
}],
yAxes: [
{
type: 'linear',
position: 'left',
gridLines: {
color: '#999999',
lineWidth: 1
},
ticks: {
fontColor: "rgba(255, 255, 255, 1)",
}
}, {
type: 'linear',
position: 'right',
afterUpdate: function(scaleInstance) {
console.dir(scaleInstance);
},
ticks: {
stepSize: tempmin - tempmax,
min: tempmin,
max: tempmax,
mirror: true,
padding: -200,
fontColor: "rgba(255, 255, 255, 1)",
fontSize: 14,
callback: function(value) {
if ( value === tempmin) {
return ' Dagens laveste temperatur = ' + value + '°C';
} else {
return ' Dagens højeste temperatur = ' + value + '°C';
}
}
},
gridLines: {
drawOnChartArea: false,
},
scaleLabel: {
display: true,
labelString: '°C',
fontColor: "rgba(255, 255, 255, 1)",
fontSize: 14,
fontStyle: 'bold'
}
}]
},
}
});
});
}
}
</script>
</body>
</html>
您可以使用Plugin Core API。它提供了可用于执行自定义代码的不同挂钩。在下面的代码片段中,我使用
afterDraw
钩子在根据 chart.scales
计算的位置绘制文本。
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
let maxValue = Math.max(...chart.data.datasets[0].data);
let minValue = Math.min(...chart.data.datasets[0].data);
ctx.save();
ctx.textAlign = 'center';
ctx.font = '12px Arial';
ctx.fillStyle = 'white';
ctx.textAlign = 'left';
ctx.fillText('Dagens højeste temperatur = ' + maxValue + '°C', xAxis.left + 5, yAxis.top + 5);
ctx.fillText('Dagens laveste temperatur = ' + minValue + '°C', xAxis.left + 5, yAxis.top + 18);
ctx.restore();
}
}],
如果您想将文本绘制在略高于最顶部网格线的位置,则需要在图表顶部定义一些额外填充。
layout: {
padding: {
top: 20
}
},
请查看修改后的代码,看看它如何处理静态数据。
const now = new Date().getTime();
const times = new Array(10).fill().map((v, i) => now - i * 600000).reverse();
var charttempdata = {
labels: times,
datasets: [{
label: 'Temperatur',
pointRadius: 3,
backgroundColor: 'rgba(26, 137, 245, 0.2)',
borderColor: 'rgba(26, 137, 245, 1)',
hoverBackgroundColor: 'rgba(255, 255, 255, 0)',
hoverBorderColor: 'rgba(255, 255, 255, 0)',
pointBackgroundColor: 'rgba(12, 68, 122,1)',
pointHoverBorderColor: "rgba(255, 255, 255, 0.8)",
data: [22, 23, 23, 23, 22, 20, 22, 22, 23, 25],
datalabels: {
align: function(context) {
return context.active ? 'left' : 'left';
}
}
}]
};
var linetempGraph = new Chart('tempgraphCanvas', {
type: 'line',
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
let maxValue = Math.max(...chart.data.datasets[0].data);
let minValue = Math.min(...chart.data.datasets[0].data);
ctx.save();
ctx.textAlign = 'center';
ctx.font = '12px Arial';
ctx.fillStyle = 'white';
ctx.textAlign = 'left';
ctx.fillText('Dagens højeste temperatur = ' + maxValue + '°C', xAxis.left + 5, yAxis.top + 5);
ctx.fillText('Dagens laveste temperatur = ' + minValue + '°C', xAxis.left + 5, yAxis.top + 18);
ctx.restore();
}
}],
data: charttempdata,
options: {
maintainAspectRatio: false,
tooltips: {
enabled: false,
},
legend: {
display: false,
},
scales: {
xAxes: [{
type: 'time',
time: {
unit: 'minute',
displayFormats: {
hour: 'HH:mm'
},
tooltipFormat: 'HH:mm',
},
gridLines: {
color: '#999999',
lineWidth: 1
},
ticks: {
fontColor: "#fff",
}
}],
yAxes: [{
type: 'linear',
position: 'left',
gridLines: {
color: '#999999',
lineWidth: 1
},
ticks: {
fontColor: "rgba(255, 255, 255, 1)",
stepSize: 1
}
}]
},
}
});
body {
background-color: #242e42;
color: white;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.18.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<canvas id="tempgraphCanvas"></canvas>
您可以尝试使用
js
在画布上手动书写,但是下面的示例将您的代码修改为
注意。由于我无法访问 ajax 调用返回的数据,因此我生成了数据并调用了该函数。您可以使用下面的代码,只需在
generateAndHandleTemperatureData()
中注释带有 showtempGraph()
的行并取消注释 $.post("temperaturedata.php", handleTemperatureData);
$(document).ready(function() {
showtempGraph();
});
function handleTemperatureData(data) {
//console.log(data);
var temptime = [];
var temp = [];
for (var i in data) {
temptime.push(data[i].timestamp);
temp.push(data[i].temperature);
}
var tempmin = Math.min(...temp);
var tempmax = Math.max(...temp);
var charttempdata = {
labels: temptime,
datasets: [{
label: 'Temperatur',
pointRadius: 3,
backgroundColor: 'rgba(26, 137, 245, 0.2)',
borderColor: 'rgba(26, 137, 245, 1)',
hoverBackgroundColor: 'rgba(255, 255, 255, 0)',
hoverBorderColor: 'rgba(255, 255, 255, 0)',
pointBackgroundColor: 'rgba(12, 68, 122,1)',
pointHoverBorderColor: "rgba(255, 255, 255, 0.8)",
data: temp,
datalabels: {
align: function(context) {
return context.active ? 'left' : 'left';
}
}
}]
};
var graphtempTarget = $("#tempgraphCanvas");
var linetempGraph = new Chart(graphtempTarget, {
type: 'line',
data: charttempdata,
options: {
plugins: {
datalabels: {
backgroundColor: null,
borderColor: null,
borderRadius: function(context) {
return context.active ? 0 : 0;
},
borderWidth: 1,
color: 'rgba(255, 255, 255, 1)',
font: {
size: 18,
color: 'rgba(255, 255, 255, 1)'
},
formatter: function(value, context) {
value = Math.round(value * 100) / 100;
if (context.dataIndex === context.dataset.data.length - 1) {
return value + '°C';
} else {
return context.active ?
value + '°C' :
''
}
},
offset: 8,
padding: 0,
textAlign: 'center'
}
},
maintainAspectRatio: false,
tooltips: {
enabled: false,
},
legend: {
display: false,
},
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
displayFormats: {
hour: 'HH:mm'
},
tooltipFormat: 'HH:mm',
},
unit: 'day',
gridLines: {
color: '#999999',
lineWidth: 1
},
ticks: {
fontColor: "#fff",
}
}],
yAxes: [{
type: 'linear',
position: 'left',
gridLines: {
color: '#999999',
lineWidth: 1
},
ticks: {
fontColor: "rgba(255, 255, 255, 1)",
}
}, {
type: 'linear',
position: 'left',
afterUpdate: function(scaleInstance) {
//console.dir(scaleInstance);
},
ticks: {
// stepSize: 1 || tempmin - tempmax,
min: tempmin,
max: tempmax,
mirror: true,
padding: -30,
fontColor: "rgba(255, 255, 255, 1)",
fontSize: 14,
callback: function(value,index) {
// console.log(arguments)
if(index == 0){
return ' Dagens højeste temperatur = ' + tempmax + '°C';
}else if(index == 1){
return ' Dagens laveste temperatur = ' + tempmin + '°C';
}else{
return ""
}
}
},
gridLines: {
drawOnChartArea: false,
},
scaleLabel: {
display: true,
// labelString: '°C',
fontColor: "rgba(255, 255, 255, 1)",
fontSize: 14,
fontStyle: 'bold',
//adjust the properties below to change the spacing between the lines
//reference: https://www.chartjs.org/docs/latest/axes/labelling.html
//padding: 30, //
//lineHeight:30 //
}
}]
},
}
});
}
function generateAndHandleTemperatureData() {
//TODO: generate data
var data = [];
var currentDate = new Date();
var startTime = currentDate.getTime() - 1*60*60*1000;
for(var i=startTime;i<currentDate.getTime();i+=(60*1000*15)){
data.push({
timestamp:i,
temperature: Math.random()*30+1
})
}
handleTemperatureData(data);
}
function showtempGraph() {
generateAndHandleTemperatureData()
// $.post("temperaturedata.php", handleTemperatureData);
}
body {
font-family: Roboto;
background-color: #242e42;
color: white;
width: 98%;
}
#chart-container {
width: 100%;
height: 100%;
}
<html>
<head>
<title>Temperatur</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/0.7.0/chartjs-plugin-datalabels.min.js"></script>
</head>
<body>
<div id="chart-container">
<canvas id="tempgraphCanvas" style="width:100%;height:100%;"></canvas>
</div>
</body>
</html>
这就是现在的最终样子。我很高兴。可能会做一些编辑,但总的来说,这就是我想要实现的目标。
$(document).ready(function() {
showtempGraph();
});
function handletemperatureData(data) {
var temptime = [];
var temp = [];
for (var i in data) {
temptime.push(data[i].timestamp);
temp.push(data[i].temperature);
}
var tempmin = Math.min(...temp);
var tempmax = Math.max(...temp);
var charttempdata = {
labels: temptime,
datasets: [{
label: 'Luftfugtighed',
pointRadius: 3,
backgroundColor: 'rgba(26, 137, 245, 0.2)',
borderColor: 'rgba(26, 137, 245, 1)',
hoverBackgroundColor: 'rgba(255, 255, 255, 0)',
hoverBorderColor: 'rgba(255, 255, 255, 0)',
pointBackgroundColor: 'rgba(12, 68, 122,1)',
pointHoverBorderColor: "rgba(255, 255, 255, 0.8)",
data: temp,
datalabels: {
align: function(context) {
return context.active ? 'left' : 'left';
}
}
}]
};
var graphtempTarget = $("#tempgraphCanvas");
Chart.defaults.global.defaultFontFamily = "Roboto";
var linetempGraph = new Chart(graphtempTarget, {
type: 'line',
plugins: [{
afterDraw: chart => {
let ctx = chart.chart.ctx;
let xAxis = chart.scales['x-axis-0'];
let yAxis = chart.scales['y-axis-0'];
let maxValue = Math.max(...chart.data.datasets[0].data);
let minValue = Math.min(...chart.data.datasets[0].data);
ctx.save();
ctx.textAlign = 'center';
ctx.font = '14px Roboto';
ctx.fillStyle = 'white';
ctx.textAlign = 'left';
ctx.fillText('Dagens max. temperatur = ', xAxis.left + 5, yAxis.top + 15);
ctx.fillText('Dagens min. temperatur = ', xAxis.left + 5, yAxis.top + 40);
ctx.fillText(maxValue + '°C', xAxis.left + 200, yAxis.top + 15);
ctx.fillText(minValue + '°C', xAxis.left + 200, yAxis.top + 40);
ctx.restore();
}
}],
data: charttempdata,
options: {
plugins: {
datalabels: {
backgroundColor: null,
borderColor: null,
borderRadius: function(context) {
return context.active ? 0 : 0;
},
borderWidth: 1,
color: 'rgba(255, 255, 255, 1)',
font: {
size: 18,
color: 'rgba(255, 255, 255, 1)'
},
formatter: function(value, context) {
value = Math.round(value * 100) / 100;
if (context.dataIndex === context.dataset.data.length - 1) {
return value + '°C';
} else {
return context.active ?
value + '°C' :
''
}
},
offset: 8,
padding: 0,
textAlign: 'center'
}
},
maintainAspectRatio: false,
tooltips: {
enabled: false,
},
legend: {
display: false,
},
responsive: true,
scales: {
xAxes: [{
type: 'time',
time: {
displayFormats: {
hour: 'HH:mm'
},
tooltipFormat: 'HH:mm',
},
unit: 'day',
gridLines: {
color: 'rgba(153, 153, 153, 1)',
lineWidth: 1
},
ticks: {
fontColor: 'rgba(255, 255, 255, 1)',
}
}],
yAxes: [{
type: 'linear',
position: 'left',
gridLines: {
color: 'rgba(153, 153, 153, 1)',
lineWidth: 1
},
ticks: {
fontColor: "rgba(255, 255, 255, 1)",
}
}, {
type: 'linear',
position: 'right',
weight: 50,
gridLines: {
drawOnChartArea: false,
},
ticks: {
display: false
},
scaleLabel: {
display: true,
labelString: '°C',
fontColor: "rgba(255, 255, 255, 1)",
fontSize: 14,
fontStyle: 'bold'
}
}]
},
}
});
}
function showtempGraph() {
$.post("temperaturedata.php", handletemperatureData);
}
FWIW,我无法使上述工作正常进行。它一直抱怨“chart”未定义,或“ctx”未定义,以及类似的“x-axis-0”和“y-axis-0”未定义。可能是 Chart.js 4.4.1 与 Chart.js 2.9.1 的“功能”(如 tristan202 使用的)....
var ctx = document.getElementById('myCanvas').getContext('2d');
var Mintemp=Math.min(...Chart_data.map(row=>row.t));
var Maxtemp=Math.max(...Chart_data.map(row=>row.t));
var tempNow=Chart_data[Chart_data.length-1].t;
var Graphhigh=Math.floor(Maxtemp+4);
var Graphlow=Math.floor(Mintemp-3);
var Linechart = new Chart(ctx, {
type: "line",
plugins: [{
afterDraw: (chart,args,options) =>
{
let xAxis=chart.scales.x;
let yAxis=chart.scales.y;
ctx.save();
ctx.textAlign='left';
ctx.fillText('Temperatur Max=',xAxis.left+5,yAxis.top+15);
ctx.fillText('Temperatur Min=',xAxis.left+5,yAxis.top+30);
ctx.fillText('Temperatur Now=',xAxis.left+5,yAxis.top+45);
ctx.fillText(Maxtemp+String.fromCodePoint(8451),xAxis.left+110,yAxis.top+15);
ctx.fillText(Mintemp+String.fromCodePoint(8451),xAxis.left+110,yAxis.top+30);
ctx.fillText(tempNow+String.fromCodePoint(8451),xAxis.left+110,yAxis.top+45);
ctx.restore();
}
}],
options: {