Reputation: 242
I'm drawing a bar chart with vega-lite in a Vue.js SPA. The encoding section of the main data layer looks like this:
encoding: {
x: {field: 'word', type: 'ordinal', sort: '-count'},
y: {field: 'count', type: 'quantitative'},
tooltip: [{field: 'word'}, {field: 'count'}, {field: 'doc_count'}]
}
… and in the Vue component method that updates the chart, I have this:
vegaEmbed('#vis', spec)
.then(({_spec, view}) => {
view.addEventListener('click', function (event, item) {
if (item) {
vueComponent.onWordClicked(item.datum.word);
}
})
})
… which, to complete all of that, calls this:
onWordClicked(word) {
this.$router.push({path: 'words', params: {word: word}});
}
All of this works exactly as I expect: you hover over a bar, a tooltip is displayed, you click the bar, and you are navigated to a different route in the SPA.
BUT… the tooltip stays on screen, unless and until you navigate back to the chart page and hover over the bars, in which case the tooltip can be reinvoked and then dismissed when you mouse out.
Any ideas on how to make the tooltip go away when the Vue path changes? I've tried playing around with the view.tooltip(...)
method, but suspect that's overkill (I'm happy with the default tooltip) and may not even solve my problem.
Thanks.
Upvotes: 0
Views: 224
Reputation: 1075
So, when the route changes the component that triggered the tooltip is replaced by a different component. Your component's beforeDestroy
and destroyed
methods will be called and you can hook into this and clean up anything that should be cleaned up.
destroyed() {
// close the any open vega views. (dont know the specific of vega-embed)
}
If a components cleans up all it's side effects on destroy you can call this a well-behaved component. Side effects can be timeouts and intervals that have been set, popups and dialogs that have been opened and what not. If you want to be able to clean up you need to save the handles so you can close them later on. I'll demonstrate a well-behaved clock component:
Vue.component("clock", {
template: `
<div>{{time}}</div>
`,
data() {
return {
time: null
}
},
mounted() {
// save the handle this.interval so we can clear it later on.
this.interval = setInterval(() => {
var d = new Date;
this.time = d.getHours() + ':' + d.getMinutes() + ':' + d.getSeconds()
}, 750);
},
destroyed() {
clearInterval(this.interval);
}
});
Upvotes: 1