Using VantaJS (3rd party js library) with dash

I have a rather simple page to try to integrate VantaJS into my dash app but am having some issues that I think are due to delayed rendering timing.

My app is the following (with ./assets/custom.js containing the required code to trigger the visual):

import datetime
import dash_defer_js_import as dji
import dash
import dash_bootstrap_components as dbc
import numpy as np


import plotly.express as px
from dash import dash_table
from dash import dcc
from dash import html as html
app = dash.Dash(__name__,
                external_stylesheets=[dbc.themes.BOOTSTRAP, 'https://fonts.googleapis.com/css?family=Poppins',
                                      dbc.themes.MINTY],
                external_scripts=['https://cdnjs.cloudflare.com/ajax/libs/three.js/r121/three.min.js',
                                  'https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.cells.min.js'])

# app = dash.Dash(__name__, external_stylesheets=['https://fonts.googleapis.com/css?family=Poppins'])

app.layout = html.Div(style={'font-family': 'Poppins'}, children=[

    html.Canvas(id='foo', style={'width': '500px', 'height': '500px'}),

]
                      )

if __name__ == '__main__':
    app.run_server(debug=True, host='0.0.0.0')

But within the inspect of the browser console I get: [VANTA] Cannot find element #foo

Similarly, if move custom to the parent level of the app (in the same location as my app.py) and add:
dji.Import('./custom.js')

I do not receive the error but I also do no not see the visual.

Any help would be greatly appreciated.

I have been able to create a simple html page locally and that page is able to display the vanta animation without issue.

Here’s an approach using a clientside callback based on an answer in a different thread from @RenaudLN. Because the callback is triggered once the layout has been rendered, you can use it to defer execution of JS until Dash has finished loading.

Note that when I first implemented this the use of html.Canvas was giving me some problems. Changing it to html.Div helped.

# app.py
import dash
import dash_bootstrap_components as dbc
from dash import ClientsideFunction, Input, Output, html

app = dash.Dash(
    __name__,
    external_stylesheets=[
        "https://fonts.googleapis.com/css?family=Poppins",
        dbc.themes.MINTY,
    ],
    external_scripts=[
        "https://cdnjs.cloudflare.com/ajax/libs/three.js/r121/three.min.js",
        "https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.cells.min.js",
    ],
)

app.layout = html.Div(
    children=[
        html.Div(
            dbc.Container(
                html.H1(
                    "Demo Dash app with Vanta.JS", style={"color": "#ff3d3d"}
                ),
                className="py-5",
            ),
            id="vanta-container",
            style={"height": "100vh", "width": "100vw"},
        ),
    ],
)

app.clientside_callback(
    ClientsideFunction(namespace="clientside", function_name="attach_vanta"),
    Output("vanta-container", "id"),
    [Input("vanta-container", "id")],
)

if __name__ == "__main__":
    app.run_server(debug=True)

and in assets/

// assets/custom.js
if (!window.dash_clientside) {
  window.dash_clientside = {};
}
window.dash_clientside.clientside = {
  attach_vanta: function (id) {
    setTimeout(function () {
      var el = document.getElementById(id);
      VANTA.CELLS({ el });
    }, 1);
    return window.dash_clientside.no_update;
  },
};
2 Likes

Thanks will try

Couldn’t get it to work with above solution