hubson bropa
hubson bropa

Reputation: 2770

How to make click on area above / below small column, in unstacked column chart, fire the point click event

TL;DR prone?

In order to fire a click event of column, one must click in the column. That's hard to do when the column has little or no discernible height. How can I make the area above/below a column (in an unstacked column chart) change mouse cursor to pointer and subsequent mouse click fire the point's click event?

Care for more?

I have an unstacked column chart where there is a large discrepancy in value. This results in some columns being very small, basically invisible to the user.

This proves problematic when trying to fire a click event on the small columns as from what I can tell the only way to get a click to fire the point click event is if it's within the column itself. I'm wiring the click event as

plotOptions: {
            series: {
                cursor: 'pointer',
                point: {
                    events: {
                        click: function () {
                            alert('Category: ' + this.category + ', value: ' + this.y);
                        }
                    }
                }
            }
        }

The following JSFiddle is an example of this problem (The Dec point).

I understand this limitation if columns were stacked and also know a workaround is to specify a minimum point length. However I expect, when columns are not stacked, there is a way to make clicking on any area along the vertical of chart within the x axis boundaries of the column would fire the click event.

The yellow area in image below is what I'm trying to make clickable to fire the point event for the 'Dec' column. Expected clickable area for column

Mousing over this area should change the pointer to cursor and when mouse clicked, the click event for corresponding column should be triggered.

Upvotes: 0

Views: 211

Answers (1)

hubson bropa
hubson bropa

Reputation: 2770

JSFiddle

Approach: Hook up mousemove and click events on the chart container.

In the mousemove event, get matching point based on event offset coordinates and combo of chart + point plotting. Change mouse cursor to cursor and state to hover (when appropriate).

$('#container').on('mousemove', function(event) {
    var chart = $('#container').highcharts();
    if (chart.series.length === 1) {
        $('#container').css('cursor', 'default');
        for (var seriesIdx = 0; seriesIdx < chart.series.length; seriesIdx++) {
             var series = chart.series[seriesIdx];
            for (var pointIdx = 0; pointIdx < series.data.length; pointIdx++) {
                var point = series.data[pointIdx];
                var height = chart.plotTop + point.plotY;
                var min = chart.plotLeft + point.plotX - (point.pointWidth / 2);
                var max = chart.plotLeft + point.plotX + (point.pointWidth / 2);
                var isWithin = event.offsetX >= min && event.offsetX <= max;
                if (isWithin && event.offsetY < height) {
                    $('#container').css('cursor', 'pointer');
                    point.setState('hover');
                    point.hasExtendedHover = true;
                } else {
                    if (point.hasExtendedHover) {
                        point.setState();
                        point.hasExtendedHover = false;
                    }
                }
            }
        }
    }
});

Similar for click event but break out on point found because thee is no cursor and point state cleanup needed on other points.

$('#container').on('click', function(event) {
    var chart = $('#container').highcharts();
    var found = false;
    for (var seriesIdx = 0; seriesIdx < chart.series.length; seriesIdx++) {
         var series = chart.series[seriesIdx];
        for (var pointIdx = 0; pointIdx < series.data.length; pointIdx++) {
            var point = series.data[pointIdx];
            var min = chart.plotLeft + point.plotX - (point.pointWidth / 2);
            var max = chart.plotLeft + point.plotX + (point.pointWidth / 2);
            if (event.offsetX > min && event.offsetX < max) {
                point.firePointEvent('click');
                found = true;
                break;
            }
        }
        if (found) {
            break;   
        }
    }
});

Issues:

  • I can't seem to get this to work for multiple series using categories. The plotX and plotY values of points appear to mean something different than when there is one series.
  • The mousemove event on the container does not always fire, especially on multiple series. My hypothesis is there is something stopping propagation of this event within the chart so it's not bubbling up to the container. It's sporadic so hard to know for sure what's happening.
  • If you mouse over above a column then go into the column the hover state goes away, annoying little tick that still itches after 20+ ways of scratching. IE10+ does not have this issue (wha?! +1 for IE)

Upvotes: 0

Related Questions