Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error if display property changed #592

Closed
comparecourses opened this issue Aug 31, 2014 · 41 comments
Closed

Error if display property changed #592

comparecourses opened this issue Aug 31, 2014 · 41 comments

Comments

@comparecourses
Copy link

Hi,

Thanks for this great tool for charts.

Error: When the size of the window is very small I want to hide the graph, so I have set the property of a div which contains the canvas to none. But I get the following error.

"Uncaught IndexSizeError: Failed to execute 'arc' on 'CanvasRenderingContext2D': The radius provided (-0.5) is negative. "

This error was observed for doughnut type of graph. On checking it appears that that to calculate the outer radius we use the minimum of height and width, which in this case is 0, so the resulting outer radius <0. A quick fix would be if we put an extra check when calculating the outer radius.

Can you please look into it.

@james-gardner
Copy link

I get the same issue when I set responsive : true

@tannerlinsley
Copy link
Contributor

  • 1, I get this error when resizing the chart as well. Not sure why, because in my case, the chart size never hits or gets close to zero.

@james-gardner
Copy link

This error will also (for good reason) occur if the computed dimensions of the container haven't yet been applied. I got around this by using setTimeout(function () { // chart creation code }, 0);

In my case it wasn't a problem with the library.

@minimog7
Copy link

I am also getting this issue sometimes when resizing the browser, in addition to my chart not rendering until I hover my mouse over it. The same "disappearing" happens on browser resize (and window.onorientationchange on ipad) even with "responsive: false" set, although the error is not printed to the js console.

I assumed that I could manually call the chart.resize() method after setting the dimensions of the canvas container on window.resize, to ensure the proper height/width has been set, but I still get the same issue of the chart disappearing...

Also it typically works fine until I resize the browser window multiple times, and then it seems to get stuck in this error state and can't recover until the global Chart.js object gets destroyed/recreated (I use multiple chart objects on different pages, and once the error occurs on one page it carries over to the new chart objects on the other pages even though they are fresh instances, which leads me to believe the global Chart.js object is getting stuck in some error state.).

@fulldecent
Copy link
Contributor

Hello, this issue looks like an ERROR REPORT, for something not correctly implemented in Chart.js. It would be very helpful if you could please create an example chart that would illustrate this missing feature using JSBIN and even attached a mockup here of what the result should look like.

To help, I have created a simple JSBIN which you could fork:
http://jsbin.com/yozobahucero/1/edit?html,js,output

Sorry that this response is templated as we are triaging many issues and ones with test cases will be seen first.

@eL-Prova
Copy link

I have a example for the problem. Make bigger / smaller and it will already happen

http://jsbin.com/fadeno/3/edit?html,js,output

@sunguide
Copy link

how solve it?

@popcorn245
Copy link

Okay here is the fix. I was beating my head against the wall on this one as well. It was as simple as adding a try / catch.

In Chart.js on line 1919 you will see the following:

if (instance.options.responsive){
    instance.resize(instance.render, true);
}

Change it to the following:

if (instance.options.responsive){
    try{
        instance.resize(instance.render, true);
    }catch(err){
        console.log(err.message);
    }
}

Hope this helps anyone else who is stuck and maybe it makes it into the code base. Thanks! ^_^

@albertpak
Copy link

@popcorn245 thank you!

@LeleDev
Copy link

LeleDev commented Dec 5, 2014

Still getting this error.. could the fix be merged?

@ritz078
Copy link

ritz078 commented Dec 27, 2014

It should be merged.

@tannerlinsley
Copy link
Contributor

I'm not sure if this is still needed, but here is a PR #835 with @popcorn245 's fix. If it's approved by other collaborators, we'll get it merged.

@labmorales
Copy link

Had the same problem and it wasn't fixed by @popcorn245 patch. Sometimes the resize script is unable to compute the right width or height, thus returning zero. Probably something to do with the dom element resizing not being finished on time of execution.

Line 837.

            // Something went wrong retry in 50 milisecs
            if(newWidth && newHeight){

                canvas.width = this.chart.width = newWidth;
                canvas.height = this.chart.height = newHeight;

                retinaScale(this.chart);

                if (typeof callback === "function"){
                    callback.apply(this, Array.prototype.slice.call(arguments, 1));
                }
                return this;
            }else{
                var aux = this;
                setTimeout(function(callback){ Chart.Type.prototype.resize.call(aux, callback) }, 50);
            }

Hope it helps someone.

@rgarner
Copy link

rgarner commented Mar 4, 2015

I've been getting this in a Rails 4 project. None of the above solutions worked. Realised I had turbolinks on, so the $(document).ready that set up the chart wasn't firing, and caused this negative radius issue. Solved by either disabling turbolinks or installing the jquery.turbolinks gem.

@LeleDev
Copy link

LeleDev commented May 7, 2015

Stil waiting for a fix...

@pimbrouwers
Copy link

To me the solution is dead simple. Using the latest commit, update the Chart.Arc function as follows:

