2

I've created chart that shows temperature from past 20 minute. Data is obtained via GET request from my Thingspeak meteo station. How could I send new request every 10 seconds and update only data in chart.

I think chart.update() would work, but I have no idea how to implement it :/

Here is some code:

chartIt();

async function chartIt(){
    const loadedData = await loadData();
    var myChart = new Chart(document.getElementById("tempChart").getContext('2d'), {
        type: 'line',
        backgroundColor: 'rgba(255, 251, 230, 0.5)',
        data: {
            labels: loadedData.timeStamp,
            datasets: [{
                label: 'Temperature',
                data: loadedData.chartData,
                backgroundColor: [
                    'rgba(255, 0, 132, 0.2)'
                ],
                borderColor: [
                    'rgba(255, 99, 132, 1)'
                ],
                borderWidth: 1
            }]
        },
        
    })
}

async function loadData() {
    var chartData = [];
    var timeStamp = [];
    await $.getJSON('https://api.thingspeak.com/channels/214058/fields/1.json?minutes=20', function(data) {
        $.each(data.feeds, function(){
            var value = this.field1;
            var raw_time = this.created_at;
            
             if (value) {
                value = (value / 1000) * 1000;
                value = parseFloat(value.toFixed(2));
            }

            if (raw_time){
                var timewZ = raw_time.split("T").slice(1);
                              
            }
            chartData.push(value);
            timeStamp.push(timewZ);
        });
    });
    return {chartData, timeStamp};
    
  }
.chartWrapper{
    width: 500px;
    height: 500px;
    margin:auto;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
</head>
<body>
    <div class="chartWrapper">
      <canvas id="tempChart"></canvas>
    </div>
</body>
<script src="script.js"></script>
</html>
kmlZ1337
  • 62
  • 5

2 Answers2

1

This is simplistic but would do the trick. If you wanted to enable/disable it, you'd want to hang onto your interval so you can kill it... This works though! :)

const updateFreqency = 10000;

chartIt(updateFreqency);

async function chartIt(interval){
    const loadedData = await loadData();
    var myChart = new Chart(document.getElementById("tempChart").getContext('2d'), {
        type: 'line',
        backgroundColor: 'rgba(255, 251, 230, 0.5)',
        data: {
            labels: loadedData.timeStamp,
            datasets: [{
                label: 'Temperature',
                data: loadedData.chartData,
                backgroundColor: [
                    'rgba(255, 0, 132, 0.2)'
                ],
                borderColor: [
                    'rgba(255, 99, 132, 1)'
                ],
                borderWidth: 1
            }]
        },
        
    })
    
    setInterval(async () => {
      const data = await loadData();
      myChart.data.datasets.forEach(d => d.data = data.chartData)
      myChart.labels = data.timeStamp
      myChart.update()
    }, interval)
}

async function loadData() {
    var chartData = [];
    var timeStamp = [];
    await $.getJSON('https://api.thingspeak.com/channels/214058/fields/1.json?minutes=20', function(data) {
        $.each(data.feeds, function(){
            var value = this.field1;
            var raw_time = this.created_at;
            
             if (value) {
                value = (value / 1000) * 1000;
                value = parseFloat(value.toFixed(2));
            }

            if (raw_time){
                var timewZ = raw_time.split("T").slice(1);
                              
            }
            chartData.push(value);
            timeStamp.push(timewZ);
        });
    });
    return {chartData, timeStamp};
    
  }
.chartWrapper{
    width: 500px;
    height: 500px;
    margin:auto;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/chart.js@2.8.0"></script>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <link rel="stylesheet" href="style.css">
    <title>Document</title>
</head>
<body>
    <div class="chartWrapper">
      <canvas id="tempChart"></canvas>
    </div>
</body>
<script src="script.js"></script>
</html>
chad_
  • 3,749
  • 2
  • 22
  • 22
0

basically you need access to chart so if you move its context/scope to be outside of the function then you can access it from another function....

something like....

ommited some of the code as well this is the core bits..

//moved out
var myChart;
async function chartIt(){
    const loadedData = await loadData();
    myChart = new Chart(document.getElementById("tempChart").getContext('2d'), {
        type: 'line',
        backgroundColor: 'rgba(255, 251, 230, 0.5)',
        data: {
            labels: loadedData.timeStamp,
            datasets: [{
                label: 'Temperature',
                data: loadedData.chartData,
                backgroundColor: [
                    'rgba(255, 0, 132, 0.2)'
                ],
                borderColor: [
                    'rgba(255, 99, 132, 1)'
                ],
                borderWidth: 1
            }]
        },
        
    })
}

function myTimer() {
    var loadedData = await loadData();
    //have access here as it was move out of the function which created it.
    myChart.data.labels = loadedData.timeStamp;
    myChart.data.datasets = loadedData.chartData;
    myChart.update();
}

var myVar = setInterval(myTimer, 10000);
Seabizkit
  • 2,417
  • 2
  • 15
  • 32
  • I've implemented yours solution but there is problem when myChart.update() is called. – kmlZ1337 Oct 29 '20 at 20:29
  • 1
    @kmlZ1337 the problem is that you can't set myChart.data.datasets that way. If you copy that line from my example into this, it'll work, I believe. – chad_ Oct 29 '20 at 20:36
  • @chad_ sorry what do you mean? is it just that he wanted to append rather than replace? – Seabizkit Oct 29 '20 at 20:53
  • @Seabizkit data.datasets is an array of dataset objects, which have a property "data" that we want to update. You could have done data.datasets[0].data = loadedData.chartData, I think. – chad_ Oct 29 '20 at 21:02
  • @chad_ i see, in my code, i just replace the datasets..., with new datasets, in my case it is one but its simpler to manage as it then doesn't matter then if i start using more. But yes i see what your saying `myChart.data.datasets[0] = loadedData.chartData;` should work or something like that. Thx – Seabizkit Oct 29 '20 at 21:09
  • well, the object inside datasets has an attribute called data amongst other things like labels and styles that are missing when you overwrite it. – chad_ Oct 30 '20 at 14:03
  • @chad_ i model it in c# and return as object... which represents the j object – Seabizkit Oct 30 '20 at 15:14