Does not work like this:
<template>
<Bar
:chart-options="chartOptions"
:chart-data="$attrs['chart-data'] || chartData"
:chart-id="chartId"
:dataset-id-key="datasetIdKey"
:plugins="plugins"
:css-classes="cssClasses"
:styles="styles"
:width="width"
:height="height"
/>
</template>
<script>
import { Bar } from 'vue-chartjs/legacy'
import 'chart.js/auto'
export default {
name: 'BarChart',
components: { Bar },
props: {
chartId: {
type: String,
default: 'bar-chart',
},
datasetIdKey: {
type: String,
default: 'label',
},
width: {
type: Number,
default: 400,
},
height: {
type: Number,
default: 400,
},
cssClasses: {
default: '',
type: String,
},
styles: {
type: Object,
default: () => {},
},
plugins: {
type: Object,
default: () => {},
},
},
data() {
return {
chartData: {},
chartOptions: {
responsive: true,
title: {
display: true,
text: 'Custom Chart Title',
},
},
}
},
}
</script>
tried editing even with this: https://codesandbox.io/s/exciting-ully-2wst65?file=/src/components/Bar.vue
but nothing works.
All info gathered from: https://vue-chartjs.org/api/
Registration of components are not needed if you import auto.
maybe some ideas?
You are using v2 syntax in v3, the internal plugins like the tooltip, title, legend and decimation have been moved from the options namespace to the options.plugins namespace.
So you need to nest the title options in a plugins object within the options object. Then it will work
For those like me, who are looking for a solution using vue-chartjs V4.
To show the Title you need to pass the plugin object, for example:
plugins: {
type: Array,
default: () => [Title]
}
and then pass into the chartOptions props the title configuration, for example:
chartOptions: {
responsive: true,
maintainAspectRatio: false,
plugins: {
title: {
display: true,
text: "Chart Title",
},
},
}
sandBox full example:
Related
What I'm trying to do?
Use a Handler that allow me insert an image by URL, the reason for this is to not use too much space in the Database.
What version of Vue I'm using?
Vue 2
What is not working?
When I add the handler, quill toolbar doesn't identify my custom toolbar, and it adds all the options, the console is throwing me the next error: "[Vue warn]: Error in data(): "ReferenceError: showImageUI is not defined".
Also "this.quill.insertEmbed()" is not working, the console threw me this: "Uncaught ReferenceError: Quill is not defined" (this pass when I change the Handler Image value, I'll let the second option at the final)
<template>
<div class="addBlog">
<h1>Add New Blog</h1>
<quill-editor v-model="content" :options="editorOptions" ref="myQuillEditor"/>
</div>
</template>
<script>
import 'quill/dist/quill.snow.css';
import { Quill, quillEditor } from 'vue-quill-editor';
export default {
name: 'AddBlog',
components: {
quillEditor
},
data: () => ({
title: '',
category: '',
content: '',
editorOptions: {
theme: 'snow',
debug: 'info',
placeholder: 'Type your post...',
readOnly: true,
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['link', 'image', 'video']
],
handlers: { image: showImageUI }
}
}
},
// debug: 'info',
// placeholder: 'Type your post...',
// readOnly: true,
// theme: 'snow'
// },
delta: undefined
}),
methods: {
showImageUI() {
var range = this.quill.getSelection();
var value = prompt('please copy paste the image url here.');
if(value){
this.quill.insertEmbed(range.index, 'image', value, Quill.sources.USER);
}
}
},
watch: {
content() {
this.delta = this.$refs.myQuillEditor.quill.getContents();
}
}
};
</script>
And here I let you the code(the second option) where I used directly the function into the handler:
editorOptions: {
theme: 'snow',
debug: 'info',
placeholder: 'Type your post...',
readOnly: true,
modules: {
toolbar: {
container: [
['bold', 'italic', 'underline', 'strike'],
['link', 'image', 'video']
],
handlers: { image: function imageHandler() {
var range = this.quill.getSelection();
var value = prompt('please copy paste the image url here.');
if(value){
this.quill.insertEmbed(range.index, 'image', value, Quill.sources.USER);
}} }
}
}
},
I've added tooltips.backgroundColor in chartOptions but still doesn't work, so anyone can help me?
Here is my code
<template>
<Doughnut
:chart-options="chartOptions"
:chart-data="chartData"
:chart-id="'doughnut-chart'"
:styles="styles"
:width="width"
:height="height"
/>
</template>
<script lang="ts">
import { defineComponent, type PropType } from "vue";
import TypographyComponent from "#/core/ui/components/typography/Typography.component.vue";
import { Doughnut } from "vue-chartjs";
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
ArcElement,
CategoryScale,
type Plugin,
} from "chart.js";
ChartJS.register(Title, Tooltip, Legend, ArcElement, CategoryScale);
export default defineComponent({
name: "ProgressChartComponent",
components: { Doughnut, TypographyComponent },
props: {
width: {
type: Number,
default: 400,
},
height: {
type: Number,
default: 400,
},
styles: {
type: Object as PropType<Partial<CSSStyleDeclaration>>,
default: () => {},
},
chartData: {
type: Object,
required: false,
default: () => {},
},
},
setup() {
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
cutout: "64%",
tooltips: {
enabled: false,
backgroundColor: "#227799",
},
};
return {
chartOptions,
};
},
});
</script>
...
Guessing that you're using Chart.js v3, be aware that the tooltips are defined in the namespace options.plugins.tooltip but not options.tooltips as in your code. Therefore chartOptions needs to be changed as follows:
const chartOptions = {
responsive: true,
maintainAspectRatio: false,
cutout: "64%",
plugins: {
tooltip: {
backgroundColor: "#227799"
}
}
};
For further information, please consult Tooltip Configuration from the Chart.js documentation.
I have button which toggle data passed to this ChartComponent. If hold any seconds after toggle and retoggle so its work but if we doing it a bit fast, it is cause
Cannot read properties of null (reading 'getContext')? error.
<template>
<canvas></canvas>
</template>
<script>
import { defineComponent } from 'vue'
import Chart from 'chart.js/auto'
export default defineComponent({
name: 'ChartComponent',
props: {
type: {
type: String,
required: true,
},
data: {
type: Object,
required: true,
},
options: {
type: Object,
default: () => ({}),
},
},
data: () => ({
chart: null,
}),
watch: {
data: {
handler() {
this.chart.destroy()
this.renderChart()
},
deep: true,
},
},
mounted() {
this.renderChart()
},
methods: {
renderChart() {
this.chart = new Chart(this.$el, {
type: this.type,
data: this.data,
options: this.options,
})
},
},
})
</script>
You should unwrap/unproxy this.chart before accessing it by using Vue3 "toRaw" function:
import { toRaw } from "vue";
...
watch: {
data: {
handler() {
toRaw(this.chart).destroy()
this.renderChart()
},
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
I'm currently working on an very versatile dashboard to display various data.
For the frontend I'm using the latest nuxt and vue version.
My dashboard has many kinds of variations to display data (for example pie charts, line charts,...) these are described in components which are called dynamically.
The Problem is that when I browse from the Page "/" to another (for example "/foo") the interval gets fired again and crashes the app.
That happenes after the lifecycle hook destroyed. I tried to define the interval as an variable and stop it in the beforeDestroy hook but it did not help.
let interval= setInterval(this.fetchData.bind(null, configuration, connector), configuration.refreshTime)
/* later */
clearInterval(interval);
Do you see an error?
Thank you.
Thats the relevant code:
Template
<no-ssr>
<v-container grid-list-md>
<v-layout row wrap v-masonry transition-duration="0.5s" item-selector=".flex" column-width="#grid-sizer">
<v-flex xs1 sm1 md1 lg1 x1 id="grid-sizer"></v-flex>
<component :key="dashboardItem.id" v-for="(dashboardItem,index) in dashboardItems" :is="dashboardItem.type" :connector="dashboardItem.connector"
:type="dashboardItem.type" :configuration="dashboardItem.configuration" :id="dashboardItem.id" :index="index"></component>
</v-layout>
</v-container>
</no-ssr>
Script
import OnlyValue from '#/components/dashboardItems/OnlyValue.vue'
import TrafficLight from '#/components/dashboardItems/TrafficLight.vue'
import ChartAllHover from '#/components/dashboardItems/ChartAllHover.vue'
import PieChart from '#/components/dashboardItems/PieChart.vue'
import Section from '#/components/dashboardItems/Section.vue'
import Gauge from '#/components/dashboardItems/Gauge.vue'...
export default {
name: 'HomePage',
head () {
return {
title: "Dashboard"
}
},
computed: {
...mapGetters({
isAuthenticated: "users/isAuthentificated",
profileName: "profiles/name",
dashboardItems: "profiles/dashboardItems"
})
},
mounted() {
if (typeof this.$redrawVueMasonry === 'function') {
this.$redrawVueMasonry()
}
},
components: {
OnlyValue,
TrafficLight,
ChartAllHover,
PieChart,
Section,
Gauge
}
}
When calling a components it looks the following:
import dashboardItem from '~/mixins/dashboardItem'
export default {
name: "gauge",
mixins: [dashboardItem],
props: {
connector: {
type: String,
required: true
},
type: {
type: String,
required: true
},
configuration: {
type: Object,
required: true
},
id: {
type: Number,
required: true
},
index: {
type: Number,
required: true
}
},
data: () => ({
initOptions: {
renderer: 'svg'
},
options: {
tooltip: {
formatter: "{c}%"
},
series: [{
name: null,
type: 'gauge',
detail: {
formatter: '{value}%'
},
data: null
}]
},
isLoading: true
}),
methods: {
getData(configuration, connector) {
this.fetchData(configuration, connector)
setInterval(this.fetchData.bind(null, configuration, connector), configuration.refreshTime)
},
fetchData(configuration, connector) {
this.getSingleValue(configuration, connector)
.then(data => {
this.isLoading = false
let percent = (data.value / configuration.max) * 100
percent = Math.round(percent * 10) / 10
this.$nextTick(function () {
this.$refs.gauge.mergeOptions({
series: [{
name: data.title,
data: [{
value: percent,
name: data.title
}]
}]
})
})
this.$redrawVueMasonry()
})
.catch(e => console.log(e))
}
},
mounted () {
this.getData(this.configuration, this.connector)
}
}