Chart.js: [BUG] Cannot read property 'skip' of undefined when hover the chart

Created on 31 Dec 2016  路  33Comments  路  Source: chartjs/Chart.js

Expected Behavior

Here is a live example: https://codepen.io/anon/pen/mRbrze
It shouldn't show error in the console when I hover the chart.

Current Behavior

There are many error message in the console when I hover the chart: Cannot read property 'skip' of undefined

Possible Solution

I can follow the source of the error to: https://github.com/chartjs/Chart.js/blob/ecc35c527b8d91c2bdbc2cdc97ef667adfe7e3a3/src/core/core.interaction.js#L40

Steps to Reproduce (for bugs)

  1. open the live example: https://codepen.io/anon/pen/mRbrze
  2. hover mouse on the chart, the error message should be in the console

Context

For performance reason, when a chart is not in viewport, I update the data, but don't call chart1.update().

Environment

help wanted bug

Most helpful comment

Like many others I also ran into this error when hovering (or clicking) a chart while I was still feeding data to it. The above suggestion by jrtitus was close but didn't work, it turned out that the actual view is undefined and not just the skip property. So altering the function in core.interaction.js fixed it for me. This is what I added (full function further below):

if (!element.hasOwnProperty('_view')) {
    continue;
}

Entire function with the addition:

function parseVisibleItems(chart, handler) {
    var datasets = chart.data.datasets;
    var meta, i, j, ilen, jlen;

    for (i = 0, ilen = datasets.length; i < ilen; ++i) {
        if (!chart.isDatasetVisible(i)) {
            continue;
        }

        meta = chart.getDatasetMeta(i);
        for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
            var element = meta.data[j];
            if (!element.hasOwnProperty('_view')) {
                continue;
            }
            if (!element._view.skip) {
                handler(element);
            }
        }
    }
}

That worked for me, I hope it works for you too. Maybe the chart.js pros could have a look and see if it should be added permanently. I don't think this issue should have been closed anyway.

All 33 comments

There seems to be a lot of issues when looking into the internals of the chart. The x coordinate of the points is NaN and then they are never drawn (hence why the _view property never exists). I'm guessing the cause is https://github.com/chartjs/Chart.js/blob/master/src/core/core.datasetController.js#L14 which listens to changes in the data object. What happens when you change the data object is that we create new points in the internal meta data but we are expecting update() to be called. I think you should defer updates to the chart until they become visible though I don't know if you would see this in practice because the chart would be hidden and hence would not receive events.

CC @simonbrunel since you implemented the data update listening

Another case is: When I'm hovering a chart, I want the chart not updated, because a moving chart is not easy to see details, so I didn't call chart1.update() too.
The idea of buffering the datas until the I need the chart updated, seems OK, I will try it.

We need to synchronize the data with the metadata to get proper animations: if you replace the whole dataset.data object (and so avoid metadata implicit synchronization), there should be no errors because synchronisation will be fully done when calling chart.update().

But I don't think it's a good approach to have the chart data / labels not synced with elements while interacting with the chart (i.e. modifying data without calling update() immediately). I would rather buffer data/labels in another location and when the chart become visible (or you need it to be updated), load data and call chart.update() right after.

I finished buffering datas until I need the chart updated several hours ago, it is more complicated, but OK.
For this issue, feel free to close it.
Maybe it's better to show them as warnings, rather than throw errors.

Closing this issue as resolved

So was this resolved, if so how? Please see this. The fix for me was to downgrade Chart.js to version 2.3.0, as others have stated.

This was not resolved. I'm experiencing the same issue. It should not have been closed, in my opinion, as the solution was a workaround instead of a fix for the bug. In my case, either it's impractical to eliminate user interaction before calling update, or I'm misunderstanding the solution. I call chart update once per second, and I have an asynchronous data timer that gets data every 10 seconds. The data timer performs one fetch that gets data used for about 10 charts, which is why I'm not sure I can tie the chart updates to the completion of the data timer. If I had something like the .onevent functionality of NodeJS, this would probably be a moot discussion. :)

@defaye @fhhowdy can you both provide a fiddle that reproduce your issue. Seems like very specific use cases and we need more input in order to investigate for a proper fix.

