Search code examples
javascriptdygraphs

Dygraphs - Highlight two series at the same time


I know the question was already asked before but I am very new to Dygraphs and struggling to find the answer. I have the following datastructure in javascript:

x , Label1, Label2, label3.... label1_2, label1_3, etc...
new Date(...), 1.23,1.45,.... , .... , ....,
new Date(...), null, null, ......., 1.23,1.434
new Date(....), 1.4656, 1.6765.......,null, null,null

The whole idea is to have a plot on which a certain part of the line is dashed and the remaining part is not. I initially have 7 time series, I splitted each time serie in two (the dashed part and the non-dashed part), now I would like to highlight the whole time series ( so 2 distinct series in terms of Dygraphs the dashed serie, and the non-dashed that I splitted in two) when I pass the mouse over either the dashed region either the non dashed region.

I ve seen that people were stipulating using HihlightCallback but I am struggling to put it in practice.

What I have for the moment:

data =[new Date(), ..,..,.,,.,,.]
labels= {'A','B', ..... }
series= {'A': {strokePattern: [10, 20] }, 'B': .......}

g = new Dygraph( demo, data, {width: 1000,height: 700,labelsDivStyles: { 'textAlign': 'right' }, labels: labels,series:series, visibility: visibility, gridLineColor: 'red', gridLinePattern: [5,5], highlightCircleSize: 2,strokeWidth: 1, strokeBorderWidth: 1,highlightSeriesOpts: { strokeWidth: 3,strokeBorderWidth: 1,highlightCircleSize: 5}});

I believe my structure should be as follows:

g.updateOptions({ highlightCallback: function(event, x, points, row, seriesName) {
//1)here I need to somehow reference the other series whose label is situated N columns from the highlighted serie ( I can also reference it by its name).
// 2) Hilight the other serie                                                 
                         }});

I tried many different syntaxe but nothing seems to be working properly. Could anyone please help me on this I am lost.

Here is what I would like to achieve :

http://www.google.co.uk/publicdata/explore?ds=k3s92bru78li6_#!ctype=l&strail=false&bcs=d&nselm=h&met_y=ggxwdn_ngdp&scale_y=lin&ind_y=false&rdim=world&idim=world:Earth&idim=country:AR:DZ:AU:AZ&ifdim=world&tstart=343382400000&tend=1574064000000&hl=en_US&dl=en_US&ind=false

Thanks a lot!


Solution

  • If I understand correctly, you've set up something like this: jsbin

    Typically you style the highlighted series using highlightSeriesOpts, but that comes with the assumption that there's only a single highlighted series.

    If you want to model the data this way (as separate series for actual & projected), you'll need to style the series yourself using highlightCallback. There are a few gross things about this which I'll mention below, but this is doable.

    Demo: jsbin

    g = new Dygraph(document.getElementById("graph"),
                     "X,Y,Y projected,Z,Z projected\n" +
                     "2006,0,,3,\n" +
                     "2008,2,,6,\n" +
                     "2010,4,,8,\n" +
                     "2012,6,,9,\n" +
                     "2014,8,8,9,9\n" +
                     "2016,,10,,8\n" +
                     "2018,,12,,6\n" +
                     "2020,,14,,3\n",
                     {
                         colors: ['blue', 'blue', 'red', 'red'],
                         series: {
                           'Y': { },
                           'Y projected': { strokePattern: [5, 5] },
                           'Z': { },
                           'Z projected': { strokePattern: [5, 5] }
                         },
                         highlightCallback: function(_, _, _, row, seriesName) {
                           update(seriesName, row);
                         },
                         unhighlightCallback: function() {
                           update();
                         },
                         highlightSeriesOpts: {},
                         highlightSeriesBackgroundAlpha: 1.0
                     });
    
    function update(selectedSeries, row) {
      var newOptions = {};
      var seriesNames = g.getLabels().slice(1);
      seriesNames.forEach(function(label) {
        newOptions[label] = {strokeWidth: 1};
      });
    
      if (selectedSeries == 'Y' || selectedSeries == 'Y projected') {
        newOptions['Y'] = newOptions['Y projected'] = {strokeWidth: 3};
      } else if (selectedSeries == 'Z' || selectedSeries == 'Z projected') {
        newOptions['Z'] = newOptions['Z projected'] = {strokeWidth: 3};
      }
      g.updateOptions({series: newOptions});
      if (typeof(row) !== 'undefined') {
        g.setSelection(row);
      }
    }
    

    The idea is that you call updateOptions in your highlightCallback, setting the strokeWidth property for each series according to whether it (or its paired series) is selected.

    There are a few gross things about this:

    • You have to set highlightSeriesOpts for the seriesName parameter to be passed to highlightCallback.
    • You need to counteract the default fading behavior of highlightSeriesOpts by setting highlightSeriesBackgroundAlpha.
    • Calling updateOptions clears the selection, so you have to call setSelection explicitly to re-select.

    If you're willing to model the measured & projected values as a single series, then you can accomplish this more cleanly by writing a custom plotter which switches from solid to dashed lines at some point.

    Here's a demo: jsbin

    g = new Dygraph(document.getElementById("graph"),
                     "X,Y,Z\n" +
                     "2004,0,3\n" +
                     "2006,2,6\n" +
                     "2008,4,8\n" +
                     "2010,6,9\n" +
                     "2012,8,9\n" +
                     "2014,10,8\n" +
                     "2016,12,6\n" +
                     "2018,14,3\n",
                     {
                         plotter: function(e) {
                           var ctx = e.drawingContext;
                           ctx.beginPath();
                           ctx.moveTo(e.points[0].canvasx, e.points[0].canvasy);
                           for (var i = 1; i < e.points.length; i++) {
                             var p = e.points[i];
                             ctx.lineTo(p.canvasx, p.canvasy);
                             if (p.xval == 2014) {
                               ctx.stroke();
                               ctx.beginPath();
                               ctx.moveTo(p.canvasx, p.canvasy);
                               ctx.setLineDash([5]);
                             }
                           }
                           ctx.stroke();
                           ctx.setLineDash([]);
                         },
                         highlightSeriesOpts: {
                           strokeWidth: 3
                         }
                     });
    

    Because your data is a single series, you no longer need to highlight multiple series simultaneously and hence you can use highlightSeriesOpts.