livebook-dev / livebook

Automate code & data workflows with interactive Elixir notebooks
https://livebook.dev
Apache License 2.0
4.73k stars 410 forks source link

Handle many more types of diagrams + alternative for now #1008

Closed djcoin closed 2 years ago

djcoin commented 2 years ago

Hi, thanks for this awesome project.

I was looking into Livebook to use it as a documentation tool and was especially interested with embedding diagrams.

Unfortunately, I found out that mermaid was limited to only a few graph.

I was hoping that Livebook would provide many more types of diagram to be a great documentation tool.

This would take time and was frustrating, but then, it hits me: I could find an API to draw diagrams and execute some Elixir code to make it available from inside the livebook

So here it goes for those who are experiencing the same limit (and are impatient): https://gist.github.com/djcoin/a9ef5396d8cd018ef5f37edd0942fe05

🎉

josevalim commented 2 years ago

Correct! With the Kino API, you can render anything you want. For now we will likely stick with Mermaid, as it runs in the browser and other projects, such as GitHub, are adopting it too. thank you!

jonatanklosko commented 2 years ago

Also, you don't need to download the content in Elixir, instead you can define your own kino with JavaScript that renders a <img> tag pointing directly to the URL and let the browser handle it. Here's one way to do it:

defmodule Kino.Kroki do
  use Kino.JS

  @types ~w(
    actdiag blockdiag c4plantuml ditaa dot erd graphviz packetdiag
    nomnoml nwdiag plantuml seqdiag svgbob umlet vega vegalite  
  )a

  def new(type, graph) when type in @types do
    encoded = graph |> :zlib.compress() |> Base.url_encode64()
    url = "https://kroki.io/#{type}/svg/#{encoded}"
    Kino.JS.new(__MODULE__, url)
  end

  asset "main.js" do
    """
    export function init(ctx, url) {
      ctx.root.innerHTML = `
        <img src="${url}" alt="" />
      `;
    }
    """
  end
end

And then

Kino.Kroki.new(:graphviz, """
digraph G {Hello->World}
""")

@josevalim maybe we should add Kino.HTML for cases like this. On the other hand, for larger chunks of code it's better to define a custom Kino.JS, otherwise we send the whole HTML every time. So it could simplify some basic use cases, but advertising this way may not be the best idea :thinking:

djcoin commented 2 years ago

@jonatanklosko Using image is a nice tip, Kroki also provides a POST api (for large content I guess), this wouldn't work in this case though

@josevalim Oh, I wasn't suggesting to drop Mermaid at all. I was rather thinking that this was a nice complement to it. For those (user and developer) who are lacking some diagrams, it provides an easy way to circumvent it (and delay integration of lots of extra lib to fill the "gap" in the diagrams handling)

jonatanklosko commented 2 years ago

@djcoin oh good point, we can totally do POST! It's even better, because we don't need to compress and encode it. Here's the updated version:

defmodule Kino.Kroki do
  use Kino.JS

  @types ~w(
    actdiag blockdiag c4plantuml ditaa dot erd graphviz packetdiag
    nomnoml nwdiag plantuml seqdiag svgbob umlet vega vegalite  
  )a

  def new(type, graph) when type in @types do
    Kino.JS.new(__MODULE__, %{type: type, graph: graph})
  end

  asset "main.js" do
    """
    export function init(ctx, { type, graph }) {
      fetch(`https://kroki.io/${type}/svg`, {
        method: "POST",
        headers: {
          "content-type": "text/plain",
        },
        body: graph,
      })
      .then((resp) => resp.text())
      .then((svg) => {
        ctx.root.innerHTML = svg;
      });
    }
    """
  end
end

I will add it to jonatanklosko/kino_lab for the reference :)

djcoin commented 2 years ago

@jonatanklosko One last note as you plan to integrate it in kino_lab! I wrote this chunk of code quite quickly, the "svg" type can be specified too in the API (png etc.). Also I hope that I didn't forget any diagram type handled by Kroki (I thought I had them all until I stumbled upon packetdiag that I added). Cheers!

jonatanklosko commented 2 years ago

@djcoin great! Since we are the ones rendering the diagram, I think using SVG makes sense, especially that it's supported by all diagram types :) I think there are a couple more diagrams in the table on Korki page, I will grab those, thanks!