Loading d3 JS in webview

Hey all, I'm a backend developer and very new with Typescript/JS/Node/etc. That said, I am taking a shot at doing some d3 JS visualizations in a Joplin plugin.

My Goal: In a panel on the side of Joplin, render a small graph using d3 JS.

What I've tried:

  1. I created a new Plugin successfully with an index.s and a viz.js file.
  2. I set up some HTML from index.ts and had that display successfully.
  3. I then added my vis.js script to the panel (await panels.addScript(view, './viz.js');) and had vis.js log to the console successfully. Good so far
  4. I then added d3.js to the panel: await panels.addScript(view, './d3.v6.min.js');
  5. Now, this is where I had issues. I now want to run d3.select() inside my viz .js file

Issues

  • Trying to call the d3.select() function returns an error d3 is undefined.
  • Ok, that makes sense, I never imported it. I then tried adding import * as d3 from './d3.min.js to viz.js and got the error: Cannot use import statement outside a module
  • I next tried const d3 = require('d3') after I did npm install d3 but received the error: require is not define at viz.js:1
  • After quite a bit of searching, I found this Joplin forum thread that sounded similar so I thought that I might have to compile my viz.js script. I remove the require and import from from viz.js and added it to extraScripts in plugins.config.json. I then got the error: exports is not defined at viz.js:1

I did a lot of searching around the exports is not defined but have no clue what's going on there. Looking in the dist/ directory, the very first line of the compiles scripts contains exports.

Is there a simpler way to make d3JS available within a panel/webview for visualization? I read through most other plugins' source code but could not find example of anyone using JS libraries inside the webview vs directly from index.tx

I don't know exactly how d3 works but when you include a JS file like this in a webview, you can't use import, require or anything like this. The D3 lib most likely creates a global object which can then access from elsewhere.

So you first attempt, to directly call d3.select() is probably the right one, but maybe you need to wait for the D3 lib to finish loading. A simple test could be:

setInterval(() => {
    console.info(d3);
}, 1000);

If it works as expected, you should see initially see some "undefined" message in the console, then once it's loaded you should see the d3 object.

2 Likes

That's exactly it! Thanks for suffering my lack of JS knowledge and the quick reply. Hoping to have a beta plugin of Graph visualization for note links by the weekend.

I'm a big fan of Joplin, looking forward to contributing more to the community.

2 Likes

Could this be relevant?