Chart.Arc = Chart.Element.extend({
        inRange: function (chartX, chartY) {

        var pointRelativePosition = helpers.getAngleFromPoint(this, {
            x: chartX,
            y: chartY
        });

        //Check if within the range of the open/close angle
        var betweenAngles = (pointRelativePosition.angle >= this.startAngle && pointRelativePosition.angle <= this.endAngle),
            withinRadius = (pointRelativePosition.distance >= this.innerRadius && pointRelativePosition.distance <= this.outerRadius);

        return (betweenAngles && withinRadius);
        //Ensure within the outside of the arc centre, but inside arc outer
    },
    tooltipPosition: function () {
        var centreAngle = this.startAngle + ((this.endAngle - this.startAngle) / 2),
            rangeFromCentre = (this.outerRadius - this.innerRadius) / 2 + this.innerRadius;
        return {
            x: this.x + (Math.cos(centreAngle) * rangeFromCentre),
            y: this.y + (Math.sin(centreAngle) * rangeFromCentre)
        };
    },
    draw: function (animationPercent) {

        var easingDecimal = animationPercent || 1;

        var ctx = this.ctx;
        var innerRadius = (this.innerRadius < 0) ? this.innerRadius * -1 : this.innerRadius;
        var outerRadius = (this.outerRadius < 0) ? this.outerRadius * -1 : this.outerRadius;

        ctx.beginPath();

        ctx.arc(this.x, this.y, outerRadius, this.startAngle, this.endAngle);

        ctx.arc(this.x, this.y, innerRadius, this.endAngle, this.startAngle, true);

        ctx.closePath();
        ctx.strokeStyle = this.strokeColor;
        ctx.lineWidth = this.strokeWidth;

        ctx.fillStyle = this.fillColor;

        ctx.fill();
        ctx.lineJoin = 'bevel';

        if (this.showStroke) {
            ctx.stroke();
        }
    }
});

The thing to take note of is the ternary operator on both inner and outer radius to prevent negative values. This worked like a charm on my project. Charts continued to be responsive and there was NO deleterious effects by converting the radii into natural numbers (ie: positive)

@ghost
Copy link

ghost commented Jun 12, 2015

ı get the same error. And when I look at my canvas I look at my canvas I see this : http://imgur.com/TfFlLVH

But the desired width and height are 300px and I clearly stated it, but it changes to 0.

And I see no error in console with pimbrouwers' patch but still canvas isn't rendering with 0 width and height.

EDİT: Okay, I changed the time to create the charts to document.ready and it was still getting error. But I tried to create the charts in setTimeout(in document.ready) with 300 ms delay and I got the chart ready for me. The error was gone.

@pimbrouwers
Copy link

@bmsedat if the setTimeout worked that probably means you have a race condition somewhere. You should avoid using setTimeout whenever you can, unless say you're doing something like a "polling" system.

Are you using Chart JS within a Javascript framework like Angular or Knockout?

Are you fetching your data from an external source? If so, you should be creating the chart in a callback after YOU KNOW the data fetching is completed.

@ghost
Copy link

ghost commented Jun 12, 2015

No, I'm not fetching my data from external source, nor I have something like a polling system, nor I use a framework.. Like I said I already tried to use it in document.ready, if you somehow guess how a canvas or data is not ready when "document" is ready, all you said is inaccurate with me.

@pimbrouwers
Copy link

@bmsedat to begin, you obviously need to calm down a little bit. I'm simply trying to help you. What's worse is you've missed my point entirely...

If using setTimeout solved the problem for you, you most likely have a race condition. I wasn't accusing you as to what might be causing it. I was simply probing for more details, so I could point you in the right direction.

The document.ready may very well not work in your case, as it simply denotes the DOM being ready, which probably isn't satisfactory in your case. As I said, if you're fetching data from an external resource (this includes hitting a controller in your own project). Then you need to have the chart initiate as a callback after the data has been fully retrieved. This methodology isn't something I've contrived, it's common practice in JavaScript.

I would offer to review your code if you posted a sample somewhere, but given you basically bit my head off for trying to help. You can continue to struggle along.

Have a nice day. Best of luck with your race condition.

@ghost
Copy link

ghost commented Jun 12, 2015

Okay, thanks.

@web-engineer
Copy link

OK - I've just had this problem too... I just updated to the latest commit on the master branch and observed this problem - yet it is not present in an earlier commit.

Commit -
1cfa42b 17th September 2014 works fine.

I haven't used blame to the current commit, however I should add I'm using charts within an accordion component so perhaps the current branch is not reading the size of the canvas when the element is hidden in the display list?

For me the fix is simple (for now), I've just wound back to where I was, I only pulled to the latest commit as I was debugging something that ultimately wasn't to do with chart.js.

Happy to assist some time when we're less busy but hope this observation helps.

(just to add - the error we had was identical to that in the opening of this issue)

@steezeburger
Copy link

This is happening to me when I use an ng-show="watchedData.length > 0" to show/hide my charts based on available datum.

