Vue : Echart js how to export chart as image (Vuexy admin.) - vue.js

I'm attempting to export the chart as a picture. I just joined eCharts. Can someone explain how the export button operates? I need to download charts as image.
Here's what I try : Do I have something wrong?
<template>
<b-card title="Data Science">
<app-echart-bar:option-data="option"/>
</b-card>
</template>
<script>
import { BCard } from 'bootstrap-vue'
import AppEchartBar from '#core/components/charts/echart/AppEchartBar.vue'
export default {
components: {
BCard,
AppEchartBar,
},
data() {
return {
option: {
toolbox: {
show: true,
orient: 'vertical',
left: 'right',
top: 'center',
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar', 'stack'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
xAxis: [
{
type: 'category',
data: ['FB', 'IN', 'TW', 'YT',],
},
],
yAxis: [
{
type: 'value',
splitLine: { show: false },
},
],
grid: {
left: '40px',
right: '30px',
bottom: '30px',
},
series: [
{
name: 'Available',
type: 'bar',
barGap: 0,
emphasis: {
focus: 'series'
},
data: [22, 24, 20, 18]
},
{
name: 'Not Available',
type: 'bar',
barGap: 0,
emphasis: {
focus: 'series'
},
data: [12, 10, 14, 16]
},
],
},
}
},
}
</script>
Comp:
<template>
<e-charts
ref="line"
autoresize
:options="option"
theme="theme-color"
auto-resize/>
<script>
import ECharts from 'vue-echarts'
import 'echarts/lib/component/tooltip'
import 'echarts/lib/component/legend'
import 'echarts/lib/chart/bar'
import theme from './theme.json'
ECharts.registerTheme('theme-color', theme)
export default { components: {
ECharts,
}, props: {
optionData: {
type: Object,
default: null,
}, }, data() {
return {
option: {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow',
},
},
toolbox: {
show: true,
orient: 'vertical',
left: 'right',
top: 'center',
feature: {
mark: { show: true },
dataView: { show: true, readOnly: false },
magicType: { show: true, type: ['line', 'bar', 'stack'] },
restore: { show: true },
saveAsImage: { show: true }
}
},
legend: {
left: 0,
},
grid: this.optionData.grid,
xAxis: this.optionData.xAxis,
yAxis: this.optionData.yAxis,
series: this.optionData.series,
},
} }, }
</script>
The chart created by eCharts is shown below :
Can somebody assist me with adding a button or tell me whether I need to add a script to download an image.

Related

Cannot change anything in chart options

