Can't trigger beforeDraw with Vue-Chartjs (or any other plugins) - vue.js

I'm trying to add custom text to the Chartjs chart (using vue-chartjs), what I've found out so far is that I need to do this via beforeDraw (or similar) plugin. I included the plugin in the options.plugins, but it doesn't get triggered.
What am I doing wrong? Here's the code
<script>
import {Scatter} from "vue-chartjs";
export default {
extends: Scatter,
props: {
chartdata: {
type: Object,
default: null
},
options: {
type: Object,
default: null
}
},
mounted () {
this.renderChart(this.chartdata, {
scales: {
xAxes: [{
ticks: {
max: 100,
min: -100
},
type: 'linear',
}],
yAxes: [{
display: true,
type: 'linear',
ticks: {
max: 100,
min: -100
}
}]
},
elements: {
point: {
pointStyle: 'circle',
radius: 16,
backgroundColor: "#dc005a"
}
},
layout: {
padding: {
left: 25,
right: 25,
top: 25,
bottom: 25
}
},
plugins: [{
id: "AddLegend",
beforeDraw(chart) {
console.log(chart)
},
}],
});
}
}
</script>

Plugins can optionally be registered globally through Chart.plugins.register. You can register any of the hooks provided by the Plugin Core API and provide your custom code. The afterDraw hook for example would have to be registered as follows:
Chart.plugins.register({
afterDraw: chart => {
// your code
}
});

mounted () {
this.addPlugin({
id: 'my-plugin',
afterDraw: function (chart) {
var ctx = chart.ctx;
ctx.font = "bold 20px FiraGO";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText("ლიბერალური", chart.width/2, chart.height - 25);
ctx.font = "bold 20px FiraGO";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.fillText("ავტორიტარული", chart.width/2, 25);
ctx.font = "bold 20px FiraGO";
ctx.fillStyle = "red";
ctx.textAlign = "center";
ctx.rotate(Math.PI/2);
ctx.fillText("გეგმიური ეკონომიკა", chart.width/(-2), 25);
// ctx.save();
ctx.fillText("თავისუფალი ეკონომიკა", chart.width/(-2), chart.height - 25);
// ctx.save();
// ctx.rotate(Math.PI/(-2))
// ctx.save();
}
});
this.renderChart(this.chartdata, {
scales: {
xAxes: [{
ticks: {
max: 100,
min: -100
},
type: 'linear',
}],
yAxes: [{
display: true,
type: 'linear',
ticks: {
max: 100,
min: -100
}
}]
},
elements: {
point: {
pointStyle: 'circle',
radius: 16,
backgroundColor: "#dc005a"
}
},
layout: {
padding: {
left: 50,
right: 50,
top: 50,
bottom: 50
}
},
});
}

Related

Remove empty space around a barchart with no axes showing in Chartjs

