Search code examples
javascriptsliderd3.jsrickshaw

One slider, two graphs, with Rickshaw and D3.js


I have two graphs rendering with Rickshaw, perfectly fine. I have a single slider that I want to be able to manipulate both graphs, but what it's doing now is manipulating the last graph that I declare:

//graph one
var graph_one = new Rickshaw.Graph( {
        element: document.querySelector("#chart_one"),
        height: 150,
        width: 170,
        renderer: 'bar',
        series: data
} );

//slider code
var slider_one = new Rickshaw.Graph.RangeSlider({
    element: document.querySelector('#slider-range'),
    graph: graph_one
});

graph_one.render();

//graph two
var graph_two = new Rickshaw.Graph( {
        element: document.querySelector("#chart_two"),
        renderer: 'line',
        height: 150,
        width: 170,
        series: data
} );

//slider code
var slider_two = new Rickshaw.Graph.RangeSlider({
    element: document.querySelector('#slider-range'),
    graph: graph_two
});

graph_two.render();

Is it possible to have one slider manipulate two graphs?


Solution

  • I accomplished this by editing the rickshaw.js, specifically editing Rickshaw.Graph.RangeSlider to accept arrays of graphs as a graph variable:

    Rickshaw.Graph.RangeSlider = function(args) {
    
        var element = this.element = args.element;
        var graph = this.graph = args.graph;
        //added by bozdoz
        if(graph.constructor === Array){
                $( function() {
                    $(element).slider( {
                        range: true,
                        min: graph[0].dataDomain()[0],
                        max: graph[0].dataDomain()[1],
                        values: [ 
                            graph[0].dataDomain()[0],
                            graph[0].dataDomain()[1]
                        ],
                        slide: function( event, ui ) {
                            //on slide, move both graphs
                            for(var i=0; i < graph.length; i++){
                                graph[i].window.xMin = ui.values[0];
                                graph[i].window.xMax = ui.values[1];
                                graph[i].update();
    
                                // if we're at an extreme, stick there
                                if (graph[i].dataDomain()[0] == ui.values[0]) {
                                    graph[i].window.xMin = undefined;
                                }
                                if (graph[i].dataDomain()[1] == ui.values[1]) {
                                    graph[i].window.xMax = undefined;
                                }
                            }
                        }
                    } );
                } );
                graph[0].onUpdate( function() {
    
                    var values = $(element).slider('option', 'values');
    
                    $(element).slider('option', 'min', graph[0].dataDomain()[0]);
                    $(element).slider('option', 'max', graph[0].dataDomain()[1]);
    
                    if (graph[0].window.xMin == undefined) {
                        values[0] = graph[0].dataDomain()[0];
                    }
                    if (graph[0].window.xMax == undefined) {
                        values[1] = graph[0].dataDomain()[1];
                    }
    
                    $(element).slider('option', 'values', values);
    
                } );
                ...
    

    Then, when declaring the graphs, I only need to add the slider code to the last graph, including both graph variables as an array:

    var slider_two = new Rickshaw.Graph.RangeSlider({
        element: document.querySelector('#slider-range'),
        graph: [graph_one, graph_two]
    });
    

    Works exactly how I wanted it to work: http://jsfiddle.net/bozdoz/k4NmL/