Problem with updating charts (chartjs) in vue - vuejs2

I have difficult situation with updates dynamically data on charts. I created vue component that must render analytics from axios. There are several functions (methods) which parse arrived jsons from several API.
I created draw() - method for render every charts.
draw() {
if (this.mychart) {
this.mychart.destroy();
}
const ctx = document.getElementById('main-chart');
this.mychart = new Chart(ctx,
{
type: 'line',
data: {
labels: this.labels,
datasets: this.datacollection
},
options: {
legend: {
display: true,
position: 'bottom',
},
responsive: true,
scales: {
xAxes: [{
type: "time",
display: true,
scaleLabel: {
display: false,
},
ticks: {
major: {
fontStyle: "bold",
fontColor: "#FF0000"
}
}
}],
yAxes: [
{
id: 'y1',
type: 'linear',
position: 'left',
display: false
},
{
id: 'y2',
type: 'linear',
position: 'right',
display: false
},
{
id: 'y3',
type: 'linear',
position: 'left',
display: false
},
{
id: 'y4',
type: 'linear',
position: 'right',
display: false
},
{
id: 'y5',
type: 'linear',
position: 'left',
display: false
},
{
display: false,
gridLines: {
display: false
},
scaleLabel: {
display: true,
labelString: this.labelY
},
ticks: {
min: 0, // it is for ignoring negative step.
beginAtZero: true,
stepSize: 100
}
}]
}
}
});
},
All operations for calculating (parsing) data I do in mounted hook.
Also added in mounted hook nextTick() for delay render charts before data finish parsing.
async mounted() {
await this.loadIncomings(this.clubsId),
await this.loadAvgIncomings(this.clubsId),
await this.loadAvgPayments(this.clubsId),
await this.loadAvgSchedule(this.clubsId),
await this.loadTrainings(this.clubsId)
this.$nextTick(() => {
this.draw()
})
},
Now if internet connection is fast - charts render at one time. If you refresh page - you must waiting approximately 5-20 seconds for parsing data, and after this - appear graphs.
But, if I have bad connection, some axios requests finish with errors, and appear not all charts. And also I must waiting longer for parsing.
Finally, I have situation, that when I refresh page - several seconds page is empty. If connection is bad- not all charts render.
After this I have several questions:
1)How I could start render some finished data by chartjs in first seconds?
I mean not waiting when all data will come and calculated. I would like , that my charts render step by step. I want see y-axis and x-axis after I click refresh window.
Now I am using nextTick() but it is like 2nd step, where 1st step - is parsing data (may be I don't correctly understand)
I found some answers on similar question with render dynamic data, and people offered use chart.update(). But I can't get it. Where I must input this? If you look at my component, I have special method - draw(). If input in final string in my method with parsing data like : this.draw.mychart.update() or this.mychart.update() - I receive error in browser.
For example this function:
async loadIncomings(clubsId) {
try {
for (let clubId in clubsId) {
clubId = clubsId[clubId]
let dateFrom = this.dateFrom
let dateTo = this.dateTo
let groupBy = 'month'
let potential = true
let definitely = true
await this.$store.dispatch('loadIncomings', { clubId, dateFrom, dateTo, groupBy, potential, definitely }) // here I am waiting data from store (in store I use axios)
this.draftData = this.$store.state.incomings
if (this.labels.length === 0) {
this.getDates()
}
this.flagStartDate = true
await this.getIncomings(clubId)
this.flagStartDate = false
}
this.getIncomingsTotal()
this.draw.mychart.update() // here I am trying to refresh charts like advice from forums
} catch (e) {
console.error(e)
}
},
As you can see, this.getIncomingsTotal() - is last method for parsing data. After him, I am trying to update chart. But it's doesn't work.
Analytics-test.vue?b2a7:177 TypeError: Cannot read properties of undefined (reading 'update')
at VueComponent.loadIncomings (Analytics-test.vue?b2a7:175:1)
at async VueComponent.mounted (Analytics-test.vue?b2a7:498:1)
2)Also I use vue2-datepicker. I want set range dateFrom/dateTo. But when I choose date - charts doesn't change.
I have watch() , where I can monitoring dates dateFrom() and dateTo(). And also I am trying to rechart graphs with new dates - but nothing changes.
watch: {
dateFrom() {
console.log('dateFrom changed to', this.dateFrom)
this.draw()
},
dateTo() {
console.log('dateTo changed to', this.dateTo)
this.draw()
}
},
Under I show you my component:
<template>
<div class="container">
<h3>Прибыль/посещаемость</h3>
<date-picker v-model="dateFrom" valueType="date"></date-picker>
<date-picker v-model="dateTo" valueType="date"></date-picker>
<canvas id="main-chart"></canvas>
</div>
</template>
<script>
import Chart from 'chart.js';
import DatePicker from 'vue2-datepicker';
import 'vue2-datepicker/index.css';
export default {
name: 'Analytics-test',
components: {
DatePicker
},
data: () => ({
dateFrom: new Date('2021-12-01'),
dateTo: new Date(),
flagStartDate: false,
chartData: null,
labels: [],
dataset: {},
draftData: null,
data: [],
datacollection: [],
clubsId: ['5c3c5e12ba86198828baa4a7', '5c3c5e20ba86198828baa4c5', '60353d6edbb58a135bf41856', '61e9995d4ec0f29dc8447f81', '61e999fc4ec0f29dc844835e'],
}),
methods: {
draw() {
if (this.mychart) {
this.mychart.destroy();
}
const ctx = document.getElementById('main-chart');
this.mychart = new Chart(ctx,
{
type: 'line',
data: {
labels: this.labels,
datasets: this.datacollection
},
options: {
legend: {
display: true,
position: 'bottom',
},
responsive: true,
elements: {
line: {
// tension: 0, // disables bezier curves
// bezierCurve: false
}
},
scales: {
xAxes: [{
type: "time",
display: true,
// gridLines: {
// display: false
// },
scaleLabel: {
display: false,
// labelString: 'Time'
},
ticks: {
major: {
fontStyle: "bold",
fontColor: "#FF0000"
}
}
}],
yAxes: [
{
id: 'y1',
type: 'linear',
position: 'left',
display: false
},
{
id: 'y2',
type: 'linear',
position: 'right',
display: false
},
{
id: 'y3',
type: 'linear',
position: 'left',
display: false
},
{
id: 'y4',
type: 'linear',
position: 'right',
display: false
},
{
id: 'y5',
type: 'linear',
position: 'left',
display: false
},
{
display: false,
gridLines: {
display: false
},
scaleLabel: {
display: true,
labelString: this.labelY
},
ticks: {
min: 0, // it is for ignoring negative step.
beginAtZero: true,
stepSize: 100 // if i use this it always set it '1', which look very awkward if it have high value e.g. '100'.
}
}]
}
}
});
},
// Выручка
incomingsClub(clubId) {
switch (clubId) {
case '5c3c5e12ba86198828baa4a7':
return { label: "Выручка Фрунзенской", borderColor: "#3e95cd", fill: false }
case '5c3c5e20ba86198828baa4c5':
return { label: "Выручка Чернышевской", borderColor: "#8e5ea2", fill: false };
case '60353d6edbb58a135bf41856':
return { label: "Выручка Василеостровской", borderColor: "#e8c3b9", fill: false };
case '61e9995d4ec0f29dc8447f81':
return { label: "Выручка Московской", borderColor: "#3cba9f", fill: false };
case '61e999fc4ec0f29dc844835e':
return { label: "Выручка Лесной", borderColor: "#c45850", fill: false };
case 'all':
return { label: "Выручка сети", borderColor: "#8e8786", fill: false };
default:
return 'Неизвестный клуб';
}
},
async loadIncomings(clubsId) {
try {
for (let clubId in clubsId) {
clubId = clubsId[clubId]
let dateFrom = this.dateFrom
let dateTo = this.dateTo
let groupBy = 'month'
let potential = true
let definitely = true
await this.$store.dispatch('loadIncomings', { clubId, dateFrom, dateTo, groupBy, potential, definitely })
this.draftData = this.$store.state.incomings
if (this.labels.length === 0) {
this.getDates()
}
this.flagStartDate = true
await this.getIncomings(clubId)
this.flagStartDate = false
}
this.getIncomingsTotal()
// this.draw.mychart.update()
} catch (e) {
console.error(e)
}
},
getDates() {
for (let item in this.draftData) {
if (item === 'items') {
for (let elem in this.draftData[item]) {
this.labels.push(this.draftData[item][elem].date.slice(0, 7))
}
}
}
},
bindDataDates(indexDate) {
return Array(indexDate).fill(null);
},
getIncomings(clubId) {
for (let item in this.draftData) {
if (item === 'items') {
for (let elem in this.draftData[item]) {
let positionDate = this.labels.indexOf(this.draftData[item][elem].date.slice(0, 7))
if (this.flagStartDate && positionDate > 0) {
let zerroArray = this.bindDataDates(positionDate)
this.data = this.data.concat(zerroArray)
}
this.data.push(this.draftData[item][elem].amount)
this.flagStartDate = false
}
this.dataset.data = this.data
Object.assign(this.dataset, this.incomingsClub(clubId))
Object.assign(this.dataset, { yAxisID: 'y1' })
this.datacollection.push(this.dataset)
this.data = []
this.dataset = {}
}
}
},
getIncomingsTotal() {
for (let item in this.datacollection) {
if (!this.data.length) {
this.data = this.datacollection[item].data
continue
}
const firstArr = this.data
const secondArr = this.datacollection[item].data;
this.data = []
let length;
if (firstArr.length >= secondArr.length) {
length = firstArr.length;
} else {
length = secondArr.length;
}
for (let i = 0; i < length; i++) {
const a = firstArr[i] === undefined ? 0 : firstArr[i];
const b = secondArr[i] === undefined ? 0 : secondArr[i];
this.data.push(a + b);
}
}
this.dataset.data = this.data
Object.assign(this.dataset, this.incomingsClub('all'))
Object.assign(this.dataset, { yAxisID: 'y1' })
this.datacollection.push(this.dataset)
this.data = []
this.dataset = {}
},
// Средняя сумма за жизнь
avgIncomingsClub(clubId) {
omitted..
},
getDatesAvgIncome() {
omitted..
},
async loadAvgIncomings(clubsId) {
omitted..
},
getAvgIncomings(clubId) {
omitted..
},
// Среднее кол-во оплат
avgPaymentsClub(clubId) {
omitted..
},
async loadAvgPayments(clubsId) {
omitted..
},
getAvgPayments(clubId) {
omitted..
},
// Посещаемость
avgAttendanceClub(clubId) {
omitted..
},
async loadAvgSchedule(clubsId) {
omitted..
},
getAvgAttendance(clubId) {
omitted..
},
// Тренировок
participantsCountClub(clubId) {
omitted..
},
async loadTrainings(clubsId) {
omitted..
},
async getParticipantsCount(clubId) {
omitted..
},
watch: {
dateFrom() {
console.log('dateFrom changed to', this.dateFrom)
this.draw()
},
dateTo() {
console.log('dateTo changed to', this.dateTo)
this.draw()
}
},
async mounted() {
await this.loadIncomings(this.clubsId),
await this.loadAvgIncomings(this.clubsId),
await this.loadAvgPayments(this.clubsId),
await this.loadAvgSchedule(this.clubsId),
await this.loadTrainings(this.clubsId)
this.$nextTick(() => {
this.draw()
})
},
</script>
<style>
.container form {
display: flex;
}
</style>
I skipped code in other functions because it's doesn't matter. Situation with other the same.

Related

Why chart don't update?

I am trying to integrate datepicker in my chart. But after selecting dateTo or dateFrom - nothing changes.
I have used construction this.chart.update() in watch.
I logged this.chart.update(), and I see following:
What I am doing wrong?
Why my chart don't update?
If put in watch just draw() - charts will be update, but dateTo or dateFrom - will be old (not that I select in datepicker).
<template>
<div class="container">
<h3>Прибыль/посещаемость</h3>
<date-picker v-model="dateFrom" valueType="date"></date-picker>
<date-picker v-model="dateTo" valueType="date"></date-picker>
<canvas ref="mainChart"></canvas>
</div>
</template>
<script>
import Chart from 'chart.js';
import DatePicker from 'vue2-datepicker';
import 'vue2-datepicker/index.css';
export default {
name: 'Analytics-test',
components: {
DatePicker
},
data: () => ({
dateFrom: new Date('2021-11-01'),
dateTo: new Date(),
flagStartDate: false,
chartData: null,
mychart:null,
labels: [],
dataset: {},
draftData: null,
data: [],
datacollection: [],
clubsId: ['5c3c5e12ba86198828baa4a7', '5c3c5e20ba86198828baa4c5', '60353d6edbb58a135bf41856', '61e9995d4ec0f29dc8447f81', '61e999fc4ec0f29dc844835e'],
}),
methods: {
draw() {
if (this.mychart) {
this.mychart.destroy();
}
const ctx = this.$refs.mainChart;
this.mychart = new Chart(ctx,
{
type: 'line',
data: {
labels: this.labels,
datasets: this.datacollection
},
options: {
legend: {
display: true,
position: 'bottom',
},
responsive: true,
elements: {
},
scales: {
xAxes: [{
type: "time",
display: true,
scaleLabel: {
display: false,
},
ticks: {
major: {
fontStyle: "bold",
fontColor: "#FF0000"
}
}
}],
yAxes: [
{
id: 'y1',
type: 'linear',
position: 'left',
display: false
},
{
id: 'y2',
type: 'linear',
position: 'right',
display: false
},
{
id: 'y3',
type: 'linear',
position: 'left',
display: false
},
{
id: 'y4',
type: 'linear',
position: 'right',
display: false
},
{
id: 'y5',
type: 'linear',
position: 'left',
display: false
},
{
display: false,
gridLines: {
display: false
},
scaleLabel: {
display: true,
labelString: this.labelY
},
ticks: {
min: 0,
beginAtZero: true,
stepSize: 100
}
}]
}
}
});
},
participantsCountClub(clubId) {
switch (clubId) {
case '5c3c5e12ba86198828baa4a7':
return { label: "Тренировок на Фрунзенской", borderColor: "#3e95cd", fill: false }
case '5c3c5e20ba86198828baa4c5':
return { label: "Тренировок на Чернышевской", borderColor: "#8e5ea2", fill: false };
case '60353d6edbb58a135bf41856':
return { label: "Тренировок на Василеостровской", borderColor: "#e8c3b9", fill: false };
case '61e9995d4ec0f29dc8447f81':
return { label: "Тренировок на Московской", borderColor: "#3cba9f", fill: false };
case '61e999fc4ec0f29dc844835e':
return { label: "Тренировок на Лесной", borderColor: "#c45850", fill: false };
default:
return 'Неизвестный клуб';
}
},
async loadTrainings(clubsId) {
try {
for (let clubId in clubsId) {
clubId = clubsId[clubId]
let dateFrom = this.dateFrom
let dateTo = this.dateTo
let groupBy = 'month'
await this.$store.dispatch('loadAvgSchedule', { clubId, dateFrom, dateTo, groupBy })
this.draftData = this.$store.state.avgShedule
if (this.labels.length === 0) {
this.getDatesAvgIncome()
}
this.flagStartDate = true
await this.getParticipantsCount(clubId)
this.flagStartDate = false
}
} catch (e) {
console.error(e)
}
},
async getParticipantsCount(clubId) {
for (let item in this.draftData) {
let positionDate = this.labels.indexOf(this.draftData[item].date.slice(0, 7))
if (this.flagStartDate && positionDate > 0) {
let zerroArray = await this.bindDataDates(positionDate)
this.data = this.data.concat(zerroArray)
}
this.data.push(this.draftData[item].participantsCount)
this.flagStartDate = false
}
this.dataset.data = this.data
Object.assign(this.dataset, this.participantsCountClub(clubId))
Object.assign(this.dataset, { yAxisID: 'y5', hidden: true })
this.datacollection.push(this.dataset)
this.data = []
this.dataset = {}
},
//omitted other functions..
},
watch: {
dateFrom() {
console.log('dateFrom changed to', this.dateFrom),
console.log('this.mychart', this.mychart),
this.mychart.update()
},
dateTo() {
console.log('dateTo changed to', this.dateTo)
this.mychart.update()
}
},
async mounted() {
await this.loadIncomings(this.clubsId),
await this.loadAvgIncomings(this.clubsId),
await this.loadAvgPayments(this.clubsId),
await this.loadAvgSchedule(this.clubsId),
await this.loadTrainings(this.clubsId)
this.$nextTick(() => {
this.draw()
})
},
}
</script>
<style>
.container form {
display: flex;
}
</style>
I set dateTo and dateFrom in functions(for example loadTrainings()), before it creates request to store (in store this function create axios request to API).
let dateFrom = this.dateFrom
let dateTo = this.dateTo
let groupBy = 'month'
await this.$store.dispatch('loadAvgSchedule', { clubId, dateFrom, dateTo, groupBy })

How can I call a method from options of ApexChart with vue.js

I'm new with vue and apex charts, basically what I need is to call a method from the apex chart options, I created a file showing the problem I'm having:
https://jsfiddle.net/wr3uo5va/
I need to call the method currencyValue from chartOptions.dataLabels
dataLabels: {
enabled: true,
offsetX: -25,
formatter: function(val) {
return val + " Reais"; <--- This works
// return this.currencyValue(val) <--- This does not work
},
},
Any suggestion ?
The problem is this inside the formatter callback is the chart instance (not the component instance) because it's declared as a regular function.
The solution is to use an arrow function to bind the component instance as the context:
export default {
methods: {
currencyValue(value) {⋯},
loadChartData() {
⋮
this.chartOptions = {
⋮
dataLabels: {
⋮
// ❌ don't use regular function here
//formatter: function(val) {
// return this.currencyValue(val)
//},
// ✅
formatter: (val) => {
return this.currencyValue(val)
},
},
}
}
}
}
updated fiddle
You can put chartOptions in methods instead of in data.
Below is working code
const currencyValue = (val) => {
return "R$" + val;
}
new Vue({
el: "#app",
data() {
return {
series: [450, 300, 500]
}
},
methods: {
chartOptions() {
return {
labels: ['Paid', 'Pending', 'Rejected'],
plotOptions: {
radialBar: {
size: 165,
offsetY: 30,
hollow: {
size: '20%'
},
track: {
background: "#ebebeb",
strokeWidth: '100%',
margin: 15,
},
dataLabels: {
show: true,
name: {
fontSize: '18px',
},
value: {
fontSize: '16px',
color: "#636a71",
offsetY: 11
},
total: {
show: true,
label: 'Total',
formatter: function() {
return 42459
}
}
}
},
},
responsive: [{
breakpoint: 576,
options: {
plotOptions: {
radialBar: {
size: 150,
hollow: {
size: '20%'
},
track: {
background: "#ebebeb",
strokeWidth: '100%',
margin: 15,
},
}
}
}
}],
colors: ['#7961F9', '#FF9F43', '#EA5455'],
fill: {
type: 'gradient',
gradient: {
// enabled: true,
shade: 'dark',
type: 'vertical',
shadeIntensity: 0.5,
gradientToColors: ['#9c8cfc', '#FFC085', '#f29292'],
inverseColors: false,
opacityFrom: 1,
opacityTo: 1,
stops: [0, 100]
},
},
stroke: {
lineCap: 'round'
},
chart: {
dropShadow: {
enabled: true,
blur: 3,
left: 1,
top: 1,
opacity: 0.1
},
},
tooltip: {
x: {
formatter: function (val) {
return val;
},
},
y: {
formatter: function (val) {
return currencyValue(val);
},
},
},
}
}
},
components: {
VueApexCharts
}
})
Methods can't be called in data or computed, they can be called in methods
One thing to be modified in html is below
<vue-apex-charts
type="donut"
:options="chartOptions()"
:series="series">
</vue-apex-charts>

get selected value from first chart into dynamic second chart | Apexchart dynamic charts

the issue im facing is when i end 2nd chart like 'chart.render()' , 2nd chart gets value that i selected in first chart but when i click on another value in first chart , instead of update 2nd chart div , it creats another div vertically.
here is my chart.
i'm getting value from controlle in chart.
var app = #json($newval);
var options = {
series: app,
chart: {
events: {dataPointSelection:function (event, chartContext, config) {
var value= config.w.config.series[config.dataPointIndex]
$( "#chart2" ).load(window.location.href + " #chart2" );
secondchart(value);
}
},
width: 380,
type: 'donut',
},
dataLabels: {
enabled: false
},
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 200
},
legend: {
show: false
}
}
}],
legend: {
position: 'right',
offsetY: 0,
height: 230,
}
};
var chart = new ApexCharts(document.querySelector("#chart1"), options);
chart.render();
//second chart starts...
function secondchart(value) {
//in this console.log im getting correct value
console.log(value)
var options = {
series: [{
data: [value]
}],
chart: {
type: 'bar',
height: 350
},
plotOptions: {
bar: {
borderRadius: 4,
horizontal: true,
}
},
dataLabels: {
enabled: false
},
xaxis: {
categories: ['South Korea', 'Canada', 'United Kingdom', 'Netherlands', 'Italy', 'France', 'Japan',
'United States', 'China', 'Germany'
],
}
};
chart.render()
}
</script>```
so here is code what i want do do exactly,
<script>
var app = #json($newval);
var options = {
series: app,
chart: {
events: {
dataPointSelection: function (event, chartContext, config) {
var value = config.w.config.series[config.dataPointIndex]
secondchart(value);
}
},
width: 380,
type: 'donut',
},
dataLabels: {
enabled: false
},
responsive: [{
breakpoint: 480,
options: {
chart: {
width: 200
},
legend: {
show: false
}
}
}],
legend: {
position: 'right',
offsetY: 0,
height: 230,
}
};
var chart = new ApexCharts(document.querySelector("#chart1"), options);
chart.render();
function secondchart(value) {
var cat = #json($cat);
var options = {
series: [{
data: [value,value]
}],
chart: {
redrawOnParentResize: true,
type: 'bar',
height: 350
},
plotOptions: {
bar: {
borderRadius: 4,
horizontal: true,
}
},
dataLabels: {
enabled: false
},
xaxis: {
categories: [cat
],
}
};
// $( "#chart2" ).load(window.location.href + " #chart2" );
var chart = new ApexCharts(document.querySelector("#chart2"), options);
debugger
if ($("#chart2") == null) {
console.log( $("#chart2"));
chart.render()
} else {
$("#chart2").empty();
console.log( $("#chart2"));
chart.render()
}
}
</script>

Vue-Charts label numbers to the side of a bar chart

I am using a Nuxt application with vue-charts. I have a barchart that I trying to see if there is a way to callback the numbers next to the chart. Some what like this
My barchart options look like this now.
barLostDollarChartOptions: {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
title: {
display: true,
text: 'Daily NP Opportunity Costs'
},
scales: {
yAxes: [{
//Sets the Max value after re-rendering chart
beforeFit: function (scale){
let maxValue = 0
if (scale.chart.config && scale.chart.config.data && scale.chart.config.data.datasets) {
scale.chart.config.data.datasets.forEach(dataset => {
if (dataset && dataset.data) {
dataset.data.forEach(value => {
if (value > maxValue) {
maxValue = value
}
})
}
})
}
// After, set max option !!!
scale.options.ticks.max = maxValue
},
// afterFit: function (scale){
// console.log('yAxes',scale)
// let arr = Object.values(scale.chart.config.data.datasets[0].data);
// let min = Math.min(...arr);
// let max = Math.max(...arr);
// maxValueArray.push(max)
// // console.log( `Min value: ${min}, max value: ${max}` );
//
// }
}
],
xAxes: [{
ticks:{
callback: function(value, index, values) {
if(parseInt(value) >= 1000){
// console.log(value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","))
return '$' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} else {
return '$' + value;
}
},
},
}]
}
},
But I am trying to see if there is a way that I can call back the number and render it next to the bar? any ideas?
You can use the datalabels plugin for this:
Chart.plugins.register(ChartDataLabels);
var options = {
type: 'horizontalBar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'orange'
}]
},
options: {
plugins: {
datalabels: {
anchor: 'end',
align: 'end',
formatter: (val) => ('$' + val)
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/1.0.0/chartjs-plugin-datalabels.js"></script>
</body>

Drilldown in Map with Vue.js

I'm trying to use the Drilldown in Map (vue-Highchart), but cannot get it working.
like this: https://www.highcharts.com/maps/demo/map-drilldown
Anyone have any examples of this in Vue.js? Please.
Tks.
Here is simple example of drilldown functionality(with vue-highcharts) which provides drilldown and drillup event from Vue-instance:
Vue.use(VueHighcharts, { Highcharts: Highcharts });
// helper script to load external script
let loadScript = function(url, onLoad){
var scriptTag = document.createElement('script');
scriptTag.src = url;
scriptTag.onload = onLoad;
scriptTag.onreadystatechange = onLoad;
document.body.appendChild(scriptTag);
};
// simple chart options
var options = {
chart: {},
title: {
text: 'Highcharts-Vue Map Drilldown Example'
},
subtitle: {
text: '',
floating: true,
align: 'right',
y: 50,
style: {
fontSize: '16px'
}
},
legend: {
layout: 'vertical',
align: 'right',
verticalAlign: 'middle'
},
colorAxis: {
min: 0,
minColor: '#E6E7E8',
maxColor: '#005645'
},
mapNavigation: {
enabled: true,
buttonOptions: {
verticalAlign: 'bottom'
}
},
plotOptions: {
map: {
states: {
hover: {
color: '#EEDD66'
}
}
}
},
drilldown: {
activeDataLabelStyle: {
color: '#FFFFFF',
textDecoration: 'none',
textOutline: '1px #000000'
},
drillUpButton: {
relativeTo: 'plotBox',
position: {
x: 70,
y: 280
}
}
},
series: [{
data: Highcharts.geojson(Highcharts.maps['countries/us/us-all']).map((d, i) => {
d.drilldown = true;
// set value just for example
d.value = i;
return d;
}),
name: 'USA',
dataLabels: {
enabled: true,
format: '{point.properties.postal-code}'
}
}]
};
let vm = new Vue({
el: '#app',
data: {
isLoading: false,
options: options
},
created() {
// prepare events for chart from Vue instance
this.options.chart.events = {
drilldown: this.drilldown.bind(this),
drillup: this.drillup.bind(this)
}
},
methods: {
drilldown(e) {
let { chart } = this.$refs.highcharts;
if (!e.seriesOptions) {
mapKey = 'countries/us/' + e.point.properties['hc-key'] + '-all';
if (Highcharts.maps[mapKey]) {
this.prepareDrilldownData(mapKey, e.point);
return;
}
this.isLoading = true;
loadScript('https://code.highcharts.com/mapdata/' + mapKey + '.js', () => {
this.isLoading = false;
this.prepareDrilldownData(mapKey, e.point);
});
}
chart.setTitle(null, { text: e.point.name });
},
drillup(e) {
let { chart } = this.$refs.highcharts;
chart.setTitle(null, { text: '' });
},
prepareDrilldownData(mapKey, point) {
let { chart } = this.$refs.highcharts;
data = Highcharts.geojson(Highcharts.maps[mapKey]).map((d, i) => {
// set value just for example
d.value = i;
return d;
});
chart.addSeriesAsDrilldown(point, {
name: point.name,
data: data,
dataLabels: {
enabled: true,
format: '{point.name}'
}
});
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<script src="https://code.highcharts.com/maps/highmaps.js"></script>
<script src="https://code.highcharts.com/maps/modules/drilldown.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-highcharts/dist/vue-highcharts.min.js"></script>
<script src="https://code.highcharts.com/mapdata/countries/us/us-all.js"></script>
<div id="app">
<highmaps ref="highcharts" :options="options"></highmaps>
<div v-if="isLoading" style="text-align: center; margin-top: 15px; font-size: 20px;">Loading...</div>
</div>
There is also jsfiddle if you want.