I have a bar chart and I would like to change the font color, border width and some other tings, but it doesn't work. It is in my computed property. In the chartOptions I want to change the y axis min and max value but I don't know if it is correct. Can anyone help me?
Also I want to make a horizontal line in this bar chart. It is the "Enemy's Avarage" and now it is a constant. I set the type to line and now I have a dot in my chart.
This is my chart component:
<script>
import { defineComponent } from 'vue'
import { Bar } from 'vue3-chart-v2'
export default defineComponent({
name: 'ChanceChart',
extends: Bar,
props: {
chartData: {
type: Object,
required: true
},
chartOptions: {
type: Object,
required: false,
},
},
mounted () {
this.renderChart(this.chartData, this.chartOptions)
}
})
</script>
And this is my app:
<template>
<div id="chart">
<ChanceChart :chartData="chartData" :chartOptions="chartOptions" />
</div>
</template>
<script>
import Navigation from "../components/Navigation.vue";
import ChanceChart from "../components/ChanceChart.vue";
import PageLoader from "../components/PageLoader.vue";
export default {
components: {
ChanceChart,
},
computed: {
chartOptions() {
return {
options: {
scales: {
y: {
title: {
display: true,
text: 'Value'
},
min: 0,
max: 100,
ticks: {
stepSize: 10,
}
},
},
elements: {
point: {
radius: 0
},
line: {
borderWidth: 2
}
},
plugins: {
legend: {
labels: {
boxWidth: 0,
font: {
fontColor: "#fff",
color: "#fff"
},
},
},
},
}
}
},
chartData() {
return {
datasets: [
{
type: 'bar',
label: "Enemy's Chance",
borderColor: "#1161ed",
borderWidth: 2,
data: this.emnemyCardsFilled,
},
{
type: 'bar',
label: "My Chance",
borderColor: "#f87979",
borderWidth: 2,
data: this.myCardsFilled,
},
{
type: 'line',
label: "Enemy's Avarage",
borderColor: "rgb(238, 255, 0)",
borderWidth: 2,
data: [50],
},
],
}
},
},
You need to remove the options part in the computed chartOptions prop:
chartOptions() {
return {
scales: {
y: {
title: {
display: true,
text: 'Value'
},
min: 0,
max: 100,
ticks: {
stepSize: 10,
}
},
},
elements: {
point: {
radius: 0
},
line: {
borderWidth: 2
}
},
plugins: {
legend: {
labels: {
boxWidth: 0,
font: {
fontColor: "#fff",
color: "#fff"
},
},
},
},
}
},

vue doesn't update the child chart component in echart

I have built a vue component to show a PIE chart in echart library as showed below. The PIE chart will be initialized with a default value.
pieChart.vue
<template>
<div :class="className" :style="{height:height,width:width}" />
</template>
<script>
import echarts from 'echarts'
require('echarts/theme/macarons') // echarts theme
import resize from './mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
width: {
type: String,
default: '100%'
},
height: {
type: String,
default: '300px'
},
chartData: {
type: Object,
required: true
}
},
watch: {
chartData: function(val){
console.log('chartdata handler',val);
this.setOptions(val.legend, val.data);
}
},
data() {
return {
chart: null
}
},
mounted() {
this.$nextTick(() => {
this.initChart()
})
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
this.chart = echarts.init(this.$el, 'macarons');
this.setOptions(
['group_a','group_b','group_c'],
[
{ value: 1, name: 'group_a' },
{ value: 2, name: 'group_b' },
{ value: 3, name: 'group_c' },
]
);
},
setOptions( lengend, data ) {
this.chart.setOption({
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} ({d}%)'
},
legend: {
left: 'center',
bottom: '10',
data: lengend
},
series: [
{
name: 'WEEKLY WRITE ARTICLES',
type: 'pie',
roseType: 'radius',
radius: '50%',
data: data,
animationEasing: 'cubicInOut',
animationDuration: 2600
}
]
});
}
}
}
</script>
then I use this component in a view.
<template>
<pie-chart :chartData="updateData"/>
</template>
<script>
export default {
name: 'Personalinforadm',
components: {
PieChart,
},
data() {
return {
updateData: {
data:[
{ value: 33, name: 'group_a' },
{ value: 17, name: 'group_b' },
{ value: 3, name: 'group_c' },
],
legend:['group_a','group_b','group_c']
}
}
},
created() {
this.updateData = {
data:[
{ value: 3, name: 'group_a' },
{ value: 17, name: 'group_b' },
{ value: 3, name: 'group_c' },
],
legend:['group_a','group_b','group_c']
}
}
}
</script>
however the view doesn't update the PIE chart component with the new values in created methods. why the new values doesn't pass to the PIE component and trigger the watch methods, any ideas what goes wrong with the code?
take a look at https://github.com/ecomfe/vue-echarts or solution below may help you.(if you use version >4.x)
sample.vue
<template>
//...
<v-chart
class="chart mt-7"
:option="botChartData"
:update-options="updateOpts"
/>
//...
</template>
<script>
export default {
data() {
return {
updateOpts: {
notMerge: true,
},
botChartData: {
tooltip: {
trigger: "item",
formatter: "{a} <br/>{b} : {c} ({d}%)",
},
series: [
{
name: "Active Bots",
type: "pie",
center: ["50%", "50%"],
radius: ["75%", "90%"],
itemStyle: {
borderRadius: 8,
},
data: [],
}
],
},
};
},
methods: {
connect() {
this.bots = [
{
value: 0,
name: "a",
},
{
value: 1,
name: "b",
},
{
value: 2,
name: "c",
},
];
this.botChartData.series[0].data = this.bots;
}
},
};
</script>
I called "connect" in "created" you can call it in mounted or on events!
if you need to set your chart as a child component you can easily pass this.botChartData like below
child.vue
<template>
<v-chart
class="chart mt-7"
:option="botData"
:update-options="updateConf"
/>
</template>
<script>
export default {
props: {
botChartData: {
type: Object
},
updateOpts: {
type: Object
}
},
computed: {
botData() {
return this.botChartData
},
updateConf() {
return this.updateOpts
}
}
};
</script>
in parent.vue
<template>
//...
<sample :botChartData="botChartData" :updateOpts="updateOpts" />
//...
</template>
<script>
//...the same as sample.vue js
</script>
By the way if you have multiple charts in one page dont forget notMerge then your charts will reinitialize after switching between them

