diff --git a/src/plugins/plugin.legend.js b/src/plugins/plugin.legend.js index 03f7fe4f21b..5f431c10c2e 100644 --- a/src/plugins/plugin.legend.js +++ b/src/plugins/plugin.legend.js @@ -233,7 +233,7 @@ export class Legend extends Element { return; } const titleHeight = me._computeTitleHeight(); - const {legendHitBoxes: hitboxes, options: {align, labels: {padding}}} = me; + const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = me; if (this.isHorizontal()) { let row = 0; let left = _alignStartEnd(align, me.left + padding, me.right - me.lineWidths[row]); @@ -246,6 +246,25 @@ export class Legend extends Element { hitbox.left = left; left += hitbox.width + padding; } + + if (rtl) { + // When the legend is in RTL mode, each row starts at the right + // To ensure that click handling works correctly, we need to ensure that the items in the + // hitboxes array line up with how the legend items are drawn (this hack is required until V4) + const boxMap = hitboxes.reduce((map, box) => { + map[box.row] = map[box.row] || []; + map[box.row].push(box); + return map; + }, {}); + + const newBoxes = []; + Object.keys(boxMap).forEach(key => { + boxMap[key].reverse(); + newBoxes.push(...boxMap[key]); + }); + + me.legendHitBoxes = newBoxes; + } } else { let col = 0; let top = _alignStartEnd(align, me.top + titleHeight + padding, me.bottom - me.columnSizes[col].height); diff --git a/test/specs/plugin.legend.tests.js b/test/specs/plugin.legend.tests.js index 2006dabe0f1..b8d1fba6d84 100644 --- a/test/specs/plugin.legend.tests.js +++ b/test/specs/plugin.legend.tests.js @@ -996,5 +996,41 @@ describe('Legend block tests', function() { await jasmine.triggerMouseEvent(chart, 'mousemove', chart.getDatasetMeta(0).data[0]); expect(leaveItem).toBe(chart.legend.legendItems[0]); }); + + it('should call onClick for the correct item when in RTL mode', async function() { + var clickItem = null; + + var chart = acquireChart({ + type: 'line', + data: { + labels: ['A', 'B', 'C', 'D'], + datasets: [{ + data: [10, 20, 30, 100], + label: 'dataset 1' + }, { + data: [10, 20, 30, 100], + label: 'dataset 2' + }] + }, + options: { + plugins: { + legend: { + onClick: function(_, item) { + clickItem = item; + }, + } + } + } + }); + + var hb = chart.legend.legendHitBoxes[0]; + var el = { + x: hb.left + (hb.width / 2), + y: hb.top + (hb.height / 2) + }; + + await jasmine.triggerMouseEvent(chart, 'click', el); + expect(clickItem).toBe(chart.legend.legendItems[0]); + }); }); });