What's the proper way to implement a custom click handler in vega-lite
Asked Answered
G

2

6

I don't seem to be able to figure this out by reading the docs. Is there a way to implement a onClick event handler for any of my marks?

Gwendagwendolen answered 29/8, 2019 at 9:47 Comment(0)
C
5

Since Vega-Lite does not yet have support for signals, you could patch the generated Vega. You can add a signal to the compiled Vega spec and then add a signal listener through the Vega view API. You can patch the generated Vega with the patch option in Vega-Embed.

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-lite@3"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-embed@4"></script>
</head>

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

  <script>
    const spec = {
      "$schema": "https://vega.github.io/schema/vega-lite/v3.json",
      "data": {
        "values": [
          {"a": "A", "b": 28},
          {"a": "B", "b": 55},
          {"a": "C", "b": 43},
          {"a": "D", "b": 91},
          {"a": "E", "b": 81},
          {"a": "F", "b": 53},
          {"a": "G", "b": 19},
          {"a": "H", "b": 87},
          {"a": "I", "b": 52}
        ]
      },
      "mark": "bar",
      "encoding": {
        "x": {"field": "a", "type": "ordinal"},
        "y": {"field": "b", "type": "quantitative"}
      }
    };
    vegaEmbed('#vis', spec, {
      patch: (spec) => {
        spec.signals.push({
            "name": "barClick",
            "value": 0,
            "on": [{"events": "rect:mousedown", "update": "barClick + 1"}]
        })
        return spec;
      }
    }).then(result => {
        result.view.addSignalListener('barClick', console.log);
    }).catch(console.warn);
  </script>
</body>
Chappelka answered 30/8, 2019 at 17:59 Comment(2)
To expand on this, the addSignalListener callback can be a function of the event name AND the underlying value. By replacing "barClick +1" with "datum" as the value to go with the update key, I was able to access the datum that was clicked on programatically. See codepen.io/stephenshank/pen/XWJpPxo.Dart
+dominik When I compiled my cljs code with this, I am getting Error: Unrecognized signal name: "barClick" when I try to render the chart.Leake
S
6

I had a hard time with vega-lite to get the patch to recognize the objects I wanted click events for. So instead, I just added a generic eventListener

vegaEmbed('#vis', spec, {}
).then(result => {
    result.view.addEventListener('click', function(event, item) {
       console.log('CLICK', event, item);
    });
}).catch(console.warn);

The item object contains the datum. If there is no datum, you know the click was not on a useful location.

https://vega.github.io/vega/docs/api/view/#view_addEventListener

Swaine answered 13/5, 2020 at 18:41 Comment(0)
C
5

Since Vega-Lite does not yet have support for signals, you could patch the generated Vega. You can add a signal to the compiled Vega spec and then add a signal listener through the Vega view API. You can patch the generated Vega with the patch option in Vega-Embed.

<!DOCTYPE html>
<head>
  <meta charset="utf-8">
  <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-lite@3"></script>
    <script src="https://cdn.jsdelivr.net/npm/vega-embed@4"></script>
</head>

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

  <script>
    const spec = {
      "$schema": "https://vega.github.io/schema/vega-lite/v3.json",
      "data": {
        "values": [
          {"a": "A", "b": 28},
          {"a": "B", "b": 55},
          {"a": "C", "b": 43},
          {"a": "D", "b": 91},
          {"a": "E", "b": 81},
          {"a": "F", "b": 53},
          {"a": "G", "b": 19},
          {"a": "H", "b": 87},
          {"a": "I", "b": 52}
        ]
      },
      "mark": "bar",
      "encoding": {
        "x": {"field": "a", "type": "ordinal"},
        "y": {"field": "b", "type": "quantitative"}
      }
    };
    vegaEmbed('#vis', spec, {
      patch: (spec) => {
        spec.signals.push({
            "name": "barClick",
            "value": 0,
            "on": [{"events": "rect:mousedown", "update": "barClick + 1"}]
        })
        return spec;
      }
    }).then(result => {
        result.view.addSignalListener('barClick', console.log);
    }).catch(console.warn);
  </script>
</body>
Chappelka answered 30/8, 2019 at 17:59 Comment(2)
To expand on this, the addSignalListener callback can be a function of the event name AND the underlying value. By replacing "barClick +1" with "datum" as the value to go with the update key, I was able to access the datum that was clicked on programatically. See codepen.io/stephenshank/pen/XWJpPxo.Dart
+dominik When I compiled my cljs code with this, I am getting Error: Unrecognized signal name: "barClick" when I try to render the chart.Leake

© 2022 - 2024 — McMap. All rights reserved.