Annotations are not displayed in Chart.js

I'm sorry for my poor English.
I'm trying to display a horizontal line in a graph using vue-chartjs and chartjs-plugin-annotation.
The graph appears and the options are applied, but the horizontal line does not appear because the settings in the annotation are not working.
If anyone knows how to fix this, please let me know.
The version and code is as follows
Chart.js v2.9.4
chartjs-plugin-annotation v0.5.7
Chart.js
import { Bar } from 'vue-chartjs'
import chartjsPluginAnnotation from 'chartjs-plugin-annotation'
export default {
extends: Bar,
props: ["chartData", "options"],
mounted() {
this.addPlugin(chartjsPluginAnnotation),
this.renderChart(this.chartData, this.options)
}
}
**Vue**
<template>
<Chart :chartData="chartItems" :options="chartOptions"/>
</template>
<script>
import Chart from './Chart.js'
export default {
components: {
Chart
},
data() {
return {
chartItems: {
labels: ["12月", "1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月"],
datasets: [{
label: "月ごとの数",
data: [9500, 12000, 19000, 15000, 9500, 5000, 10000, 14000, 9500, 8000, 4500, 7000],
backgroundColor: 'lightblue'
}]
},
chartOptions: {
legend: {
display: false
},
scales: {
xAxes: [{
display: true,
gridLines: {
display:false
}
}],
yAxes: [{
display: true,
id: 'y-axis-0',
position: 'right',
ticks: {
beginAtZero: true,
maxTicksLimit: 5,
userCallback: (label, index, labels) => label.toLocaleString()
},
}]
},
annotation: {
annotations: [{
type: 'line',
id: 'hLine',
mode: 'horizontal',
scaleID: 'y-axis-0',
value: 9000,
borderWidth: 2,
borderColor: 'black'
}]
},
tooltips: {
enabled: false
},
animation: {
duration: 0
}
}
}
}
}
</script>
It seems like there might be problems with the annotations library in chartjs 2.9.4, try downgrading to 2.9.3
Git issue: https://github.com/chartjs/chartjs-plugin-annotation/issues/276

Generate highcharts from v-for not populating all graphs with data

