Inserting multiple figures of interactive (js) content with vector.js

I am confused about the exact way to include javascript and where. There seems to be the need of creating a partial AND a custom shortcode for this.
What do I want to achieve:
Let’s say I want to write a blog post on my hugo site where there is a figure which includes this animation shown in the examples: “animation” ( Vector.js ).
What I’ve learned so far is that I should make my own shortcode. For example something like this:

{{ div id="first-interactive-figure" }}

Then I would have some self-made javascript code e.g. “my-javascript.js” which would access this div through the id and change it. If I have three of these interactive elements I would include 3 shorcodes each with a different id and write the specific code for each id in “my-javascript.js”.

My problem is that I don’t understand how to get the javascript to load. I tried it with a partial which I would activate in the frontmatter. Also, WHEN do I have to include the javascript? I understand that if I want to manipulate the divs with the javascript the divs must probably already exist for it, right? The partial is loaded in the head.

I don’t understand it really. There is a lot of moving parts in this problem and I am unsure about where to begin. Maybe I don’t know how to ask the right questions.

I would be so glad, if a more experienced person could nudge me in the right direction. How would YOU go about somehting like this: insert a small animated figure (with fixed width and height) into the blog post. What would be the requirements? Thank you for your time

Your div shortcode looks weird to me. If width is meant to be an attribute, it should like this
width="{{mul textwidth 100}}%"
provided that textwidth is defined before used in your shortcode. And height = width * 0.5 will most certainly not work as you want it to – width is the name of an HTML attribute (I suppose), not a numerical value.

In the end, it should look like something like
<div id="..." width="..." height="..."> ... </div>
On a side note: Wouldn’t it be more appropriate to put width/height settings in the CSS?

Why not use a <script> element that you add to the header of your template? I’m sure you find lots of explanations on the web how to do that.

If I were to do that (and I’m certainly not, because I hate moving images on a web page), I’d use an animated GIF.

Thank you for your answer!
The width-part was only an example. I wanted to communicate that I want the size to be set by some context. I should have just omitted it. I will change it in the original post as it is discracting from the real issue.

My problem is especially the way HOW I have to add the script in the header.
My hugo page is kind of a blog and I only want to use the library “vector.js” to write my interactive figure-elements. But I want to use them only in SOME blog posts.That means I only want to enable it sometimes. I understand that I have to use a partial for that where I can include the vector.js library. If I set the flag in the header vector.js will then be loaded in the beginning.

But then comes the next problem:
Now I have my javascrip that I write myself which uses vector.js. I understand it so that I would have my blog_post.md and somewhere else I would have the javascript for this particular blog post. Or should/could I write it directly inside the md-file?

In the hugo documentation there is mentioned that the “static” folder is for images, videos, data or (custom) javascript. So I figure there sould be a way that I could include te javascript in my blog post at some point - AFTER I insert the divs.
In my md-file it would look like this:

{{ mydivshortcode id="interactive_figure_01" }}
{{ mydivshortcode id="interactive_figure_02" }}
...

{{ here insert custom js from static folder }} 

So should I write 2 shortcodes ? One for the divs and one to insert the custom js file ?

Use something like

{{if .HasShortcode "my-animated-figure" }}
<script src="https:/.../vector.js" ></script>
<script src="my-animated-figure.js"></script>
{{end}}

in your header. Then your hand-crafted JS as well as vector.js will only be included on those pages that use the shortcode my-animated-figure.

Then in your blog posts (that is in your something.md), include the shortcode
{{ my-animated-figure ...}}

Other than that, I don’t know if I understood your questions. There’s a bit too much text for my taste and too little code. You talk about inserting divs but do not explain what the div’s have to do with your JavaScript problem.

I suggest that you google for “Hugo gallery” - that might give you some ideas how to solve your problem: many people want to have galleries only on some of their pages, so they have to include the JS code from them only on those pages. And they use a div as a container for the pictures and so on…

1 Like

layouts/_default/baseof.html

<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0">
  <title>{{ .Title }}</title>
  {{ if .HasShortcode "vectorjs" }}
    <link rel="stylesheet" href="https://vectorjs.org/library.css">
  {{ end }}
</head>

layouts/shortcodes/vectorjs.html

{{ .Inner }}

Markdown - Option 1

{{< vectorjs >}}
<div id="animate-along-path" class="vertical-center i-container"></div>
<script type="module" src="https://vectorjs.org/examples/interaction/animate-along-path.js"></script>
{{< /vectorjs >}}

Markdown - Option 2

<div id="foo" class="vertical-center i-container"></div>
<script type="module">
import { Interactive } from 'https://vectorjs.org/index.js';
let interactive = new Interactive('foo');
interactive.width = 736;
interactive.height = 225;
interactive.border = true;
let circle = interactive.circle(interactive.width / 2, interactive.height / 3, 50);
circle.classList.add('default');
let displayCircle = interactive.circle(0, 0, 6);
displayCircle.style.fill = '#333333';
let scrubber = interactive.scrubber(100, 175, {});
let pathLength = circle.getTotalLength();
function animate() {
    let currentPosition = scrubber.value / (scrubber.max - scrubber.min);
    let point = circle.getPointAtLength(currentPosition * pathLength);
    displayCircle.cx = point.x;
    displayCircle.cy = point.y;
    requestAnimationFrame(animate);
}
requestAnimationFrame(animate);
</script>