1

I want to create my linear timeseries widget in thingsboard but i need some custom features not included in the default version.

Configuration provided as an example byThingsboard:

The Chart.js library: https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js HTML Canvas: JS Code:

var myChart;

self.onInit = function() {
    
    var chartData = {
        datasets: []
    };

    for (var i=0; i < self.ctx.data.length; i++) {
        var dataKey = self.ctx.data[i].dataKey;
        var dataset = {
            label: dataKey.label,
            data: [],
            borderColor: dataKey.color,
            fill: false
        };
        chartData.datasets.push(dataset);
    }
    
    var options = {
        maintainAspectRatio: false,
        legend: {
            display: false
        },
        scales: {
        xAxes: [{
            type: 'time',
            ticks: {
                maxRotation: 0,
                autoSkipPadding: 30
            }
        }]
    }
    };
    
    var canvasElement = $('#myChart', self.ctx.$container)[0];
    var canvasCtx = canvasElement.getContext('2d');
    myChart = new Chart(canvasCtx, {
        type: 'line',
        data: chartData,
        options: options
    });
    self.onResize();
}

self.onResize = function() {
    myChart.resize();
}

self.onDataUpdated = function() {
    for (var i = 0; i < self.ctx.data.length; i++) {
        var datasourceData = self.ctx.data[i];
        var dataSet = datasourceData.data;
        myChart.data.datasets[i].data.length = 0;
        var data = myChart.data.datasets[i].data;
        for (var d = 0; d < dataSet.length; d++) {
            var tsValuePair = dataSet[d];
            var ts = tsValuePair[0];
            var value = tsValuePair[1];
            data.push({t: ts, y: value});
        }
    }
    myChart.options.scales.xAxes[0].ticks.min = self.ctx.timeWindow.minTime;
    myChart.options.scales.xAxes[0].ticks.max = self.ctx.timeWindow.maxTime;
    myChart.update();
}

And the output:

Thingsboard timeseries example

Well as you can see the X axis its defined as time and the "First" and "Second" are the datasource generated by the ctx object.

-So what do i need? As you can see both datasource coloured never change and i want to change the color by the following situations: if the value of (Y axis is > 50 and < 70 ) and during 6min (X axis) then colour green if the value of (Y axis is > 70 and < 90 ) and during 6min (X axis) then colour orange if the value of (Y axis is > 90 ) and during 6min (X axis) then colour red By default the colour will be grey lets say in this example.

I have tried to create the chart using the Chart.js library and inject it in TB but the X axis isn not the same as i expected because i need the same X axis like i showed before in the picture above.

Also i have tried this with another library, Highcharts, but the result is this: HighCharts try

The library used: https://cdnjs.cloudflare.com/ajax/libs/highcharts/10.3.3/highcharts.min.js

self.onInit = function() {
    //self.ctx.flot = new TbFlot(self.ctx);
Highcharts.chart('container', {
    chart: {
        type: 'line'
    },
    xAxis: {
        categories: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    },

    plotOptions: {
        series: {
            color: {
                linearGradient: [500, 0, 100, 0],
                stops: [
                    [0, 'red'],
                    [1, 'green']
                ]
            }
        }
    },

    series: [{
        data: [29.9, 71.5, 106.4, 129.2, 144.0, 176.0, 135.6, 148.5, 216.4, 194.1, 95.6, 54.4]
    }]
});
}

My knowledge about JS is basic and im investigating how this charts works for this libraries but i dont get how TB charts works, exclusively how the X axis works and update.

X axis Update method:

self.onDataUpdated = function() {
    for (var i = 0; i < self.ctx.data.length; i++) {
        var datasourceData = self.ctx.data[i];
        var dataSet = datasourceData.data;
        myChart.data.datasets[i].data.length = 0;
        var data = myChart.data.datasets[i].data;
        for (var d = 0; d < dataSet.length; d++) {
            var tsValuePair = dataSet[d];
            var ts = tsValuePair[0];
            var value = tsValuePair[1];
            data.push({t: ts, y: value});
        }
    }
    myChart.options.scales.xAxes[0].ticks.min = self.ctx.timeWindow.minTime;
    myChart.options.scales.xAxes[0].ticks.max = self.ctx.timeWindow.maxTime;
    myChart.update();
}```

Note: depending which version of the library we use this method changes.

If anyone who experimented or created before a custom timeseries chart in TB please let me know any useful information because from TB i didnt find to many helpful documentation.

PD: its my first time creating a question in StackOverflow

1 Answers1

0

The required behaviour is achievable in Highcharts by using zones, but requires some customization if you want to apply the duration check.

Below is an example of adding zones dynamically, based on point value and trend time length.

  chart: {
    type: 'line',
    events: {
      load: function() {
        const zones = [];
        const sixMinutes = 1000 * 60 * 6;

        function updateTime(timeObj, color, timestamp) {
          // check time for other colors
          for (let key in timeObj) {
            if (key !== color && key !== 'passed' && timeObj[key]) {
              if (timeObj.passed > sixMinutes) {
                zones.push({
                  color: 'grey',
                  value: timeObj[key]
                }, {
                  value: timeObj[key] + timeObj.passed,
                  color: key
                });
              }
              timeObj[key] = 0;
              timeObj.passed = 0;
            }
          }
          // save current trend
          if (timeObj[color]) {
            timeObj.passed = timestamp - timeObj[color];
          } else {
            timeObj[color] = timestamp;
          }
        }

        this.series.forEach(s => {
          const time = {
            green: 0,
            orange: 0,
            red: 0,
            passed: 0
          };

          s.points.forEach(p => {
            if (p.y > 50 && p.y < 70) {
              updateTime(time, 'green', p.x);
            } else if (p.y > 70 && p.y < 90) {
              updateTime(time, 'orange', p.x);
            } else if (p.y > 90) {
              updateTime(time, 'red', p.x);
            } else {
              updateTime(time, null, p.x);
            }
          });

          s.update({
            zones
          });
        });
      }
    }
  }

Live demo: https://jsfiddle.net/BlackLabel/jt0p9a3d/

API Reference: https://api.highcharts.com/highcharts/series.line.zones

Docs: https://www.highcharts.com/docs/chart-concepts/series#zones

ppotaczek
  • 36,341
  • 2
  • 14
  • 24
  • Thank you so much for your reply ppotaczek. I will try to implement this solution in ThingsBoard. My biggest challenge its to adapt it to Thingsboard due to the Update X axis function. – Denis Pintea Jul 14 '23 at 08:10
  • Hi @Denis Pintea, I don't know Thingsboard, but with pure Highcharts you don't need to update x-axis. – ppotaczek Jul 14 '23 at 08:27