I'm working with highcharts to generate some polar graphs. https://codesandbox.io/s/vue-template-nibjp?file=/src/App.vue
The idea is that once the user presses update, a new array is pulled and it generates an n amount of charts based on that.
This is the code for the chart:
<template>
<div>
<highcharts :options="chartOptions" ref="lineCharts" :constructor-type="'chart'"></highcharts>
</div>
</template>
<script>
import {Chart} from 'highcharts-vue'
import Highcharts from "highcharts";
import HighchartsMore from "highcharts/highcharts-more";
HighchartsMore(Highcharts);
export default {
props:["options"],
components: {
highcharts: Chart
},
watch: {
options: {
handler(newOpt) {
this.chartOptions.series = newOpt.series
},
deep: true
}
},
data() {
return {
chartOptions: Highcharts.merge(this.options, {
chart: {
polar: true,
},
tooltip: {
},
title: {
text: null
},
subtitle: {
text:null
},
legend: {
enabled: false
},
credits: {
enabled: false
},
lang: {
noData: null
},
exporting: {
buttons: {
contextButton: {
theme: {
fill: "#F5F5F5"
}
}
}
},
pane: {
startAngle: -60,
size: '100%'
},
xAxis: {
tickPositions:[0,120,240],
min: 0,
max: 360,
labels: false
},
yAxis: {
max: 10,
tickInterval:2,
labels: false
},
plotOptions: {
series: {
grouping: true,
groupPadding:0,
pointPadding:0,
borderColor: '#000',
borderWidth: '0',
stacking: 'normal',
pointPlacement: 'between',
showInLegend: true
},
column: {
pointPadding: 0,
groupPadding: 0
}
},
series: [
{
data: [],
type: 'column',
name: 'On-time',
color: "#1DACE8",
pointStart: 0,
pointRange: 120
},
{
data: [],
type: 'column',
name: 'Fare',
color: "#EDCB64",
pointStart: 120,
pointRange: 120
},
{
data: [],
type: 'column',
name: 'Route Share',
color: "#F24D29",
pointStart: 240,
pointRange: 120
}
]
})
}}
}
</script>
And the code for the page:
<template>
<div id="app">
<button #click="updateChart">Update</button>
<v-item-group>
<v-container>
<v-row>
<v-col v-for="(chart, index) in chartSet" :key="index" cols="2">
<highcharts v-bind:options="chart"/>
</v-col>
</v-row>
</v-container>
</v-item-group>
</div>
</template>
<script>
import Chart from "./components/Chart";
var newSet = [
{ series: [{ data: [8] }, { data: [2] }, { data: [10] }] },
{ series: [{ data: [4] }, { data: [6] }, { data: [3] }] },
{ series: [{ data: [2] }, { data: [3] }, { data: [1] }] }
];
export default {
name: "App",
components: {
highcharts: Chart
},
data() {
return {
chartSet: [
{ series: [{ data: [] }, { data: [] }, { data: [] }] },
{ series: [{ data: [] }, { data: [] }, { data: [] }] },
{ series: [{ data: [] }, { data: [] }, { data: [] }] }
]
};
},
methods: {
updateChart() {
this.chartSet = newSet;
}
}
};
</script>
<style>
</style>
The problem I'm having is the following. If the chartSet is bigger than the newSet, and the newSet (has data for 3 charts), all works well and the charts are populated as they should.
chartSet: [
{ series: [{ data: [] }, { data: [] }, { data: [] }] },
{ series: [{ data: [] }, { data: [] }, { data: [] }] },
{ series: [{ data: [] }, { data: [] }, { data: [] }] },
{ series: [{ data: [] }, { data: [] }, { data: [] }] }
]
newSet = [
{ series: [{ data: [8] }, { data: [2] }, { data: [10] }] },
{ series: [{ data: [4] }, { data: [6] }, { data: [3] }] },
{ series: [{ data: [2] }, { data: [3] }, { data: [1] }] }
];
If the chartSet is smaller than the newSet, then only the first charts are populated.
chartSet: [
{ series: [{ data: [] }, { data: [] }, { data: [] }] }
]
newSet = [
{ series: [{ data: [8] }, { data: [2] }, { data: [10] }] },
{ series: [{ data: [4] }, { data: [6] }, { data: [3] }] },
{ series: [{ data: [2] }, { data: [3] }, { data: [1] }] }
];
The problem is that I don't know in advance how large the newSet will be as this depends on user input. So I could create a chartSet with 20 entries but then my page would be populated with empty graphs until the user presses update and that doesn't look ok. How can I start with only one graph and populate all the rest on demand?
To achieve it you have to update only series data and not the whole series object:
watch: {
options: {
handler(newOpt) {
const newChartSeries = [];
this.chartOptions.series.forEach(function(series, i) {
newChartSeries.push(Highcharts.merge(
series,
newOpt.series[i]
));
});
this.chartOptions.series = newChartSeries;
},
deep: true
}
},
created: function() {
const newChartSeries = [];
const options = this.options;
this.plotOptions.series.forEach(function(series, i) {
newChartSeries.push(Highcharts.merge(
series,
options.series[i]
));
});
this.chartOptions = Highcharts.merge(this.plotOptions, {
series: newChartSeries
});
},
data() {
return {
plotOptions: {
...
plotOptions: {
series: {
grouping: true,
groupPadding: 0,
pointPadding: 0,
borderColor: '#000',
borderWidth: '0',
stacking: 'normal',
pointPlacement: 'between',
showInLegend: true
},
column: {
pointPadding: 0,
groupPadding: 0
}
},
series: [{
data: [],
type: 'column',
name: 'On-time',
color: "#1DACE8",
pointStart: 0,
pointRange: 120
}, {
data: [],
type: 'column',
name: 'Fare',
color: "#EDCB64",
pointStart: 120,
pointRange: 120
}, {
data: [],
type: 'column',
name: 'Route Share',
color: "#F24D29",
pointStart: 240,
pointRange: 120
}]
},
chartOptions: null
}
}
Demo:
https://codesandbox.io/s/vue-template-1gyhw

