2

I am trying to emulate vega-lite events to trigger interactions on charts manually through javascript.

I am able to dispatch events and get them to be reconized by the listner, however the event doesn't register any items and does not trigger the visualization state to change.

Here is a codesandbox where I try to emulate a click event on the chart. You can see in the console the event registering in the event listener but not triggering the interaction. Is there a specific way to dispatch events? Is there a method similar to resluts.view.dispatch(event)?

codesandbox

1 Answers1

0

I have prepared a demo which may help you. This HTML file will create a bar chart that highlights each bar in sequence when you click the "Emulate Click" button.

enter image description here

I have created a param and referenced this in the embed code:

view.signal("TestButton_tuple"....
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Vega-Lite Click Emulation Demo</title>
  <script src="https://cdn.jsdelivr.net/npm/vega@5"></script>
  <script src="https://cdn.jsdelivr.net/npm/vega-lite@5"></script>
  <script src="https://cdn.jsdelivr.net/npm/vega-embed@6"></script>
</head>
<body>
  <button id="emulateClick">Emulate Click</button>
  <div id="chart"></div>

    <script>
    const spec = {
      $schema: "https://vega.github.io/schema/vega-lite/v5.json",
      description:
        "A bar chart with highlighting on hover and selecting on click. (Inspired by Tableau's interaction style.)",
      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 }
        ]
      },
      params: [
        {
          name: "TestButton",
          select: {
            type: "point",
            encodings: ["x"]
          }
        }
      ],
      mark: {
        type: "bar",
        fill: "#4C78A8",
        stroke: "black",
        cursor: "pointer"
      },
      encoding: {
        x: { field: "a", type: "ordinal" },
        y: { field: "b", type: "quantitative" },
        fillOpacity: {
          condition: { param: "TestButton", empty: false, value: 1 },
          value: 0.3
        },
        strokeWidth: {
          condition: [
            {
              param: "TestButton",
              empty: false,
              value: 2
            }
          ],
          value: 0
        }
      },
      config: {
        scale: {
          bandPaddingInner: 0.2
        }
      }
    };

    vegaEmbed("#chart", spec).then((result) => {
      const view = result.view;
      const labels = ["A", "B", "C", "D", "E", "F", "G", "H", "I"];
      let currentIndex = -1;

      // Set up the button click event listener
      document.getElementById("emulateClick").addEventListener("click", () => {
        // Change the internal state of the chart to simulate the click
        currentIndex = (currentIndex + 1) % labels.length;
        const selectedLabel = labels[currentIndex];
        view.signal("TestButton_tuple", {
          "unit": "layer_0",
          "fields": [
            {
              "field": "a",
              "type": "E"
            }
          ],
          "values": [
            [selectedLabel]
          ]
        }).run();
      });
    });

    </script>
</body>
</html>

Here is an alternative embed code which selects the bars based on the value ranking highest to lowest. Useful in a meeting if you wanted to highlight the highest bar and then the next highest etc:)

vegaEmbed("#chart", spec).then((result) => {
  const view = result.view;
  const sortedData = spec.data.values.slice().sort((a, b) => b.b - a.b);
  const sortedLabels = sortedData.map((d) => d.a);
  let currentIndex = -1;

  // Set up the button click event listener
  document.getElementById("emulateClick").addEventListener("click", () => {
    // Change the internal state of the chart to simulate the click
    currentIndex = (currentIndex + 1) % sortedLabels.length;
    const selectedLabel = sortedLabels[currentIndex];
    view.signal("TestButton_tuple", {
      "unit": "layer_0",
      "fields": [
        {
          "field": "a",
          "type": "E"
        }
      ],
      "values": [
        [selectedLabel]
      ]
    }).run();
  });
});

Happy charting! Adam from APB Reports

APB Reports
  • 985
  • 10