Release 0.4

After fixing a couple bugs in Chart.js I began to migrate to the bugs that I possibly couldn’t 100% fix but that rather made me interested in why this issue occurs. Like most things in life when people are interested in an activity they tend to apply themselves more when compared to others. For me, I can work both ways, however, I do enjoy working projects and issues that affect real-world application and a lot of my new bug fixes and code reflect that.

I decided to take on two bugs for this release, the first bug allows too many data points to be hovered with the tooltip on certain charts. Example: ch1

Luckily when I asked to work on this issue, user etimberg helped point me in the right direction and said to take a look at the code in “core.interaction.js” to solve the issue. After hours of investigation and debugging I started drawing various conclusions as to why this bug occurs. I narrowed it down to one function simply called “x.”

x: function(chart, e, options) {
   var position = getRelativePosition(e, chart);
   var items = [];
   var intersectsItem = false;

   parseVisibleItems(chart, function(element) {
      if (element.inXRange(position.x)) {
         items.push(element);
      }

      if (element.inRange(position.x, position.y)) {
         intersectsItem = true;
      }
   });

   if (options.intersect && !intersectsItem) {
      items = [];
   }
   return items;
}

In summary, this function retrieves the tooltips in the range of “x” from function “parseVisibleItems” and then pushes the tooltip item(s) into the items array. I originally thought this bug was located in “parseVisibleItems” but after debugging further and further, I found out that “parseVisibleItems” returns all the tooltips, in general, leaving “element.inXRange(position.x)” to deal with parsing those items returned only if they are in the range of X. The keywords here that are fundamental to the bug is “inXRange.” Naturally, with a small number of data points there would be only one point in the range of X however in the case we are dealing with there upwards of three hundred and fifty data points for “x” meaning that there could be several points that are in the range of “x.”

I believe the philosophy for “inXRange” is that for a user it makes it easier to highlight and hover over data points without having to be precisely on the x coordinate in which the data point is located. “inXRange” allows the user to be somewhat close to the data point and still have it highlighted and a tooltip showing the data. But still like mentioned above when we have excessive data points close together, multiple are highlighted and returned with the items array.

Now how do we go about fixing this issue? Firstly I had to find the threshold where the multiple highlighting of data points occurs. After testing I found that “inXRange” will return more than one tooltip item as the data points increase past 40 (Here is an example of 35 data points). ch3

Now when we have more than 40 data points it essentially requires a tighter range for x because we have the data points closer and closer together. What I ended doing is making a copy and modifying function “inXRange” so that the range will be smaller allowing for only one data point to be returned. Example code:

x: function(chart, e, options) {
   var position = getRelativePosition(e, chart);
   var items = [];
   var intersectsItem = false;

   parseVisibleItems(chart, function(element) {
      if (element.datasetlength < 40) {
         if (element.inXRange(position.x)) {
            items.push(element);
         }
      } else if (element.datasetlength >= 40) {
           if (element.inXRangeSmall(position.x)) {
              items.push(element);
              // Cleanup extra elements
              if (items.length > 1) {
                 items.splice(1, items.length);
              }
           }
      }
      if (element.inRange(position.x, position.y)) {
         intersectsItem = true;
      }
   });

   if (options.intersect && !intersectsItem) {
      items = [];
   }
   return items;
}

In summary, this code applies my modified “inXRange” function when the datasetLength (amount of data points) is greater than 40. I then added an additional piece of code to splice any extra items in the array in the event that a certain datasetLength returns more than one tooltip item in the range of x. This code produces the following result:

ch2.gif

As shown above, since the range of x has been shrunken only the correct tooltips are being returned. This is currently what I have in for my pull request and I am waiting for a response from the Chart.js maintainers.

For my second bug I decided to investigate an issue in which charts aren’t showing when they are nested under the <details> tag in a div. I found this bug to be very interesting because it only occurs in Firefox and seems to be a problem with DOM loading. Example:

chartJs_firefoxBug

(Left: Firefox   Right: Chrome)

I began to dig around with the inspector tool on Firefox to see if the canvas was even showing. It turns out it was, however, there is a render time to produce a chart and when the DOM is loaded the chart isn’t loaded instantly at the same time making it not appear. The way to we get around this in Chart.js is by triggering a CSS animation when the chart is initialized so that the DOM recognizes a change in state and shows the canvas. However, Firefox cannot detect the CSS animations thus can’t refresh the DOM with the rendered canvas. A manual way around this is triggering the animations yourself with the inspector tool. Example: chartJs_firefoxBug4.gif

I began doing some research to see how other projects and developers perform DOM node insertion detection and came across an API called MutationObserver. This is a fairly new API however it is supported by all modern web browsers which would make it great for implementation with Chart.js. Basically, a MutationObserver provides developers with a way to react to changes in a DOM. It was made to replace the now deprecated “DOMContentLoaded.” I tried out some small examples on how to add and use a MutationObserver in a project but I thought I’d better ask the main Chart.js developers if this is a worthwhile solution to develop.

ch4.PNG

Unfortunately, a MutationObserver wasn’t the right API for our particular project, however, I still feel like there is a way to fix this on our end or possibly figure out why just firefox can’t detect our current implementation. Overall I enjoyed working on these two bugs and hope to accomplish more in the future. I may look at joining another project temporarily as I wait for my pull requests to be reviewed.

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s