ChartJS 在折线图中向画布添加文本

问题描述 投票:0回答:4

我有一些线图,全部从 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>
canvas chart.js
4个回答
3
投票

您可以使用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>


1
投票

您可以尝试使用

js
在画布上手动书写,但是下面的示例将您的代码修改为

  1. 将轴向左移动
  2. 打印最高值和最低值作为前两个刻度

注意。由于我无法访问 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>


0
投票

这就是现在的最终样子。我很高兴。可能会做一些编辑,但总的来说,这就是我想要实现的目标。

$(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);
}

Weather Station


0
投票

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: {
© www.soinside.com 2019 - 2024. All rights reserved.