pablojim / highcharts-ng

AngularJS directive for Highcharts

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No correct support for multiples yAxis

ValentinH opened this issue · comments

Highcharts allows to specify several yAxis for a given chart (a demo can be see here: http://www.highcharts.com/demo/combo-multi-axes).

However, this is not properly handle by highcharts-ng:

  • multiple yAxis configuration can be passed as an array of axis to the configuration.
  • BUT all the extremes (min/max) management is done expecting a single axis instead of a possible array.

For instance, this (link to source):

var processExtremes = function(chart, axis, axisName) {
      if(axis.currentMin || axis.currentMax) {
        chart[axisName][0].setExtremes(axis.currentMin, axis.currentMax, true);
      }
    };

sets only the first axe extremes provided axis is an Axis on not an Array of Axis.

Again, for the watch on config.yAxis, the code is:

angular.forEach(axisNames, function(axisName) {
          scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
            if (newAxes === oldAxes) return;
            if(newAxes) {
              chart[axisName][0].update(newAxes, false);
              updateZoom(chart[axisName][0], angular.copy(newAxes));
              chart.redraw();
            }
          }, true);
        });

and for my opinion it should be something like this:

angular.forEach(axisNames, function(axisName) {
          scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
            if (newAxes === oldAxes) return;
            if(newAxes) {
                if(newAxes instanceof Array) {
                    for(var axe_index in newAxes) {
                        var axe = newAxes[axe_index];
                        if(axe_index < chart[axisName].length) {
                            chart[axisName][axe_index].update(axe, false);
                            updateZoom(chart[axisName][axe_index], angular.copy(axe));
                        }
                    }
                }
                else {
                    chart[axisName][0].update(newAxes, false);
                    updateZoom(chart[axisName][0], angular.copy(newAxes));
                }
                chart.redraw();
            }
          }, true);
        });

What do you think? If this last suggestion is OK, I can make a pull request.

Thanks by advance,
Valentin

Thanks for this. It looks looks generally good. Could you create a pull request and a few jsfiddles showing its use.

commented

It has another situation like this:
I have three tab to display different data. Each tab has different number serie and yAxis. when i to switch tab to show chart. yAxis doesn't change.

use @ValentinH's method it just can solve multiples yAxis, but can't solve multiples tab with multiples yAxis. finally i use
angular.forEach(axisNames, function(axisName) {
scope.$watch('config.' + axisName, function (newAxes, oldAxes) {
if (newAxes === oldAxes) return;
if(oldAxes && axisName == 'yAxis'){
initChart();
}
if(newAxes) {
chart[axisName][0].update(newAxes, false);
updateZoom(chart[axisName][0], angular.copy(newAxes));
chart.redraw();
}
}, true);
to reinit chart. Thanks by advance

I think this is a different issue. You are giving a solution that works for your problem but that doesn't work anymore for multiple axis. Indeed, your code still uses chart[axisName][0] which means only the first axis is updated.

commented

OK , thank you for your advise.

I have run into this as well, trying to manipulate a single y axis on a chart with multiple y axes. Have you made any progress on this?

Borrowing this JSFiddle (http://jsfiddle.net/ashwinp/J7LmP/4/) to illustrate that the application behaves the same regardless of the use of linkedTo - delete it and re-run and you will see the behavior remains.

The code I provided only handle the watch on multiple Y-Axis...

Understood, I wasn't sure if more had been done. Thanks for the quick reply.

What kind of manipulation do you wanna do? Cause I added a getter on the Highcharts object from which you can get each axis.

I am trying to add functionality to scroll and zoom axes of only some of the set of y axes in the chart.

I fixed my issue. The code that I thought was setting the y axis for each series was using an incorrect variable (copy/paste issue embarrassingly).

So, is there an easy way to get this functionality? Should I fork and patch it in and use my fork?

The code I posted in this issue works well for handling multiple axis but I haven't submitted a pull request because some other parts deal with axis and I don't really understand these parts...

Was this ever addressed? I would also like to the use the multiple y-axis functionality

The suggestion for the configuration of axes is not enough because it does not support creating/removing axis dynamically. I have done it like this:

  angular.forEach(axisNames, function(axisName) {
      scope.$watch('config.' + axisName, function(newAxes, oldAxes) {
        if (newAxes === oldAxes || !newAxes) {
          return;
        }

        if (angular.isArray(newAxes)) {

          for (var axisIndex = 0; axisIndex < newAxes.length; axisIndex++) {
            var axis = newAxes[axisIndex];

            if (axisIndex < chart[axisName].length) {
              chart[axisName][axisIndex].update(axis, false);
              updateZoom(chart[axisName][axisIndex], angular.copy(axis));
            }
            else {
              //Create axis if it does not exist: Cosme
              chart.addAxis(axis);
            }

            //Remove extra axis
            for (var axisIndex = newAxes.length; axisIndex < chart[axisName].length; axisIndex++) {
              chart[axisName][axisIndex].remove();
            }

          }

        } else {
          // update single axis
          chart[axisName][0].update(newAxes, false);
          updateZoom(chart[axisName][0], angular.copy(newAxes));

          //Remove extra axis
            for (var axisIndex = 1; axisIndex < chart[axisName].length; axisIndex++) {
              chart[axisName][axisIndex].remove();
            }

        }
        chart.redraw();
      }, true);
    });

This way at least supports creating/deleting axis. I am unsure of how to correct the processExtremes function, though.

Is the support for multiple axis removed completely in version 1.0.0?
It's not working with an array for xAxis or yAxis but dictionary for an axis is working.

New issue with a jsfiddle please

Added a title for xAxis and yAxis to config in 'basic-example'
axis: dictionary -> titles are applied: http://jsfiddle.net/o5dg0kjh/2/

Tried to add multiple yAxis (like http://www.highcharts.com/demo/combo-multi-axes):
axis: array -> multiple axis not applied, default yAxis is used: http://jsfiddle.net/wd0h79z9/2/

It's working if I'm changing the x/yAxis to array instead of dictionary in defaultoptions (https://github.com/pablojim/highcharts-ng/blob/master/src/highcharts-ng.js#L78):

var defaultOptions = { chart: { events: {} }, title: {}, subtitle: {}, series: [], credits: {}, plotOptions: {}, navigator: {}, xAxis: [{ events: {} }], yAxis: [{ events: {} }] };

Thanks, it looks like angular merge has some slightly strange behaviour merging dicts and arrays. angular.merge({foo: {a: 1}}, {foo: [1,2]})
I'll try add a fix.

@philippone this is now partially fixed. It now supports multiple axes but does not support the dynamic addition & deletion of axes.

This would require tracking of the axes like we track series here: https://github.com/pablojim/highcharts-ng/blob/master/src/highcharts-ng.js#L42

PRs accepted!

@pablojim I made a PR - let me know if this works: #584