How to create a Bar chart that's capable of multiple select

Share RGraph:   Share or Like RGraph on Facebook!

Summary
A guide for creating a Bar chart that's capable of multiple select - so multiple bars can be selected and highlighted. You can use this with AJAX, for example, and also pass information about which bars are currently highlighted back to the server.

You can, relatively simply, create a Bar chart that permits the selection of bars - and which then sends that information back to the server.

This allows you to select bars on the Bar chart and have that information recorded by the server so that when the Bar chart is shown again the same bars are selected.

Optionally, you can also have the selection control something else based on the selection (also by using AJAX and communicating with your server - the possibilities are down to you).

And by using the local storage API - ie the localData variable) you can have the data persist on just the client - so no sending it back to the server with AJAX.

Here's an example chart and the code thats necessary to get the basic multiple selection up and running.

[No canvas support]
<script>
    //
    // This state variable remembers the state of the bars and whether they're selected or not
    //
    state = {
        selected: []
    };

    //
    // Create and configure the Bar chart
    //
    bar = new RGraph.Bar({
        id: 'cvs',
        data: [4,8,6,3,5,8,9],
        options: {
            backgroundGridVlines: false,
            backgroundGridBorder: false,
            noyaxis: true,
            noxaxis: true,
            labels: ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
            title: 'A Bar chart with multiple select enabled'
        }
    }).draw()
    
    //
    // The mousemove event just returns true so that the pointer is changed when it's over the bars. Note that
    // this .on() function is chained to the draw function above - I've just put it on its own line for clarity.
    //
    .on('mousemove', function (e, shape)
    {
        return true;
    })
    
    //
    // Again - this .on() function is chained to the above function - it's just seperated out for clarity.
    // It uses the index of the bar that was clicked (which is to be found in the shape object) and
    // toggles that index between true and false in the state array.
    //
    .on('click', function (e, shape)
    {
        var idx = shape.index;
    
        state.selected[idx] = !state.selected[idx];

        RGraph.redraw();

    })
    
    //
    // Again - this .on() function is chained to the above function - it's just seperated out for clarity.
    // It's a function that uses the RGraph ondraw event to draw highlighting over the relevant bars.
    //
    .on('draw', function (obj)
    {
        for (var i=0; i<obj.data.length; ++i) {
            if (state.selected[i]) {
            
                var coords = obj.coords[i];
            
                RGraph.path2(
                    obj.context,
                    'lw 3 b r % % % % f rgba(255,255,255,0.8) s #a00 lw 1',
                    coords[0],
                    coords[1],
                    coords[2],
                    coords[3]
                );
            }
        }
    });
</script>

Persisting state with the localData variable (HTML5 local storage)

The HTML5 Storage API can be used to enable persitent state. ie The selected bars are remembered across page refreshes. This doesn't communicate the information back to the server though - so the usefulness of this is limited.

If what you need the persistence for is client-side though - this will work fine.

By using the AJAX option below - you can communicate the selection back to the server.

[No canvas support]
<script>
    // Initialise the state1 variable if doesn't exist
    if (!localStorage['state1']) {
        state1 = [];
    } else {
        state1 = JSON.parse(localStorage['state1']);
    }



    bar1 = new RGraph.Bar({
        id: 'cvs1',
        data: [4,8,6,3,5,8,9],
        options: {
            backgroundGridVlines: false,
            backgroundGridBorder: false,
            noyaxis: true,
            noxaxis: true,
            labels: ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
            title: 'A Bar chart with multiple select enabled'
        }
    })
    
    // Again, the mousemove event just returns true so that the pointer is changed
    .on('mousemove', function (e, shape)
    {
        return true;
    })
    

    .on('click', function (e, shape)
    {
        var idx = shape.index;

        // Update the state2 variable with the new status
        state1[idx] = !state1[idx];
        
        // Save the state1 variable to localStorage
        localStorage['state1'] = JSON.stringify(state1);

        RGraph.redraw();
    })
    
    // Draw the highlight over the relevant bars
    .on('draw', function (obj)
    {
        for (var i=0; i<obj.data.length; ++i) {
            if (state1[i]) {

                var coords = obj.coords[i];

                RGraph.path2(
                    obj.context,
                    'lw 3 b r % % % % f rgba(255,255,255,0.8) s #a00 lw 1',
                    coords[0],
                    coords[1],
                    coords[2],
                    coords[3]
                );
            }
        }
    }).draw();
</script>
    

Persisting state with AJAX

This is a far more useful example that is very similar to the one above but with one key difference - whenever you select or unselect a bar the current state of whats highlighted is communicated back to the server via an AJAX POST request.

The RGraph.AJAX.POST() method is used to send the AJAX request.

The callback is a simple one - it just alert()s the output of the server-side script (which is an array of the state of the bars).

The code is very similar to the above example - the difference is highlighted in red.

[No canvas support]
<script>
    // Initialise the localData variable if need be
    if (!localStorage['state2']) {
        state2 = [];
    } else {
        state2 = JSON.parse(localStorage['state2']);
    }



    bar2 = new RGraph.Bar({
        id: 'cvs2',
        data: [4,8,6,3,5,8,9],
        options: {
            backgroundGridVlines: false,
            backgroundGridBorder: false,
            noyaxis: true,
            noxaxis: true,
            labels: ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'],
            title: 'A Bar chart with multiple select enabled (plus AJAX)'
        }
    }).on('mousemove', function (e, shape)
    {
        return true;
    }).on('click', function (e, shape)
    {
        var idx = shape.index;

        // Update the state variable
        state2[idx] = !state2[idx];
        
        /// Save the state to localStorage
        localStorage['state2'] = JSON.stringify(state2);
        
        // Send the state information to the server so it can be saved
        // (the question mark ensures that this very page is the one
        // that's requested. here's no need to serialise the state2
        // variable as the .POST() function does that for you. The only
        // thing that's done in the AJAX callback is the output of the
        // AJAX request is alert()ed.
        RGraph.AJAX.POST('?', {state: state2}, function (str)
        {
            alert('This is the output of the AJAX request:\n\n' + str);
        });

        RGraph.redraw();

    }).on('draw', function (obj)
    {
        for (var i=0; i<obj.data.length; ++i) {
            if (state2[i]) {

                var coords = obj.coords[i];

                RGraph.path2(
                    obj.context,
                    'lw 3 b r % % % % f rgba(255,255,255,0.8) s #a00 lw 1',
                    coords[0],
                    coords[1],
                    coords[2],
                    coords[3]
                );
            }
        }
    }).draw();
</script>
    

An SVG example with AJAX support

You can also do this whilst using an SVG Bar chart instead of a canvas one. It's a little more code though so I've created a demo page for this and you can access that here.