wergeld
wergeld

Reputation: 14462

Update Data Point From Existing DataTable On Set Interval

I want to have the HighChart update the series by added the next data point to the chart so that the chart "plays". I have a data series that contains both an X an Y component. I would like for chart to be updated (say every second) with the next point in this series. I am using this in a VB.NET 4 site using DotNet.HighCharts API. I have followed along on several demos (such as this one) and all of these are using some randomly generated value. How can I get the chart to use an existing set of points? Here is a jsFiddle using the random function - http://jsfiddle.net/tQpNN/3/ I just do not know how to iterate through the passed in data series (if that is the way to do it) or to make DotNet.HighCharts iterate for me.

EDIT with some code:

    Dim stfipsList4 = (From r In dt4.AsEnumerable() Select r("areaname")).Distinct().ToList()
    Dim SeriesList4 As New List(Of Series)(stfipsList4.Count)
    Dim seriesItem4(stfipsList4.Count) As Series
    Dim xDate4 As DateTime
    Dim fakeDate4 As String
    Dim sX4 As Integer

    sX4 = 1
    For Each state In stfipsList4
        Dim data As New Dictionary(Of DateTime, Decimal)
        Dim stateVal As String = state.ToString
        Dim recCount As Integer = dt4.Rows.Count - 1
        Dim seriesPointCount As Integer = dt4.Compute("Count(population)", "areaname = '" + stateVal + "'")
        Dim chartData As Object(,) = New Object(seriesPointCount - 1, 1) {}
        Dim x As Integer = 0
        For i As Integer = 0 To recCount
            If dt4.Rows(i)("areaname").ToString = stateVal Then
                fakeDate4 = "1/1/" + dt4.Rows(i)("periodyear").ToString
                xDate3 = DateTime.Parse(fakeDate4)
                chartData.SetValue(xDate4.Date, x, 0)
                chartData.SetValue(dt4.Rows(i)("population"), x, 1)
                x += 1
            End If

        Next

        seriesItem4(sX4) = New Series With {
                    .Name = state.ToString, _
                    .Data = New Helpers.Data(chartData)
        }

        SeriesList4.Add(seriesItem3(sX4))

        sX4 = sX4 + 1
    Next


    Dim iterateData As String = JsonSerializer.Serialize(New Helpers.Data(New Object() {seriesItem3(1).Data}))

    Dim chart4 As Highcharts = New Highcharts("chart4").SetOptions(New Helpers.GlobalOptions() With { _
        .[Global] = New [Global]() With { _
                .UseUTC = False _
            } _
        }).InitChart(New Chart() With { _
         .DefaultSeriesType = ChartTypes.Spline, _
         .MarginRight = 10, _
         .Events = New ChartEvents() With { _
          .Load = "ChartEventsLoad" _
         } _
        }).SetTitle(New Title() With { _
         .Text = "Live data" _
        }).SetXAxis(New XAxis() With { _
         .Type = AxisTypes.Datetime, _
         .TickPixelInterval = 150 _
        }).SetSeries(New Series() With { _
             .Data = New Helpers.Data(New Object() {})
            }) _
    .AddJavascripVariable("counter", "0") _
    .AddJavascripVariable("stockData", iterateData) _
    .AddJavascripFunction("ChartEventsLoad", "// set up the updating of the chart each second" & vbCr & vbLf & _
                          " var series = this.series[0];" & vbCr & vbLf & _
                          " setInterval(function() {" & vbCr & vbLf & _
                          " var x = stockData[counter].key;" & vbCr & vbLf & _
                          " var y = stockData[counter].value;" & vbCr & vbLf & _
                          " series.addPoint([x, y], true, series.points.length > 10);" & vbCr & vbLf & _
                          " counter++;" & vbCr & vbLf & _
                          "}, 1000);")

This passes in my series of data (could be 1 or multiple different individual series). What I want to do is have the series points "play" by adding one point at a time (with scaling of the x-axis but I do not want to remove any points). This dummy version just adds a new random y-value at a given instant. I am not sure how to iterate over my existing data.

This does set the "stockData" javascript var to my data set. I am seeing errors in FireBug stating that

stockData[counter] is undefined