Fairly straightforward, but I have a single bar on a barchart that I want to show by itself. I've hidden the axes and their ticks, but there is still all of that space there on the left and top//bottom of chart from the axes and the legend I am presuming.
Is there a way to remove this space without just putting negative margins on the element?
I've tried working with negative padding, but that doesn't work on the top and bottom of the chart.
I made a quick CodeSandbox to show my actual component
Any tips would be greatly appreciated!
Cheers!
Horizontal Stacked Bar Chart
<template>
<div style="width: 100%; height: 100%">
<canvas :id="id" width="100%" height="100%"></canvas>
</div>
</template>
<script>
import { defineComponent, onMounted } from "vue"
import Chart from "chart.js/auto"
import ChartDataLabels from "chartjs-plugin-datalabels"
export default defineComponent({
props: {
kind: {
/**
* #example: 'single', 'stacked'
*/
type: String,
default: "stacked",
},
color: {
type: String,
default: "rgba(255, 99, 132, 1)",
},
labels: {
type: Array,
default: () => ["S1", "S2", "S4", "S6"],
},
datasets: {
type: Array,
default: () => [
{
label: "va_value",
data: [80, 10, 60, 50],
backgroundColor: "#11DCB5",
borderColor: "transparent",
barThickness: 20,
minBarLength: 4,
// This is here to show SOMETHING even if the value is 0
},
{
label: "nva_value",
data: [20, 0, 40, 0],
backgroundColor: "#CA2F4B",
borderColor: "transparent",
barThickness: 20,
minBarLength: 4,
},
],
},
},
setup(props, context) {
const id = Math.random().toString()
onMounted(() => {
Chart.register(ChartDataLabels)
const ctx = document.getElementById(id)
const myChart = new Chart(ctx, {
type: "bar",
data: {
labels: props.labels,
datasets: props.datasets,
},
options: {
layout: {
padding: {
left: -20,
bottom: -20,
top: -20
}
},
plugins: {
legend: {
display: false,
},
datalabels: {
formatter: function (value) {
return props.kind === "stacked" ? `${value}s` : `${value}%`
},
color: "#fff",
anchor: "center",
align: "center",font: {
weight: "bold",
},
},
},
responsive: true,
maintainAspectRatio: false,
indexAxis: "y",
scales: {
y: {
beginAtZero: true,
stacked: true,
ticks: {
color: "#fff",
},
grid: {
drawBorder: false,
display: false,
},
},
x: {
display: props.kind === "stacked" ? true : false,
beginAtZero: true,
stacked: true,
ticks: {
color: "#fff",
},
grid: {
drawBorder: false,
display: false,
},
title: {
display: true,
text: props.kind === "stacked" ? "Step Time (s)" : "",
color: "#fff",
},
},
},
},
})
myChart
})
return { id }
},
})
</script>
<style lang=""></style>
This is because you set barThickness to 20 in your datasets. If you remove this it will show as you want:
https://codesandbox.io/s/modest-wave-60xui0

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>

chart js showing different width of bar

I am creating simple bar chart using Chartjs in Vue
<bar-chart
:data="[40, 19, 3, 5,]"
:labels="['0-30 days', '31-60 days', '61-90 days', '90+']"
:colors="['blue', 'blue', 'blue', 'blue']"
></bar-chart>
and the code for this is
createChart(chartData: object) {
const canvas = document.getElementById('bar') as HTMLCanvasElement;
const myopt = {
deferred: {
xOffset: '50%',
delay: 250,
},
plugins: {
datalabels: {
align: 'top',
anchor: 'end',
color: 'blue',
},
},
legend: {
display: true,
},
title: {
display: true,
text: 'Chart.js - Different Bar Colors',
},
tooltips: { enabled: true },
responsive: true,
hover: { mode: null },
elements: {
point: {
radius: 0,
},
},
scales: {
xAxes: [{
scaleLabel: {
display: true,
labelString: '',
},
offset: false,
color: 'rgba(0, 0, 0, 0)',
gridLines: {
drawOnChartArea: false,
},
}],
yAxes: [{
id: 'y-axis-0',
mirror: false,
stacked: true,
offset: false,
callback(label:any, index:any, labels:[]) {
return `${label}%`;
},
ticks: {
beginAtZero: true,
min: 0,
},
gridLines: {
display: true,
color: 'rgba(0, 0, 0, 0)',
drawOnChartArea: false,
},
}],
},
};
const options = {
type: 'bar',
data: chartData,
options: myopt,
};
new Chart(canvas, options);
}
the chart which this is generating is not equidistant sharing image for reference
position and width of the bar is incorrect and also I want to know if there is any way by which i can customize labels for y axis e.g. instead of 40,35,30... it will be ** 40k,35k,30k** in y axis
If any one has worked on this case please help
You can make use of the tick callback for your K at the end (https://www.chartjs.org/docs/latest/axes/labelling.html#creating-custom-tick-formats)
var ctx2 = document.getElementById("stack-chart");
var stackChart1 = new Chart(ctx2, {
type: 'bar',
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
callback: (val) => (val + 'k')
}
}]
},
legend: {
display: false,
labels: {
fontSize: 20,
fontColor: '#595d6e',
}
},
tooltips: {
enabled: false
}
},
data: {
labels: ['1', '2', '3', '4', '5'],
datasets: [{
backgroundColor: "#5e63b4",
data: [20, 30, 40, 50, 60]
}]
},
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
<canvas id="stack-chart" width="1360" height="450"></canvas>