The chart datum is calculated inside a $watch on $watchedData. I'm guessing there's not enough time after triggering the ng-show to get proper sizes for the charts?, so it's throwing this error.

I'm just not using the ng-show for now. I haven't really thought through a fix for my use case yet, but maybe this will help someone else drill down their bug.

@rohan-deshpande
Copy link

This is happening to me but randomly. It sometimes happens, and sometimes doesn't. Weird.

Edit: well seems like a setTimeout fixed it. I'm not ajaxin' in my data so I don't know what's causing it at all, I can't recreate the issue solidly, it seems to be completely random.

Edit: actually no, the setTimeout didn't fix it at all. So for me right now, responsive:true is broken, I'm only using Pie charts so I am not sure about others, but for me this feature isn't working in the build I am using (v1.0.2)

@John-Lin
Copy link

Stil waiting for a fix... +1

@LeleDev
Copy link

LeleDev commented Aug 19, 2015

+1

@vchalyi
Copy link

vchalyi commented Aug 19, 2015

I am waiting for a fix too +1

@ghost
Copy link

ghost commented Aug 28, 2015

BUMP! +1

@hakkikonu
Copy link

Also I observed this bug on line chart. When I combine Jquery's toggle function with <canvas> chart does not shown.

@venantius
Copy link

Also experiencing this issue.

@etimberg
Copy link
Member

I have a fix for this for v2.0 in #1470. The fix in the PR will handle resizing the canvas when the display property changes on the parent. Nothing should preclude this PR from being back ported to v1.0. I'd be happy to merge a PR into v1.0 once #1470 is merged into v2.

@george3447
Copy link

+1

2 similar comments
@jakenoble
Copy link

+1

@overflood
Copy link

+1

@jakesylvestre
Copy link
Contributor

Appears to be fixed in #1092 and #1470 has been merged. @etimberg are we good to merge?

@etimberg
Copy link
Member

etimberg commented Nov 4, 2015

@jakesyl i think we can backport #1470 to v1

@nolros
Copy link

nolros commented Nov 10, 2015

ran into the same problem with the latest version and Angular 1.4. As per a comment above it seems to be a data latency issue and as such I built a simple $interval in the directive that solves the problem but you could timeout to the same in JS.

<canvas id="{{ section.chart.app_id }}" width="{{ section.chart.width }}" height="{{section.chart.height }}" donut-chart="{{ section.chart.app_id }}"></canvas>
.directive( 'donutChart', [ 'ChartService', '$interval', function(ChartService, $interval) {
    return {
        link: function( scope, elem, attrs ) {
            var getData,
                chartUuid  = attrs['donutChart'];

            // destroy timer
            function killTimer(){
                if(angular.isDefined(timer)) {
                    $interval.cancel(timer);
                    timer=undefined;
                }
            }

            var timer = $interval(function () {
                getData = ChartService.getChartDataByUuid(chartUuid);

                if(getData) {
                    killTimer();
                   var chart = elem.context.getContext("2d");
                   var donutChart  = new Chart(cmochart).Doughnut(getData , ChartService.getDonutChartConfig());
                } else {
                    console.log('waiting for data');
                }
            }, 100);

        }
    }
}]);

etimberg added a commit that referenced this issue Nov 17, 2015
@dylmye dylmye mentioned this issue Dec 10, 2015
@wilywork
Copy link

"Uncaught IndexSizeError: Failed to execute 'arc' on 'CanvasRenderingContext2D': The radius provided (-0.5) is negative. "
for solution error , the <canvas .... be visible !

axeljohansson added a commit to I-sektionen/isektionen_old that referenced this issue Feb 23, 2016
@Rahul-pra
Copy link

Rahul-pra commented Apr 4, 2018

In Chart.js see the following:
Step :1

if (instance.options.responsive){
    instance.resize(instance.render, true);
}

Change it to the following:

if (instance.options.responsive){
    try{
        instance.resize(instance.render, true);
    }catch(err){
        console.log(err.message);
    }
}

and
Step 2:
In Chart.js see the following:

this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - this.options.segmentStrokeWidth/2)/2;
Change it to the following:
this.outerRadius = (helpers.min([this.chart.width,this.chart.height]) - 0/2)/2;

because of this.options.segmentStrokeWidth default value 2 get from page jQuery

or if you don't want to above step 1 and step 2 change follow other step
In page jQuery function change following:

segmentStrokeWidth : 0, //default 2

@SilviuIordache
Copy link

This error will also (for good reason) occur if the computed dimensions of the container haven't yet been applied. I got around this by using setTimeout(function () { // chart creation code }, 0);

In my case it wasn't a problem with the library.

Thank you, wrapping the chart initialization in a setTimeout worked for me (using Chart.js in Vue)

@SameenaMulla
Copy link

I used this autoSkip=true in combinational line and volume graph for large dataset facing double gap at the end of chart. @pzelnip if you have any solution please let me know.
graph

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests