15

I was wondering if there is actually an out-of-the-box support for onclick event on a data point or I have to modify the library to make it works. I scanned through some parts of the source code and I didn't see anything that allows binding custom click actions. Tutorial on their site also doesn't show this option (http://code.shutterstock.com/rickshaw/).

Any help is appreciative. I'm currently evaluating between flot, rickshaw and flotr2. So far none of them satisfy all requirements and I'm very surprised the with exception of flot, there is no option for custom onClick event in other libraries. I saw that some people added some hack-ish way for flotr2, but it's very specific to bar charts only.

Yan Sklyarenko
  • 31,557
  • 24
  • 104
  • 139
juminoz
  • 3,168
  • 7
  • 35
  • 52

4 Answers4

4

This is a bit of a hack, but I had the same requirement. I already had a HoverDetail object hooked up, so I hooked into the onShow event of the HoverDetail object to store the value of the selected item's x label.

(This was in an angular app, so that's why I'm setting the variable on scope)

var hoverDetail = new Rickshaw.Graph.HoverDetail({
    onShow: function(event){
        scope.data.activeDate = $(".x_label").text();
    },
    graph: graph
});

Then, I hooked up the normal click handler to the graph, and accessed the variable stored by the onShow handler in there.

For more information on how to work with the HoverDetail object and other Rickshaw constructs have a look at this screencast: http://tagtree.tv/d3-with-rickshaw-and-angular

hendrikswan
  • 2,263
  • 1
  • 20
  • 25
  • 1
    Great suggestion. In my case the HoverDetail formatter: function was already displaying the info I needed to link, so I didn't even need an onShow: method, I just set up an onclick event for the chart that grabbed the active item text like this: `$('#chart').on('click', function() {var s = $("#chart .detail div.item.active").text(); if (s is appropriate) window.open(someFunc(s)); });` – patricksurry Jun 10 '14 at 02:53
3

I've derived this from HoverDetail, which seems to work so far:

Rickshaw.namespace('Rickshaw.Graph.ClickDetail');
Rickshaw.Graph.ClickDetail = Rickshaw.Class.create({

    initialize: function (args) {
        this.graph = args.graph;
        this.clickHandler = args.clickHandler || function(data){};
        this.lastEvent = null;
        this._addListeners();
    },

    update: function (e) {

        e = e || this.lastEvent;
        if (!e) return;
        this.lastEvent = e;

        if (!e.target.nodeName.match(/^(path|svg|rect|circle)$/)) return;

        var graph = this.graph;

        var eventX = e.offsetX || e.layerX;
        var eventY = e.offsetY || e.layerY;

        var j = 0;
        var points = [];
        var nearestPoint;
        var nearestValue;

        this.graph.series.active().forEach(function (series) {

            var data = this.graph.stackedData[j++];

            if (!data.length)
                return;

            var domainX = graph.x.invert(eventX);

            var domainIndexScale = d3.scale.linear()
                .domain([data[0].x, data.slice(-1)[0].x])
                .range([0, data.length - 1]);

            var approximateIndex = Math.round(domainIndexScale(domainX));
            if (approximateIndex == data.length - 1) approximateIndex--;

            var dataIndex = Math.min(approximateIndex || 0, data.length - 1);

            for (var i = approximateIndex; i < data.length - 1;) {

                if (!data[i] || !data[i + 1]) break;

                if (data[i].x <= domainX && data[i + 1].x > domainX) {
                    dataIndex = Math.abs(domainX - data[i].x) < Math.abs(domainX - data[i + 1].x) ? i : i + 1;
                    break;
                }

                if (data[i + 1].x <= domainX) {
                    i++
                } else {
                    i--
                }
            }

            if (dataIndex < 0) dataIndex = 0;
            var value = data[dataIndex];
            var distance = Math.sqrt(
                Math.pow(Math.abs(graph.x(value.x) - eventX), 2) +
                Math.pow(Math.abs(graph.y(value.y + value.y0) - eventY), 2)
            );

            if (!nearestPoint || distance < nearestPoint.distance) {
                nearestValue = value;
            }
        }, this);
        if(nearestValue){
            this.clickHandler(nearestValue);
        }
    },

    render: function (args) {
        // Do nothing
    },

    _addListeners: function () {
        this.graph.element.addEventListener(
            'click',
            function (e) {
                this.update(e);
            }.bind(this),
            false
        );
    }
});

Usage like this:

 new Rickshaw.Graph.ClickDetail({
            graph: graph,
            clickHandler: function(value){
                alert(value.x + ' ' + value.y);
            }
        });
Adrian
  • 2,233
  • 1
  • 22
  • 33
0

Have you tried HighCharts.js? Its a javascript library that is used to create intearctive charts and graphs.

http://www.highcharts.com/

You can customize onclick event to call a javascript function whe using HighCharts.

SRay
  • 286
  • 1
  • 5
  • The problem with one you have to pay for is that they have to be truly amazing, but after evaluating them, non of them are. It's cheaper to just pay a D3 expert to come up with something in a long term. – juminoz Nov 02 '13 at 05:50
-1
$('#chart').on('click', 'svg rect' ,function() {
        x = $(this)[0].__data__.x; //The value of x
        y = $(this)[0].__data__.y; //The value of y
        });

Tried and tested ;)