how to keep the highligh on a bar chart?

var colors = ['url(#v-1)',
'url(#v-2)',
'url(#v-3)',
'url(#v-4)',
'url(#v-5)'];
var baseColor = '#eee';
Ext.define('Ext.chart.theme.Fancy', {
extend: 'Ext.chart.theme.Base',
constructor: function(config) {
this.callParent([Ext.apply({
axis: {
fill: baseColor,
stroke: baseColor
},
axisLabelLeft: {
fill: baseColor
},
axisLabelBottom: {
fill: baseColor
},
axisTitleLeft: {
fill: baseColor
},
axisTitleBottom: {
fill: baseColor
},
colors: colors
}, config)]);
}
});
var win = Ext.create('Ext.Panel', {
width: 1000,
height: 300,
hidden: false,
maximizable: true,
title: 'Column Chart',
renderTo: Ext.getBody(),
enableToggle: true,
pressed: true,
layout: 'fit',
items: {
id: 'chartCmp',
xtype: 'chart',
theme: 'Fancy',
animate: {
easing: 'bounceOut',
duration: 750
},
store: store,
background: {
fill: 'rgb(17, 17, 17)'
},
gradients: [
{
'id': 'v-1',
'angle': 0,
stops: {
0: {
color: 'rgb(212, 40, 40)'
},
100: {
color: 'rgb(117, 14, 14)'
}
}
},
{
'id': 'v-2',
'angle': 0,
stops: {
0: {
color: 'rgb(180, 216, 42)'
},
100: {
color: 'rgb(94, 114, 13)'
}
}
},
{
'id': 'v-3',
'angle': 0,
stops: {
0: {
color: 'rgb(43, 221, 115)'
},
100: {
color: 'rgb(14, 117, 56)'
}
}
},
{
'id': 'v-4',
'angle': 0,
stops: {
0: {
color: 'rgb(45, 117, 226)'
},
100: {
color: 'rgb(14, 56, 117)'
}
}
},
{
'id': 'v-5',
'angle': 0,
stops: {
0: {
color: 'rgb(187, 45, 222)'
},
100: {
color: 'rgb(85, 10, 103)'
}
}
}],
axes: [{
type: 'Numeric',
position: 'left',
fields: ['Quantidade'],
minimum: 0,
// maximum: 100,
label: {
renderer: Ext.util.Format.numberRenderer('0,0')
},
title: 'Numero de Processos',
grid: {
odd: {
stroke: '#555'
},
even: {
stroke: '#555'
}
}
}, {
type: 'Category',
position: 'bottom',
fields: 'Range',
title: 'Espaço temporal'
}],
series: [{
type: 'column',
axis: 'left',
highlight: true,
highlightCfg: {
fill: '#a2b5ca'
},
label: {
display: 'insideEnd',
'text-anchor': 'middle',
//Numero que aparece em cima da barra
field: 'Quantidade',
orientation: 'horizontal',
fill: '#fff',
font: '17px Arial'
},
renderer: function(sprite, storeItem, barAttr, i, store) {
barAttr.fill = colors[i % colors.length];
return barAttr;
},
style: {
opacity: 0.95
},
listeners: {
'itemmousedown': function(item) {
if(!flag) return flag;
flag = false;
var cmp = Ext.getCmp('chartCmp');
var series = cmp.series.get(0);
index = Ext.Array.indexOf(series.items, item);
selectionModel = grid.getSelectionModel();
selectedStoreItem = item.storeItem;
var as = selectedStoreItem.data.Range;
storeDadosFiltrados.proxy.extraParams.range = as;
storeDadosFiltrados.load();
}
},
xField: 'Range',
yField: ['Quantidade']
}]
},
renderTo:'grafico'
});
});
image of the chart--> http://alojaimagens.com/viewer.php?file=zz7slhsprnopuoui1mpv.jpg
I am selecting the first column, and i don't click it, just with the mouse over it. The higlight color is a variante of blue. But in the code i use itemmousedown, and i don't understand why the bar changed color only by passing by the mouse? how can i put it only highlight only in mouse click?
What about highlight: false?
If you just want the bar to be highlighted by a click, you should add a listener which highlights it on clicking the bar.