The var counter is defined in the $(document).ready(function) along with the stockdata and chart4 chart. See http://jsfiddle.net/ZvYT6/ for what the DotNet.Highcharts API spits out. The in-line javascript for the iteration looks like this:

        function ChartEventsLoad(){
        // set up the updating of the chart each second
 var series = this.series[0];
 setInterval(function() {
 var x = stockData[counter].key;
 var y = stockData[counter].value;
 series.addPoint([x, y], true, series.points.length > 10);
 counter++;
}, 1000);
    }
});

The part I am really unsure on is the stockData[counter] key/value. What is this called in javascript? stockdata is a list of data that looks like:

    var stockData = { data: [{ data: [[Date.parse('01/01/1900 00:00:00'), 530000],
    ....,
[Date.parse('01/01/2010 00:00:00'), 18801310]]
    }]
    };

EDIT v4: Okay, so now I am able to parse out my array of data using some nasty javascript.

    Dim iterateData As String = JsonSerializer.Serialize(seriesItem3(1))

    Dim chart4 As Highcharts = New Highcharts("chart4").SetOptions(New Helpers.GlobalOptions() With { _
        .[Global] = New [Global]() With { _
                .UseUTC = False _
            } _
        }).InitChart(New Chart() With { _
         .DefaultSeriesType = ChartTypes.Spline, _
         .MarginRight = 10, _
         .Events = New ChartEvents() With { _
          .Load = "ChartEventsLoad" _
         } _
        }).SetTitle(New Title() With { _
         .Text = "Live data" _
        }).SetXAxis(New XAxis() With { _
         .Type = AxisTypes.Datetime, _
         .TickPixelInterval = 150 _
        }).SetSeries(New Series() With { _
             .Data = New Helpers.Data(New Object() {})
            }) _
    .AddJavascripVariable("counter", "0") _
    .AddJavascripVariable("stockData", iterateData.ToString) _
    .AddJavascripFunction("ChartEventsLoad", "// set up the updating of the chart each second" & vbCr & vbLf & _
                          " var result = stockData.data;" & vbCr & vbLf & _
                          " var series = this.series[0];" & vbCr & vbLf & _
                          " setInterval(function() {" & vbCr & vbLf & _
                          " var p = String(result[counter]);" & vbCr & vbLf & _
                          " var splitp = p.split("","");" & vbCr & vbLf & _
                          " var x = splitp[0];" & vbCr & vbLf & _
                          " var y = splitp[1];" & vbCr & vbLf & _
                          " series.addPoint([x, y], true, false, true);" & vbCr & vbLf & _
                          " counter++;" & vbCr & vbLf & _
                          "}, 1000);")

    ltrChart4.Text = chart4.ToHtmlString()

If I look at the x and y values in firebug I can see that these are the expected values. However, my chart just updates with times on the x-axis starting at ~1900 hours and adds a point every second (per the javascript function) but there is no y value. In addition the y-axis appears to start at -2.5 - none of the values I am using are less than 1000 let alone 0. I am so close...

Upvotes: 1

Views: 1325

Answers (2)

wergeld
wergeld

Reputation: 14462