@simonbrunel I'm not up to speed with using Chart.js directly as I'm using the Vue Charts wrapper by hchstera. @fyyyyy also mentions that "_it frequently reassigns data_".

In my case I got this error when the dataset(s) were continuously updated over an interval, and it was resolved by setting option events: ['click'] to completely remove the hover event.

@iatek aren't you going to face the same problem when user click on the chart?
my dataset is also asynchronous any I am facing the same problem.

+1 @Blanketsniffer, I have the same problem here. Adding events: ['click'] to the options object only reduces the amount of errors logged in console.

I have the same problem.

I had this issue on hover and tried setting events: ['click'] which fixed it. However I then got the error when I clicked on the graph so I tried settings events to empty events: [] and that seemed to fix it for me! 馃憤

I fixed this error by changing Ids for yAxisIDs
with error:

var altitudeSpeedGlideChartData = {
        labels: ['a','b'],
        datasets: [{
            label: 'Altitude',
            borderColor: "rgb(255, 99, 132)",
            backgroundColor: "rgb(255, 99, 132)",
            fill: false,
            data: [-1,2],
            yAxisID: 'y-axis-1',
        }, {
            label: 'Vertical Speed',
            borderColor: "rgb(54, 162, 235)",
            backgroundColor: "rgb(54, 162, 235)",
            fill: false,
            data: [4,6],
            yAxisID: 'y-axis-2',
        }]
    };

var altitudeSpeedGlideChart = document.getElementById('altitudeSpeedGlide').getContext('2d');

        window.altitudeSpeedGlide = new Chart(altitudeSpeedGlideChart, {
            type: 'line',
            data: altitudeSpeedGlideChartData,
            options: {
                responsive: true,
                hoverMode: 'index',
                stacked: false,
                scales: {
                    yAxes: [{
                        type: 'linear', // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
                        display: true,
                        position: 'left',
                        yAxisID: 'y-axis-1',
                    }, {
                        type: 'linear', // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
                        display: true,
                        position: 'right',
                        yAxisID: 'y-axis-2',
                        // grid line settings
                        gridLines: {
                            drawOnChartArea: false, // only want the grid lines for one axis to show up
                        },
                    }],
                }
            }
        });

without error:

var altitudeSpeedGlideChartData = {
        labels: ['a','b'],
        datasets: [{
            label: 'Altitude',
            borderColor: "rgb(255, 99, 132)",
            backgroundColor: "rgb(255, 99, 132)",
            fill: false,
            data: [-1,2],
            yAxisID: 'y-1',
        }, {
            label: 'Vertical Speed',
            borderColor: "rgb(54, 162, 235)",
            backgroundColor: "rgb(54, 162, 235)",
            fill: false,
            data: [4,6],
            yAxisID: 'y-2',
        }]
    };

var altitudeSpeedGlideChart = document.getElementById('altitudeSpeedGlide').getContext('2d');

        window.altitudeSpeedGlide = new Chart(altitudeSpeedGlideChart, {
            type: 'line',
            data: altitudeSpeedGlideChartData,
            options: {
                responsive: true,
                hoverMode: 'index',
                stacked: false,
                scales: {
                    yAxes: [{
                        type: 'linear', // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
                        display: true,
                        position: 'left',
                        yAxisID: 'y-1',
                    }, {
                        type: 'linear', // only linear but allow scale type registration. This allows extensions to exist solely for log scale for instance
                        display: true,
                        position: 'right',
                        yAxisID: 'y-2',
                        // grid line settings
                        gridLines: {
                            drawOnChartArea: false, // only want the grid lines for one axis to show up
                        },
                    }],
                }
            }
        });

I guess those Ids were reserved

In my case this was occurring because the labels did not correlate with the data. In other words I was missing a few labels. Also I believe this will occur if the labels are not in order.

I think the fix should be to handle this error as opposed to dumping to console, may raise a warning, as it fires massively if there is a problem and consumes quite a bit of processing power. If you use these charts on mobile and hit this the whole interface will hang.

