larshei

larshei

Cannot figure out why my Vega plot and JS Hook do not work

I was trying to add timeline graphs to my current application.

The application uses Surface UI 0.6.1 and LiveView 0.16.x.

Throughout the application I made use of JS Hooks every now and then, e.g. to draw or update markers on a Leaflet Map and all worked very well so far.

Now I am running into 2 problems:

  1. I cannot figure out how to add vega lite to my phoenix project. I followed the Third-party JS packages
    section from GitHub - phoenixframework/esbuild: An installer for esbuild · GitHub, as in running npm install in the assets directory. However, I cannot see any files being added anywhere, but the compiler is also not complaining on import vegaEmbed from 'vega-embed' . Where are the packages located? :thinking:
  2. It seems like my Hooks do not work, but I do not see a difference to the Hooks I used before. Here is the code, the console.log statement is not showing in the console output in Chrome (always using “empty cache and hard reload” when reloading the page):

JS

import vegaEmbed from 'vega-embed' 

const XyDiagram = {
  mounted() {
    this.handleEvent("draw", ({spec}) => {
      console.log("XY Diagram Hook")
      vegaEmbed(this.el, spec)
        .then((result) => result.view)
        .catch((error) => console.error(error))
    })
  },
}

export {XyDiagram}

EX

defmodule Components.XyDiagram do
  use Surface.LiveComponent

  require Logger

  prop data, :list, required: true
  prop height, :decimal, default: 200
  prop value_key, :atom, required: true

  @impl true
  def update(assigns, socket) do
    data =
      Enum.map(assigns.data, & %{x: &1.timestamp, y: &1[assigns.value_key]})

    spec =
      VegaLite.new(title: "Title", width: :container, height: :container, padding: 5)
      |> VegaLite.data_from_values(data)
      |> VegaLite.mark(:line)
      |> VegaLite.encode_field(:x, "x", type: :temporal)
      |> VegaLite.encode_field(:y, "y", type: :quantitative)
      |> VegaLite.to_spec()
      |> IO.inspect() # print looks good here :)

    {:ok, push_event(socket, "draw", %{"spec" => spec})}
  end

  @impl true
  def render(assigns) do
    ~H"""
    <div style={"width:100%; height: 300px"} id="graph" :hook="XyDiagram" phx-update="ignore" />
    """
  end
end

I am a bit lost and do not know what else to try or search for.

Can you spot what I am doing wrong here?

Most Liked

milangupta

milangupta

This is how I have mine set up .. if it helps you.

assets/vendor/vega_lite.js

/* import vegaEmbed from "vega-embed"; */

/**
 * A hook used to render graphics according to the given
 * Vega-Lite specification.
 *
 * The hook expects a `vega_lite:<id>:init` event with `{ spec }` payload,
 * where `spec` is the graphic definition as an object.
 *
 * Configuration:
 *
 *   * `data-id` - plot id
 * 
 * 
 * OPTIONS : FULL LIST @ https://github.com/vega/vega-embed#options
 * Eg,
 * actions:	Boolean / Object	
 * Determines if action links ("Export as PNG/SVG", "View Source", "View Vega" 
 * (only for Vega-Lite), "Open in Vega Editor") are included with the embedded view. If the value is true, 
 * all action links will be shown and none if the value is false. This property can take a key-value mapping 
 * object that maps keys (export, source, compiled, editor) to boolean values for determining if each action 
 * link should be shown. By default, export, source, and editor are true and compiled is false. These defaults 
 * can be overridden: for example, if actions is {export: false, source: true}, the embedded visualization 
 * will have two links – "View Source" and "Open in Vega Editor". The export property can take a key-value 
 * mapping object that maps keys (svg, png) to boolean values for determining if each export action 
 * link should be shown. By default, svg and png are true.
 */


const VegaLite = {
  mounted() {
    this.id = this.el.getAttribute("data-id");
    this.viewPromise = null;

    const container = document.createElement("div");
    this.el.appendChild(container);

    this.handleEvent(`vega_lite:${this.id}:init`, ({ spec }) => {
      this.viewPromise = vegaEmbed(container, spec, {"actions": false})
        .then((result) => result.view)
        .catch((error) => {
          console.error(
            `Failed to render the given Vega-Lite specification, got the following error:\n\n    ${error.message}\n\nMake sure to check for typos.`
          );
        });
    });
  },

  destroyed() {
    if (this.viewPromise) {
      this.viewPromise.then((view) => view.finalize());
    }
  },
};

export default VegaLite;

assets/js/app.js

import VegaLite from '../vendor/vega_lite';

...

Hooks.VegaLite = VegaLite;

mix.exs

      {:vega_lite, "~> 0.1.2"},

Where Next?

Popular in Questions Top

Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
WestKeys
Currently suffering from paralysis by [HTTP client] analysis. This is rather unusual in Elixirland as there tends to be consensus on the ...
New
stefanluptak
Hello everybody, usually, I use a 29" ultra-wide monitor for VSCode which can easily accomodate explorer (files panel) + file with code ...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID&lt;0.412.0&gt; terminating ** (Postgrex.Error) FATAL...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
dblack
I’ve got an issue with an app and I’ve no idea of how to troubleshoot it. I’m hoping someone here might have seen something similar. I p...
New

Other popular topics Top

axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 48475 226
New
sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
AngeloChecked
What learn first? Rust or Elixir Hi Elixir community! I’m here because i want learn a new language. I’m a junior developer and mainly i ...
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
sergio
Kind of like when jquery came out, it was super necessary. Existing drag and drop libraries have a bunch of baggage to support old browse...
New

We're in Beta

About us Mission Statement