]> git.ipfire.org Git - thirdparty/Chart.js.git/commitdiff
Ensure correct item is clicked when a horizontal legend is in RTL mode (#9340)
authorEvert Timberg <evert.timberg+github@gmail.com>
Thu, 1 Jul 2021 18:14:05 +0000 (14:14 -0400)
committerGitHub <noreply@github.com>
Thu, 1 Jul 2021 18:14:05 +0000 (14:14 -0400)
src/plugins/plugin.legend.js
test/specs/plugin.legend.tests.js

index 03f7fe4f21bd8f14be6ddbb86e815f2260b54139..5f431c10c2eefa02654fbda817ca89ba26f6a87a 100644 (file)
@@ -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);
index 2006dabe0f13e400b319787da3796c7dfaa8af43..b8d1fba6d84407caab4fc06c932b4bf7b522eec2 100644 (file)
@@ -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]);
+    });
   });
 });