highchartstypescriptdatejs

Problems rendering an ISO Serialized DateTime JSON into a Highcharts time-series?


I am trying to use latest Highcharts to render data from Web API which is ISO formatted. I am using TypeScript and datejs (http://www.datejs.com/).

I am intending to update this chart on a poll, and the series can be dramatically transformed between requests so I have decided to destroy and recreate the chart from scratch. I tried setting the options directly and redrawing but that did not seem to have any effect.

But to be sure I commented out the initial chart creation and destruction, and I still got the same error. I have checked to see that the parser is returning a date object and it is, and the data seems to be correct.

My guess is it has something to do with how I'm constructing my data element.

Is this an acceptable structure for time-series data for high-charts:

var data: [Date, number][] = [, ];

My Model:

export interface Chart {
    Title: string;
    Series: ChartSeries[];
    XAxisTitle: string;
    YAxisTtile: string;
}
export interface ChartSeries {
    Title: string;
    Points: ChartDataPoint[];
}
export interface ChartDataPoint {
    X: string;
    Y: number;
}

An example series in XML (using NewtonSoft.Json to do the Json serialization)

<ChartSeries>
    <Points>
        <ChartDataPoint>
            <X>2015-12-16T00:00:00</X>
            <Y>184</Y>
        </ChartDataPoint>
        <ChartDataPoint>
            <X>2015-12-16T05:00:00</X>
            <Y>168</Y>
        </ChartDataPoint>
        <ChartDataPoint>
            <X>2015-12-16T07:00:00</X>
            <Y>282</Y>
        </ChartDataPoint>
    </Points>
    <Title>Version: UNK;Service Type: 1002;Server: UNK;Method Name: GetAllCustomerDetails
    </Title>
</ChartSeries>

Relevant portion of the ViewModel:

 protected Draw(): void {
        var chart = this.ChartData();
        if (!Util.Obj.isNullOrUndefined(chart)) {
            this.IsDrawing(true);
            var series: HighchartsSeriesOptions[] = [];
            for (var i = 0; i < chart.Series.length; i++) {
                var s = chart.Series[i];
                var data: [Date, number][] = [, ];
                for (var p = 0; p < s.Points.length; p++) {
                    var point = s.Points[p];
                    data.push([Date.parse(point.X), point.Y]);
                }
                series.push({
                    type: "line",
                    data: data,
                    name: s.Title
                });
            }

            var options: HighchartsOptions = {
                chart: {
                    renderTo: this.chartElementName,
                    ignoreHiddenSeries: false
                },
                series: series,
                title: chart.Title,
                yAxis: {
                    type: 'logarithmic',
                    minorTickInterval: 1,
                    title: chart.YAxisTtile
                },
                xAxis: {
                    type: 'datetime',
                    title: chart.XAxisTitle
                }
            };
            this.Chart.destroy();
            this.Chart = new Highcharts.Chart(options);
            this.IsDrawing(false);
        }
    }

The error:

  Line: 14084
  Error: Unable to set property 'index' of undefined or null reference

Some context for the error from highcharts.src.js:

generatePoints: function () {
        var series = this,
            options = series.options,
            dataOptions = options.data,
            data = series.data,
            dataLength,
            processedXData = series.processedXData,
            processedYData = series.processedYData,
            pointClass = series.pointClass,
            processedDataLength = processedXData.length,
            cropStart = series.cropStart || 0,
            cursor,
            hasGroupedData = series.hasGroupedData,
            point,
            points = [],
            i;

        if (!data && !hasGroupedData) {
            var arr = [];
            arr.length = dataOptions.length;
            data = series.data = arr;
        }

        for (i = 0; i < processedDataLength; i++) {
            cursor = cropStart + i;
            if (!hasGroupedData) {
                if (data[cursor]) {
                    point = data[cursor];
                } else if (dataOptions[cursor] !== UNDEFINED) { // #970
                    data[cursor] = point = (new pointClass()).init(series, dataOptions[cursor], processedXData[i]);
                }
                points[i] = point;
            } else {
                // splat the y data in case of ohlc data array
                points[i] = (new pointClass()).init(series, [processedXData[i]].concat(splat(processedYData[i])));
            }
            points[i].index = cursor; // For faster access in Point.update <-- error happens here, there is a single item in the collection that is undefined
        }

As Requested, stack trace:

Series.generatePoints   @   highcharts.src.js:14084
Series.translate    @   highcharts.src.js:14165
(anonymous function)    @   highcharts-more.js:53
obj.(anonymous function)    @   highcharts.src.js:660
(anonymous function)    @   highcharts.src.js:12830
each    @   highcharts.src.js:1106
Chart.renderSeries  @   highcharts.src.js:12829
(anonymous function)    @   highcharts-3d.js:26
obj.(anonymous function)    @   highcharts.src.js:660
Chart.render    @   highcharts.src.js:12937
Chart.firstRender   @   highcharts.src.js:13112
Chart.init  @   highcharts.src.js:11841
(anonymous function)    @   highcharts-3d.js:25
obj.(anonymous function)    @   highcharts.src.js:660
Chart.getArgs   @   highcharts.src.js:11746
Highcharts.Chart    @   highcharts.src.js:11720
ChartViewModel.Draw @   ChartViewModel.ts:160
(anonymous function)    @   ChartViewModel.ts:180
(anonymous function)    @   jquery-2.1.4.js:3256
fire    @   jquery-2.1.4.js:3099
self.fireWith   @   jquery-2.1.4.js:3211
deferred.(anonymous function)   @   jquery-2.1.4.js:3301
(anonymous function)    @   ChartViewModel.ts:244
(anonymous function)    @   jquery-2.1.4.js:3256
fire    @   jquery-2.1.4.js:3099
self.fireWith   @   jquery-2.1.4.js:3211
done    @   jquery-2.1.4.js:8264
(anonymous function)    @   jquery-2.1.4.js:8605

Solution

  • As it turns out there were two problems:

    var data: [Date, number][] = [, ];
    

    In order to solve the exception:

    var data: [Date, number][] = [];
    

    In order for the days to render correctly:

    var data: [number, number][] = [];
    

    and

    var d = Date.parse(point.X);
    data.push([
     Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()), 
     point.Y
    ]);