Finally got this working. This is my solution - probably not the most pretty but it works. The important bit is to pass the iterated the iterateData.ToString(). From this point you can then loop over that and then split on each element. I added in a check to make sure the addition of the points stops once we reach the last point in the data set. To do still is to allow it to handle more than one series and "play" them both.

    Dim stfipsList4 = (From r In dt4.AsEnumerable() Select r("areaname")).Distinct().ToList()
    Dim SeriesList4 As New List(Of Series)(stfipsList4.Count)
    Dim seriesItem4(stfipsList4.Count) As Series
    Dim xDate4 As DateTime
    Dim fakeDate4 As String
    Dim sX4 As Integer

    sX4 = 1
    For Each state In stfipsList4
        Dim data As New Dictionary(Of DateTime, Decimal)
        Dim stateVal As String = state.ToString
        Dim recCount As Integer = dt4.Rows.Count - 1
        Dim seriesPointCount As Integer = dt4.Compute("Count(population)", "areaname = '" + stateVal + "'")
        Dim chartData As Object(,) = New Object(seriesPointCount - 1, 1) {}
        Dim x As Integer = 0
        For i As Integer = 0 To recCount
            If dt4.Rows(i)("areaname").ToString = stateVal Then
                fakeDate4 = "1/1/" + dt4.Rows(i)("periodyear").ToString
                xDate3 = DateTime.Parse(fakeDate4)
                chartData.SetValue(xDate4.Date, x, 0)
                chartData.SetValue(dt4.Rows(i)("population"), x, 1)
                x += 1
            End If

        Next

        seriesItem4(sX4) = New Series With {
                    .Name = state.ToString, _
                    .Data = New Helpers.Data(chartData)
        }

        SeriesList4.Add(seriesItem3(sX4))

        sX4 = sX4 + 1
    Next

    Dim iterateData As String = JsonSerializer.Serialize(seriesItem3(1))

    Dim chart4 As Highcharts = New Highcharts("chart4").SetOptions(New Helpers.GlobalOptions() With { _
        .[Global] = New [Global]() With { _
                .UseUTC = False _
            } _
        }).InitChart(New Chart() With { _
         .DefaultSeriesType = ChartTypes.Column, _
         .MarginRight = 10, _
         .Events = New ChartEvents() With { _
          .Load = "ChartEventsLoad" _
         } _
        }).SetTitle(New Title() With { _
         .Text = "Live data" _
        }).SetXAxis(New XAxis() With { _
         .Type = AxisTypes.Datetime, _
         .TickPixelInterval = 150 _
        }).SetSeries(New Series() With { _
             .Data = New Helpers.Data(New Object() {}), _
             .Name = seriesItem3(1).Name
            }) _
    .AddJavascripVariable("iterated", iterateData.ToString) _
    .AddJavascripFunction("ChartEventsLoad", "// set up the updating of the chart each second" & vbCr & vbLf & _
                          " var result = iterated.data;" & vbCr & vbLf & _
                          " var counter = 0;" & vbCr & vbLf & _
                          " var series = this.series[0];" & vbCr & vbLf & _
                          " var loopseries = function() {" & vbCr & vbLf & _
                          " if (counter <= result.length) {" & vbCr & vbLf & _
                          " var p = String(result[counter]);" & vbCr & vbLf & _
                          " var splitp = p.split("","");" & vbCr & vbLf & _
                          " var x = Number(splitp[0]);" & vbCr & vbLf & _
                          " var y = Number(splitp[1]);" & vbCr & vbLf & _
                          " series.addPoint([x, y], true, series.points.length > 10, true);" & vbCr & vbLf & _
                          " counter++;" & vbCr & vbLf & _
                          " } else {" & vbCr & vbLf & _
                          " clearInterval(loopseries);" & vbCr & vbLf & _
                          " }};" & vbCr & vbLf & _
                          " setInterval(loopseries, 100);")

    ltrChart4.Text = chart4.ToHtmlString()

Upvotes: 2

Vangi
Vangi

Reputation: 724

You can see the demo for "Spline Update Each Second" at the sample project of the DotNet.Highchart project

Anyway, here is an example code how you can add point each second in your chart when you iterate your data:

Highcharts chart = new Highcharts("chart")
            .SetOptions(new GlobalOptions { Global = new Global { UseUTC = false } })
            .InitChart(new Chart
                       {
                           DefaultSeriesType = ChartTypes.Spline,
                           MarginRight = 10,
                           Events = new ChartEvents
                                    {
                                        Load = "ChartEventsLoad"
                                    }
                       })
            .SetTitle(new Title { Text = "Live data" })
            .SetXAxis(new XAxis
                      {
                          Type = AxisTypes.Datetime,
                          TickPixelInterval = 150
                      })
            .SetSeries(new Series
                       {
                           Name = "Live data",
                           Data = new Data(new[] { new Point { X = Tools.GetTotalMilliseconds(DateTime.Now), Y = 0 } })
                       })
            .AddJavascripVariable("counter", "0")
            .AddJavascripVariable("stockData", JsonSerializer.Serialize(ChartsData.StockData))
            .AddJavascripFunction("ChartEventsLoad",
                                  @"// set up the updating of the chart each second
                                   var series = this.series[0];
                                   setInterval(function() {
                                      var x = (new Date()).getTime(); // current time
                                      var y = stockData[counter];
                                      series.addPoint([x, y], true, series.points.length > 10);
                                      counter++;
                                   }, 1000);");

Sorry for the C# code. I hope this is helpful and you can find good converter.

Upvotes: 1

Related Questions