I'm trying to incorporate a Vis Timeline in my Vue app. I've used the Custom styling example as a starting point (because I will in future work on the styling). I've adapted it in my Vue app like this (cutting the css code for now):
<template>
<span id="visualization">
</span>
</template>
<script>
import { Timeline } from "vis-timeline/peer";
import "vis-timeline/styles/vis-timeline-graph2d.css";
export default {
name: 'VisTimelineChronik',
data() {
return {
itemset: [
{start: new Date(2010,7,23), content: '<div>Conversation</div><img src="'+require("@/assets/fullscreen.svg")+'" style="width:32px; height:32px;">'},
{start: new Date(2010,7,23,23,0,0), content: '<div>Mail from boss</div><img src="'+require("@/assets/fullscreen.svg")+'" style="width:32px; height:32px;">'},
{start: new Date(2010,7,24,16,0,0), content: 'Report'},
{start: new Date(2010,7,26), end: new Date(2010,8,2), content: 'Traject A'},
{start: new Date(2010,7,28), content: '<div>Memo</div><img src="'+require("@/assets/fullscreen.svg")+'" style="width:48px; height:48px;">'},
{start: new Date(2010,7,29), content: '<div>Phone call</div><img src="'+require("@/assets/fullscreen.svg")+'" style="width:32px; height:32px;">'},
{start: new Date(2010,7,31), end: new Date(2010,8,3), content: 'Traject B'},
{start: new Date(2010,8,4,12,0,0), content: '<div>Report</div><img src="'+require("@/assets/fullscreen.svg")+'" style="width:32px; height:32px;">'}
],
options: {
editable: false,
margin: {
item: 20,
axis: 40,
}
}
}
},
mounted() {
const container = document.getElementById("visualization");
const timeline = new Timeline(container, this.itemset, this.options);
}
}
</script>
I replaced the images sources with an asset of my vue app, so they can be displayed. This works, but the items get misplaced:
I'm running the Vue development server (via vue serve
) and interestingly the misplacement vanishes, when I change the code and the dev server automatically loads the new code. But when I reload the site in the browser the items are misplaced again.
I can select the misplaced items and drag them up, which moves the item up in a better position (no longer overlapping other items or the axis). The timeline will also increase its vertical size in this case if necessary.
Note: In the image the timeline is rather small, but that is only for the image. The timeline can resize itself in vertical direction and I originally had it about twice the size in horizontal direction. Still the same.
Why does this misplacement happen and how can I prevent it?
Used versions:
+-- @vue/cli-plugin-babel@5.0.8
+-- @vue/cli-plugin-router@5.0.8
+-- @vue/cli-plugin-vuex@5.0.8
+-- @vue/cli-service@5.0.8
+-- vue-router@4.1.5
+-- vue-select@4.0.0-beta.5
+-- vue@3.2.39
`-- vuex@4.0.2
+-- vis-timeline@7.7.2
The problem occurs when the icon has finished loading after the timeline has been drawn. Here is what happens:
itemset
is passed to Timelinecontent
property, including the img
which src has not been loadedimg
)src
has finally loaded and blamo, items are much larger and you get the overlapWhen the site does a hot-reload after you change sources, the image is loaded in cache, so there is no load time and Timeline can calculate the width correctly, so there is no overlap now.
From what I can see, there are two ways you can solve it:
timeline.redraw()
and timeline.fit()
to recalculate the dimension of the items and then adjust the dimension of the timelineThe first option means that you have to work with the onload event, and I am pretty sure that you don't want to go down that route, so I am going to skip the details (let me know if you do want to use it).
The second option is probably the cleaner solution, as you want to limit image dimensions anyway. You just have to add a CSS rule like:
.vis-item-content img{
width: 80px;
height: 80px;
}
Now the items have a fixed size and position is calculated correctly.
Here is a playground where you can see how different loading mechanisms and dimensions change the behavior.