[Shape click event][Active shape index] How to retrieve the index of a drawn shape, on which user clicked on, using an event?

Hi all :slightly_smiling_face:,

I need to draw rectangles using the ‘drawrect’ button on a heatmap and obtain the index of the active shape when it is clicked on.

Currently, the plotly_click event does not trigger when I click on the shape outline, and the plotly_relayout event only triggers when the shape is dragged, resized, or erased.

I have looked into the draw.js file of the plotly.js source code (draw.js) and found the function that is automatically triggered when a shape is clicked on to change its style and make it draggable, resizable, or erasable (line 189):

path.node().addEventListener('click', function() { return activateShape(gd, path); });

Therefore, I believe there should be a way to add actions to this ‘click’ event and obtain its index as well.

I have also read about some dependencies with the dragmode and clickmode attributes’ values, but I am unable to proceed with them.

A simple example is available here codepenExample or here:

HTML:

<head>
  <!-- Plotly.js -->
  <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
</head>

<body>
<div id="graph"></div>
</body>

JS

var shapes = [
  {
    editable: true,
    label: { text: "" },
    xref: "x",
    yref: "y",
    layer: "above",
    opacity: 1,
    line: { color: "white", width: 5, dash: "solid" },
    fillcolor: "rgba(0, 0, 0, 0)",
    fillrule: "evenodd",
    type: "rect",
    x0: 0.5,
    y0: 0,
    x1: 0.75,
    y1: 1.5
  }
];

var fig = {
  data: [
    {
      z: [
        [1, 20, 30],
        [20, 1, 60],
        [30, 60, 1]
      ],
      type: "heatmap"
    }
  ],
  layout: {
    title: "Heatmap with drawn rectangles",
    shapes: shapes,
    dragmode: "drawrect",
    clickmode: "event+select"
  },
  config: {
    displayModeBar: true,
    modeBarButtons: [[], ["zoom2d", "drawrect", "eraseshape", "autoScale2d"]]
  }
};

var gd = document.getElementById("graph");

Plotly.plot(gd, fig);

gd.on("plotly_click", function (d) {
  alert("plotly click");
  console.log(d);
});

gd.on("plotly_relayouting", function (d) {
  alert("plotly relayouting");
  console.log(d);
});

// gd.on("plotly_relayout", function(d) {
//   alert("plotly relayout")
//   console.log(d)
// })

// gd.on("plotly_selected", function(d) {
//   alert("plotly selected")
//   console.log(d);
// });

// gd.on("plotly_selecting", function(d) {
//   alert("plotly selecting")
//   console.log(d);
// });

Thanks a lot for your help!
YP

layer._fullLayout._activeShapeIndex

Would you mind elaborating on how to use this, @Saratoga ?

Animation

If what you want is to generate an event when a shape is selected/deselected you can change the line of code to the following in the plotly file at your risk

    path.node().addEventListener('click', function () {
      const status = activateShape(gd, path);

      if (gd._fullLayout._activeShapeIndex)
        gd.emit('plotly_selected', { activeShapeIndex: gd._fullLayout._activeShapeIndex });
      else
        gd.emit('plotly_deselect', null);

      return status
    });

And add the following lines to catch the event

        this.layer.on('plotly_selected', data => {
            console.log("select")
        })

        this.layer.on('plotly_deselect', () => {
            console.log("unselect")
        })

Animation