Vue-chartjs is rendering my responsive chart too tall for my window - vue-chartjs

I created a simple responsive HTML + JS chart with chart.js which worked well. I decided to do it within Vue CLI and so have tried to switch it to vue-chartjs but the same chart always renders about 33% taller than my window and so presents vertical scrollbars (the width is fine). I recreated the problem with a sample trivial graph which I render with:
import {Line} from 'vue-chartjs'
export default {
extends: Line,
mounted () {
this.renderChart(data, options)
}
}
Note the data is trivial and the options are {}.
If I use chart.js in my Vue component, instead of vue-chartjs then it works fine. I.e. I do nothing more than delete the above code from my component and change it to the following then it renders fine, just like my sample HTML + chart.js version.
import Chart from 'chart.js'
function mount(el) {
return new Chart(
document.getElementById(el).getContext('2d'), {
type: 'line',
data: data,
options: options,
})
}
export default {
template: '<canvas id="chart"></canvas>',
mounted () {
self.chart = mount('chart')
}
}
I am using the default responsive: true and maintainAspectRatio: false of course, and have no explicit CSS or size settings anywhere.
Why can I not get the chart to render the height correctly when I use vue-chartjs? I am using vue-chartjs version 3.4.2 but have also tried a few versions back. I have looked all over the github bug tracker but seen nothing related.

UPDATE:
You should pass the options as prop or locally. But it's needed to add:
responsive: true
maintainAspectRatio: false
the desired height as well as the options as you said. Here's how it worked for me:
options:
options: {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}]
},
responsive: true,
maintainAspectRatio: false
}
In template:
<bin-graph-weight :chart-data="datacollection" :styles="myStyles" :options="datacollection.options"/>
graph-component.js:
import { Line, mixins } from 'vue-chartjs'
const { reactiveProp } = mixins
export default {
extends: Line,
mixins: [reactiveProp],
props: ['options'],
mounted () {
// this.chartData is created in the mixin.
this.renderChart(this.chartData, this.options)
},
// If you want to pass options please create a local options object
watch: {
chartData () {
this.$data._chart.update()
}
}
}

Also had problem with height overflow and responsiveness, fixed by introducing flex parent container that takes up 100% of the space. After setting responsive and ratio options (check out related chartjs doc):
options: {
// ..
responsive: true,
maintainAspectRatio: true
}
I used following css to fill 100% of the parent (where TheChart is vue-chartjs component. Basically need to make sure the chart's parent is always filling 100% of it's own parent):
vue template
<v-container class="chart-container">
<TheChart :chartdata="chartData" :options="chartOptions" />
</v-container>
scss:
.chart-container {
flex-grow: 1;
min-height: 0;
> div {
position: relative;
height: 100%;
}
}

With responsiveness the chart rerenders with promises and actually sets two times.
With a watcher in Vue.js you can rerender every time with changes in the chartData.
Chart component:
<script>
import { Bar, mixins } from 'vue-chartjs';
const { reactiveProp } = mixins;
export default {
extends: Bar,
mixins: [reactiveProp],
props: ['chartOptions'],
mounted() {
this.renderChart(this.chartData, this.chartOptions);
},
watch: {
chartData() {
this.renderChart(this.chartData, this.chartOptions);
},
},
};
</script>
Use together with dynamic styles.
Chart properties:
<template>
<div style="height:300px;">
<bar-chart :styles="myStyles" :chart-data="dataCollection"
:chart-options="chartOptions"></bar-chart>
</div>
</template>
<script>
import BarChart from './ChartBar.vue';
export default {
components: {
BarChart,
},
props: ['dataCollection'],
data() {
return {
myStyles: {
height: '300px',
width: '100%',
position: 'relative',
},
chartOptions: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
},
gridLines: {
display: true,
},
}],
xAxes: [{
ticks: {
beginAtZero: true,
},
gridLines: {
display: false,
},
}],
},
legend: {
display: true,
},
tooltips: {
enabled: true,
mode: 'single',
callbacks: {
label(tooltipItems, data) {
const { datasetIndex, index } = tooltipItems;
const value = data.datasets[datasetIndex].data[index];
if (parseInt(value, 10) > 999) {
return ` ${value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')}`;
}
return ` ${value}`;
},
},
},
responsive: true,
maintainAspectRatio: false,
height: 300,
},
};
},
};
</script>
<style lang="scss" scoped>
</style>

Related

How to always show line chart tooltip in ionic-angular.?