Error in mounted hook: "TypeError: Cannot read property 'type' of null"

I am using echarts to draw a Heatmap
But giving me error!!
Error in mounted hook: "TypeError: Cannot read property 'type' of null"
mounted() {
this.initChart()
},
I am using the json data from here:
https://www.echartsjs.com/data/asset/data/hangzhou-tracks.json
Just took 1 data from the above link.
<template>
<div
:id="id"
:class="className"
:style="{height:height,width:width}"
/>
</template>
<script>
import echarts from 'echarts'
import resize from '../mixins/resize'
export default {
mixins: [resize],
props: {
className: {
type: String,
default: 'chart'
},
id: {
type: String,
default: 'newCustomerForecastChart'
},
width: {
type: String,
default: '200px'
},
height: {
type: String,
default: '200px'
}
},
data() {
return {
chart: null,
dataArr: [
{
"coord":
[
120.14322240845,
30.236064370321
],
"elevation": 21
},
{
"coord":
[
120.14280555506,
30.23633761213
],
"elevation": 5
}
]
}
},
mounted() {
this.initChart()
},
beforeDestroy() {
if (!this.chart) {
return
}
this.chart.dispose()
this.chart = null
},
methods: {
initChart() {
var points = [
{
"coord":
[
120.14322240845,
30.236064370321
],
"elevation": 21
},
{
"coord":
[
120.14280555506,
30.23633761213
],
"elevation": 5
}
]
this.chart = echarts.init(document.getElementById(this.id))
var colors = ['#5793f3', '#d14a61', '#675bba'];
this.chart.setOption({
animation: false,
bmap: {
center: [120.13066322374, 30.240018034923],
zoom: 14,
roam: true
},
visualMap: {
show: false,
top: 'top',
min: 0,
max: 5,
seriesIndex: 0,
calculable: true,
inRange: {
color: ['blue', 'blue', 'green', 'yellow', 'red']
}
},
series: [{
type: 'heatmap',
coordinateSystem: 'bmap',
data: points,
pointSize: 5,
blurSize: 6
}]
});
var bmap = myChart.getModel().getComponent('bmap').getBMap();
bmap.addControl(new BMap.MapTypeControl());
}
}
}
</script>
What is the problem actually?
should use
import * as echarts from 'echarts'
imstead of
import echarts from 'echarts'