This error still exists in 2.7.2 using the sample for the mixed chart example. Resolution is to revert to 2.5.
Stack Trace is:
core.interaction.js:39 Uncaught TypeError: Cannot read property 'skip' of undefined
at parseVisibleItems (core.interaction.js:39)
at getIntersectItems (core.interaction.js:55)
at indexMode (core.interaction.js:117)
at Chart.getElementsAtEventForMode (core.controller.js:678)
at Chart.handleEvent (core.controller.js:906)
at Chart.eventHandler (core.controller.js:856)
at listener (core.controller.js:793)
at HTMLCanvasElement.proxies.(anonymous function)

Downgrading to 2.5 didn't solve it either. I'm still seeing that error when i try to hover the graph while new data points are added in a definite interval.

Hey everyone, I've been working through this bug trying to incorporate Chart.js into a single file Vue component. I just discovered that it was an async data issue: I was trying to use data from an API call to populate my x-axis and my datasets but the chart was rendering before it had a chance to get all of the data from the call, which was provoking all kinds of errors. Just a v-if boolean evaluation in the Vue template solved this issue for me.

I solve this, updating the dataset when finish load my remote data

I solve this, updating the dataset when finish load my remote data

It would not work if I am updating dataset synchronously.

Hey guys, I just got the same issue.
I fixed it. so I share with this post.
When data change let call method destroy(), after call new Chart(...)

Just ran into this same issue while using this library: https://github.com/apertureless/vue-chartjs

Maybe too naive of a thought, but why not just check to make sure element._view is not undefined before accessing its skip property?

Current:

// core.interaction.js:39
if (!element._view.skip) {
    handler(element);
}

Proposed:

// core.interaction.js:39
if (element._view && !element._view.skip) {
    handler(element);
}

Like many others I also ran into this error when hovering (or clicking) a chart while I was still feeding data to it. The above suggestion by jrtitus was close but didn't work, it turned out that the actual view is undefined and not just the skip property. So altering the function in core.interaction.js fixed it for me. This is what I added (full function further below):

if (!element.hasOwnProperty('_view')) {
    continue;
}

Entire function with the addition:

function parseVisibleItems(chart, handler) {
    var datasets = chart.data.datasets;
    var meta, i, j, ilen, jlen;

    for (i = 0, ilen = datasets.length; i < ilen; ++i) {
        if (!chart.isDatasetVisible(i)) {
            continue;
        }

        meta = chart.getDatasetMeta(i);
        for (j = 0, jlen = meta.data.length; j < jlen; ++j) {
            var element = meta.data[j];
            if (!element.hasOwnProperty('_view')) {
                continue;
            }
            if (!element._view.skip) {
                handler(element);
            }
        }
    }
}

That worked for me, I hope it works for you too. Maybe the chart.js pros could have a look and see if it should be added permanently. I don't think this issue should have been closed anyway.

Yes NgIf worked for me too

I just removed the chartHovered method and the issue have been fixed.

@mattsnic, you are my hero, you saved my day. The chart.js pros really should have a look at your post.

In the min version, you need to replace this function, similar to the @mattsnic fix.

function ce(t, e) {
    var i, n, a, o, r;
    for (n = 0, o = t.data.datasets.length; n < o; ++n) if (t.isDatasetVisible(n)) for (a = 0, r = (i = t.getDatasetMeta(n)).data.length; a < r; ++a) {
        var s = i.data[a];
        !s.hasOwnProperty('_view') || s._view.skip || e(s)
    }
}

I had same problem but mines were due to moment.js,
Instead of
var moment = require('moment-timezone');
I had
const moment = require('moment-timezone');

I have this issue as well on hover. No fixes have worked for me yet.

Same problem, I didn't understood how to fix this.
for now the only way to fix it's to change in chart.js file line 6719 intoif (!element.hidden)
this post shouldn't be marked as closed in my opinion.
my chart version is: _"chart.js": "^2.9.3",_

It's not bug in Library. It can occurs if you calling new ChartJS(nodeElement, config) more than 1 time on same nodeElement in a flow. Just find place where you init you chart and check it. It is probably calling two or more times on init scenario.

So was this resolved, if so how? Please see this. The fix for me was to downgrade Chart.js to version 2.3.0, as others have stated.

I have downgraded and used the 2.3.0 version of Chart.js but now it's showing me this error- Uncaught TypeError: Chart is not a constructor. What can I do?

Was this page helpful?
0 / 5 - 0 ratings