<template> <div class="p-chart"> <canvas ref="canvas" :width="width" :height="height" @click="onCanvasClick($event)" v-bind="canvasProps"></canvas> </div> </template> <script> export default { name: 'Chart', emits: ['select', 'loaded'], props: { type: String, data: null, options: null, plugins: null, width: { type: Number, default: 300 }, height: { type: Number, default: 150 }, canvasProps: { type: null, default: null } }, chart: null, watch: { /* * Use deep watch to enable triggering watch for changes within structure * otherwise the entire data object needs to be replaced to trigger watch */ data: { handler() { this.reinit(); }, deep: true }, type() { this.reinit(); }, options() { this.reinit(); } }, mounted() { this.initChart(); }, beforeUnmount() { if (this.chart) { this.chart.destroy(); this.chart = null; } }, methods: { initChart() { import('chart.js/auto').then((module) => { if (this.chart) { this.chart.destroy(); this.chart = null; } if (module && module.default) { this.chart = new module.default(this.$refs.canvas, { type: this.type, data: this.data, options: this.options, plugins: this.plugins }); } this.$emit('loaded', this.chart); }); }, getCanvas() { return this.$canvas; }, getChart() { return this.chart; }, getBase64Image() { return this.chart.toBase64Image(); }, refresh() { if (this.chart) { this.chart.update(); } }, reinit() { this.initChart(); }, onCanvasClick(event) { if (this.chart) { const element = this.chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, false); const dataset = this.chart.getElementsAtEventForMode(event, 'dataset', { intersect: true }, false); if (element && element[0] && dataset) { this.$emit('select', { originalEvent: event, element: element[0], dataset: dataset }); } } }, generateLegend() { if (this.chart) { return this.chart.generateLegend(); } } } }; </script> <style> .p-chart { position: relative; } </style>