Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ngClick causes D3 chart to redraw

Whenever I click on one of the points it causes the chart to update. This only happens if I've got an ngClick directive on the <nvd3> element (even if the listener function does nothing). If I remove the ngClick, everything's fine.

I'm using a pretty basic nvd3 scatter chart with angular-nvd3.

What could be causing this strange interaction?

(The framerate of this recording is low, so it's hard to see but the chart is redrawn on each click, including the top one)

Clicking points on a graph

Here's a plunker that reproduces the issue:

http://plnkr.co/edit/F0ZslBaisoHWIp0VcI8o

Thanks!

UPDATE I've narrowed it down to a watch within angular-nvd3. Somehow the presence of the ngClick is causing the 'data' to change. This line is triggering the refresh: https://github.com/krispo/angular-nvd3/blob/master/dist/angular-nvd3.js#L328 There's nothing in my code that changes 'data' (also verified the object is the same instance outside the directive), and there's nothing I can see in angular-nvd3.js that could change the data at all... hmmm...

UPDATE Here's my click event listener (it's empty):

controller.handleChartClick = function(event) {
};

and html:

<div class="col-sm-10">
    <nvd3 ng-click="observationsCharts.handleChartClick($event)"
              options="observationsCharts.scatterPlotChartOptions"
              data="observationsCharts.scatterPlotChartData"></nvd3>
</div>
like image 344
HankScorpio Avatar asked Sep 27 '22 23:09

HankScorpio


2 Answers

You are correct that the following watch is causing the issue:

// Watching on data changing
 scope.$watch('data', function (newData, oldData) {
  if (newData !== oldData && scope.chart) {

    if (!scope._config.disabled && scope._config.autorefresh) {
        scope._config.refreshDataOnly && scope.chart.update ? scope.chart.update() : scope.api.refresh(); // if wanted to refresh data only, use chart.update method, otherwise use full refresh.
                            }
                        }
                    }, scope._config.deepWatchData);

The thing is, if you add a log in this function to see what the old and new data is, the data is actually changing.

When you click on one of the points, nvd3 is adding a color attribute to the data.

old data:

[{"key":"Battery Voltage","values":[{"x":1439419440000,"y":90,"series":0},{"x":1439419440000,"y":43,"series":0},{"x":1439419440000,"y":345,"series":0},{"x":1439167620000,"y":73,"series":0},{"x":1439167620000,"y":42,"series":0},{"x":1439167620000,"y":36,"series":0},{"x":1440010740000,"y":32,"series":0},{"x":1439419440000,"y":62,"series":0},{"x":1439167620000,"y":73,"series":0},{"x":1439167620000,"y":42,"series":0},{"x":1439167620000,"y":36,"series":0}]}] 

new data:

[{"key":"Battery Voltage","values":[{"x":1439419440000,"y":90,"series":0,"color":"#1f77b4"},{"x":1439419440000,"y":43,"series":0,"color":"#1f77b4"},{"x":1439419440000,"y":345,"series":0},{"x":1439167620000,"y":73,"series":0},{"x":1439167620000,"y":42,"series":0},{"x":1439167620000,"y":36,"series":0},{"x":1440010740000,"y":32,"series":0},{"x":1439419440000,"y":62,"series":0,"color":"#1f77b4"},{"x":1439167620000,"y":73,"series":0},{"x":1439167620000,"y":42,"series":0},{"x":1439167620000,"y":36,"series":0}],"color":"#1f77b4","value":90}] 

Each time you click a new point, the color attribute is added to the object, so the watch function is actually running correctly.

I would advise opening an issue over at https://github.com/krispo/angular-nvd3

**Edit - Just to clarify, the reason it happens when ng-click is added is because this forces the Angular digest cycle to run which will trigger the watch.

like image 200
Stacey Burns Avatar answered Oct 03 '22 22:10

Stacey Burns


Looks like the only workaround to this (for now) is to use the config setting deepWatchData: false. That prevents the $watch getting triggered too often.

<nvd3 config="{deepWatchData: false}" options="..." data="..."/>
like image 40
HankScorpio Avatar answered Oct 03 '22 21:10

HankScorpio