i am working on chart.js in ionic with angular and i am generating a chart which is line chart , i dnt want to show dots for each point and show tooltip on hover i want to show values alway without hover, i tried many ways which are mentioned on stackover flow as well but none of them working so i thought to share my code
following is my code
import { Component, OnInit, ViewChild, ElementRef } from "#angular/core";
import { Chart } from "chart.js";
#Component({
selector: 'app-bp',
templateUrl: './bp.page.html',
styleUrls: ['./bp.page.scss'],
})
export class BpPage implements OnInit {
#ViewChild("barCanvas") barCanvas: ElementRef;
private barChart: Chart;
constructor() {}
ngOnInit() {
setTimeout(() =>{
this.barChart = new Chart(this.barCanvas.nativeElement, {
type: "line",
data: {
labels: ["12-Apr", "13-Apr", "14-Apr", "15-Apr", "16-Apr", "17-Apr", "18-Apr"],
datasets: [{
label: "High",
backgroundColor: "#3e95cd",
borderColor: "#3e95cd",
pointBorderWidth: 10,
pointHoverRadius: 10,
data: [10943, 29649, 6444, 2330, 36694, 10943, 29649],
fill: false,
borderWidth: 3
}, {
label: "Low",
backgroundColor: "#ff3300",
borderColor: "#ff3300",
pointBorderWidth: 10,
pointHoverRadius: 10,
data: [9283, 1251, 6416, 2374, 9182, 9283, 1251],
fill: false,
borderWidth: 3
}]
},
options: {
scales: {
yAxes: [
{
ticks: {
beginAtZero: true
}
}
]
},
},
});
},1500);
}
}
To always show the tooltips, you must follow an approach similar to the one described here: Chart.js v2: How to make tooltips always appear on pie chart?
You have to define for your chart the showAllTooltips option as below:
let barChart = new Chart(this.barCanvas.nativeElement, {
type: "line",
//...
//...
},
options: {
showAllTooltips: true,
//...
}
});
And than you must call the code that defines the showAllTooltips behavior.
Here is a stackblitz of the working solution.
The method configureTooltipBehavior() is the one responsible for the magic.
https://stackblitz.com/edit/angular-ivy-fzpyva

Attach a custom plugin to Vue-Chart

