How to include external javascript library in a custom Lovelace card?

I’m trying to make a custom Lovelace card that implements the plot.ly javascript library. I need to somehow include the plotly.js file. I have tried adding it as a resource in home assistant, and I’ve tried to include it in the beginning of the custom Lovelace card code, but these both have errors. I looked at the code for the Apex Charts lovelace card, and it looks like the entirety of the apexcharts.js file has just been included in the apex charts lovelace card js file, along with the bits for lovelace. So I tried doing the same and including all the code of the plotly.js file in my custom lovelace card, but it didn’t get me anywhere. I just get “Custom element doesn’t exist” as soon as I add the plotly.js code into my custom lovelace card.

The code in the Apex Charts lovelace card is all minified and I’m not sure where the apexcharts.js code ends and the lovelace custom card js starts, so I may be doing it wrong when I am trying to follow the example of that custom card.

Does anyone have any pointers for me?
Thanks so much!

Here are the full sources: GitHub - apexcharts/apexcharts.js: 📊 Interactive JavaScript Charts built on SVG

EDIT: My mistake, that was apexchart itself. The card is at GitHub - RomRider/apexcharts-card: 📈 A Lovelace card to display advanced graphs and charts based on ApexChartsJS for Home Assistant

Thanks for your response. Yup, I’ve looked through that RomRider/apexcharts-card github repository. But like I said, I am new to node and don’t understand at all how the code in the RomRider/apexcharts-card repository relates to (or gets made into) the minified release.

That is, if I were to make a card the same way RomRider did, I don’t understand where I would put an external js library. I don’t even see a reference to the apexcharts.js code in the RomRider/apexcharts-card code.

As far as my (very limited) experience in that field goes, you include the dependency in “package.json” and the needed code is automagically included in the minified package.

See, e.g., for apexchat: apexcharts-card/package.json at 76e5ba6e027aec7f4221764fc7d2ce38fa88cc57 · RomRider/apexcharts-card · GitHub

If you are not familiar with bundling and you don’t need to make your dashboard available w/o internet, you can do:

import "https://cdn.plot.ly/plotly-2.4.2.min.js";

Or: you can use this plotly card instead :slight_smile:

I made this plotly graphs card with some bells and whistles. It follows your HA color theme, updates the data on real time, allows you to go beyond to the past by scrolling, and some more features… It should generally just do what you’d expect. I hope it fits your needs

this works:

resources:
  - url: "https://example.com/test.css"
    type: css
  - url: "https://example.com/test.js"
    type: js

I would think a more proper implementation to prevent name collisions on functions and such would like this below. This is what I do with flex-table-card:

  1. Modify core javascript with one line:
import * as plugin from "./flex-table-card-plugins.js";

This will import a separate JS file into a class named “plugin”. The file can be located in the same directory as “flex-table-card.js” (or not) and in this case named “flex-table-card-plugins.js”. Of course you can change that name if you like. You can also change the classname “plugin”.

  1. Put your function(s) in this file which will be imported. You add the keyword “export” in front of the function so that it is exported and available within the core JS. Example:
export function drawscore(place, score){
    var cellstring = '';
    if (place == 1 || place == '1T') {
      cellstring = '<div style="font-weight:bold; color: black">' + score + ' ' + '<span style="font-size:14px">' + place + '</span></div>'}
    else if (place == 2 || place == 3 || place == '2T' || place == '3T') {
      cellstring = '<div style="font-weight:normal; color:black;">' + score + ' ' + '<span style="font-size:14px;font-weight:bold;color:black">' + place + '</span></div>'}
    else {
      cellstring = '<div style="font-weight:normal; color: #888;">' + score + ' ' + '<span style="font-size:14px">' + place + '</span></div>'}
    return cellstring;
}
  1. Use them! They are in the namespace “plugin” referred to on the “import” line. To use one you would call it by adding the namespace in front of the function name. So the example above could be called many times, different data like this:
        - name: Vault
          data: '[[attribute]]'
          modify: |
            plugin.drawscore(x.EventPlace1, x.EventScore1)
        - name: Bars
          data: '[[attribute]]'
          modify: |
            plugin.drawscore(x.EventPlace2, x.EventScore2)
        - name: Beam
          data: '[[attribute]]'
          modify: |
            plugin.drawscore(x.EventPlace3, x.EventScore3)
        - name: Floor
          data: '[[attribute]]'
          modify: |
            plugin.drawscore(x.EventPlace4, x.EventScore4)
        - name: AA
          data: '[[attribute]]'
          modify: |
            plugin.drawscore(x.AAPlace, x.AAScore)

This way (using import/export your functions are isolated only to the including core card JS and not the entirety. They are in a namespace that further isolates them even from the core functions that may exist in the core card JS.