We need to attach a custom plugin to vue-chart. Please guide us how to implement on the same
import { Line, mixins } from 'vue-chartjs'
export default {
namespaced: true,
extends: Line,
props: ['chartData', 'options'],
mounted() {
this.renderChart(this.chartData, this.chartData.options)
}
}
This is how we are using the line chart of Vue-chart. How to attach the plugin here
https://blog.larapulse.com/javascript/creating-chart-js-plugins
We want to try this. But since we are using vue-chart which internally uses chart.js. Need some help to attach the plugin. please guide us
I want to apply some background color to the chart for one specific column in the chart
vue-chart-js provide method to attach plugins. Use this way:
import the plugin
import ChartDataLabels from 'chartjs-plugin-datalabels';
then, call addPlugin in mounted
mounted() {
this.addPlugin(ChartDataLabels);
this.renderChart(
this.chartData,
this.options,
);
}
Below is PieChart.vue script in case you create pie chart :
<script>
import { Pie, mixins } from 'vue-chartjs';
import ChartDataLabels from 'chartjs-plugin-datalabels';
Chart.plugins.unregister(ChartDataLabels);
const { reactiveProp } = mixins;
export default {
extends: Pie,
mixins: [reactiveProp],
props: {
options: {
type: Object,
default: null,
},
},
mounted() {
this.addPlugin(ChartDataLabels);
this.renderChart(
this.chartData,
this.options,
);
},
};
</script>
Using the annotation plugin for Chart.js as example, you can use the addPlugin function to attach it:
import { Line, mixins } from 'vue-chartjs'
import chartjsPluginAnnotation from "chartjs-plugin-annotation"
export default {
namespaced: true,
extends: Line,
props: ['chartData', 'options'],
mounted() {
//Arguments is an Array of Plugins (https://vue-chartjs.org/api/#addplugin)
this.addPlugin([chartjsPluginAnnotation]),
this.renderChart(this.chartData, this.chartData.options)
}
}
After this just pass the plugin's options on your component as usual. In this case, if you wanted to draw a vertical line, it would be something like this:
computed: {
chart() {
return {
chartData: {
labels: this.data.labels,
datasets: [
{
label: "Score",
data: this.data.data
}
],
options: {
annotation: {
annotations: [
{
type: "line",
mode: "vertical",
scaleID: "x-axis-0",
borderColor: "#4ecca3",
value: parseInt(this.data.line),
borderDash: [4, 4],
label: {
content: this.data.line,
enabled: true,
position: "top",
xAdjust: 15,
backgroundColor: '#4ecca3',
fontSize: 10,
}
}
]
}
},
}
};
}
import chartjsPluginAnnotation from "chartjs-plugin-annotation";
And:
mounted() {
Chart.plugins.register(chartjsPluginAnnotation);
this.addPlugin(chartjsPluginAnnotation);
this.renderChart(this.chartData, this.options);
}

How do you affect the padding on the MuiCardActrions component

I am trying to target the "root" class for the MuiCardActions component with a theme custom-variables override. Here is my JSS:
overrides: {
MuiCardActions: {
root: {
display: 'flex',
justifyContent: 'flex-end',
padding: 0
},
}
},
I can see that the display 'flex' and 'flex-end' is affecting it. If I change it to 'space-between' it does affect the component, but padding has no affect.
Link to post I made on a closed issue - 9749
The override feature behaves at the JavaScript level, not the CSS level.
You have to account for the media query:
https://github.com/mui-org/material-ui/blob/33a03a06c51a0d70260a89a022d6e57e80d02629/packages/material-ui/src/CardActions/CardActions.js#L13-L16
Something like this should do it:
overrides: {
MuiCardActions: {
root: {
display: 'flex',
justifyContent: 'flex-end',
[theme.breakpoints.up(0)] : {
padding: 0,
},
},
}
},

How to properly use the chartjs datalabels plugin

I'm using Chart.js to create a bar char, I have to display the percentage on each bar, so I found the chartjs-plugin-datalabels, but I can't make it work, the documentation and the examples are not clear for me.
This is What I got:
HTML:
<canvas id="bar-chart" width="800" height="450"></canvas>
Javascript:
// Bar chart
var valuedata= [2478,5267,734,784,433];
var valuelabel=["Africa", "Asia", "Europe", "Latin America", "North America"];
var myBarChart = new Chart(document.getElementById("bar-chart"), {
type: 'bar',
data: {
labels: valuelabel,
datasets: [
{
label: "Population (millions)",
backgroundColor: ["#3e95cd", "#8e5ea2","#3cba9f","#e8c3b9","#c45850"],
data: valuedata,
}
]
},
options: {
legend: { display: false },
title: {
display: true,
text: 'Predicted world population (millions) in 2050'
},
scales: {
xAxes: [{
gridLines: {
display:false
}
}],
yAxes: [{
gridLines: {
display:false,
drawBorder: false
},
ticks: {
display: false
}
}]
},
plugins: {
datalabels: {
color: 'white',
display: function(context) {
console.log("Algo: "+context);
return context.dataset.data[context.dataIndex] > 15;
},
font: {
weight: 'bold'
},
formatter: function(value, context) {
return context.dataIndex + ': ' + Math.round(value*100) + '%';
}
}
}
}
});
myBarChart.update();
Supposedly, from what I get, the "plugin" inside option is the one that let the values to be display, but as I shown in my code above, doesn't work for me, surely I'm missing something but I don't know what, can somebody help me?
Thanks.
Fiddle:
https://jsfiddle.net/s64bq4sw/16/
It was because of the version of the Chartjs I was using, this plugin requieres 2.7.0 or later.

Chart.js is always increasing height on chart.resize()

I added chart.resize() inside of addData and removeData function, but it is always increasing height and it is never decreasing!
I am updating the chart when the user click on item of the menu. Some items have more than 100 datas e some others items have only 2 data and when have few data, the chart is always increasing height:
horizontalBar
Why is this happening?
<canvas id="chart"></canvas>
var chartData = {
labels: [<?php echo '"'.implode('","', $chart_labels ).'"' ?>],
datasets: [
{
data: [<?php echo implode(',', $chart_numbers ) ?>],
backgroundColor: '#184b8f',
hoverBackgroundColor: '#ef3e42'
}
]
};
var barOptions = {
responsive: true,
maintainAspectRatio: false,
tooltips: {
enabled: false
},
hover: {
animationDuration: 0
},
legend: {
display: false
},
scales : {
xAxes : [{
gridLines : {
display: false
},
ticks: {
beginAtZero: true,
color: '#cfcfcf'
}
} ],
yAxes : [ {
gridLines : {
display: false
},
ticks: {
fontSize: 13,
fontFamily: "'Open Sans'",
fontWeight: 600,
}
}]
},
animation: {
duration: 500,
easing: "easeOutQuart",
}
};
function removeData(chart) {
chart.data.labels.pop();
chart.data.datasets.forEach((dataset) => {
dataset.data.pop();
});
chart.resize();
chart.update();
}
function addData(chart, label, data) {
chart.data.labels.push(label);
chart.data.datasets.forEach((dataset) => {
dataset.data.push(data);
});
chart.resize();
chart.update();
}
var ctx = document.getElementById("chart").getContext("2d");
var myBar = new Chart(ctx, {
type: 'horizontalBar',
data: chartData,
options: barOptions
});
I had the same thing. You have to put an empty div around the canvas.
I've found some users had the same issue in this post: https://github.com/jtblin/angular-chart.js/issues/84
The solution for me was to change the chart's options to maintainAspectRatio: false.
myChart.setOptions({
responsive: true,
maintainAspectRatio: false
});
In laravel livewire i fixed adding wire:ignore to wrapper div
<div wire:ignore>
<div class="chart-container" style="height: 80vh; width: 80vh;">
<canvas id="bar-chart" height="800" width="1500"></canvas>
</div>
</div>
I was having the same issue in a Bulma tile.
The fix was to set
responsive: false in the Chart.js script options area.