Chart.js Radial chart with arrow using Vue.js - vue.js

Hello everyone I am a newbie in using chart.js package, is there a way I can create is king of chart?

Yes, it is possible.
There might be already a plugin, that can achieve this (but I don't know any, but I didn't really look), so you could look for one,
Or you could simply write your own plugin, with a few lines of code
Here a demo, how I would do this, with an inline plugin:
(three charts with 3 different percentages)
var arrowPlugin = {
id: 'arrowPlugin',
afterDraw: (chart, args, options) => {
const { ctx } = chart;
let midX = chart.width / 2;
let midY = chart.height;
let arrowLength = chart.height / 2;
let text = `${options.value * 100}%`;
let textSize = ctx.measureText(text);
ctx.save();
ctx.save();
ctx.translate(midX, midY);
ctx.rotate( (Math.PI * options.value) - Math.PI /2);
ctx.strokeStyle = options.arrowColor;
ctx.fillStyle = options.arrowColor;
ctx.lineCap = 'butt';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(0, - arrowLength * 3 / 4 + 3)
ctx.lineTo(0, - arrowLength * 6 / 4);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, - arrowLength * 6 / 4 - 4)
ctx.lineTo(5, - arrowLength * 6 / 4 + 10)
ctx.lineTo(-5, - arrowLength * 6 / 4 + 10)
ctx.closePath();
ctx.fill()
ctx.fillStyle = options.triangleColor;
ctx.beginPath();
ctx.moveTo(0, -midY + 25)
ctx.lineTo(-10, -midY + 10)
ctx.lineTo(10, -midY + 10)
ctx.closePath()
ctx.fill();
ctx.restore();
ctx.fillStyle = options.textColor;
ctx.font = "50px Arial";
ctx.fillText(text, midX - textSize.width * 1.5, midY - 25);
ctx.restore();
},
defaults: {
// set here the percentage
value:.50,
arrowColor: 'black',
textColor: 'black',
triangleColor: 'black'
}
}
var options1 = {
type: 'doughnut',
data: {
datasets: [{
data: [20, 50, 30],
backgroundColor: [
'rgba(231, 76, 60, 1)',
'rgba(255, 164, 46, 1)',
'rgba(46, 204, 113, 1)'
],
borderColor: [
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)'
],
borderWidth: 0
}]},
options: {
cutout: 33,
rotation: -90,
circumference: 180,
maintainAspectRatio: false,
legend: { display: false },
plugins:{
tooltip: { enabled: false },
}
},
plugins:[arrowPlugin]
}
var options2 = {
type: 'doughnut',
data: {
datasets: [{
data: [20, 50, 30],
backgroundColor: [
'rgba(231, 76, 60, 1)',
'rgba(255, 164, 46, 1)',
'rgba(46, 204, 113, 1)'
],
borderColor: [
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)'
],
borderWidth: 0
}]},
options: {
cutout: 33,
rotation: -90,
circumference: 180,
maintainAspectRatio: false,
legend: { display: false },
plugins:{
tooltip: { enabled: false },
// override default percentage
arrowPlugin: { value: .20 }
}
},
plugins:[arrowPlugin]
}
var options3 = {
type: 'doughnut',
data: {
datasets: [{
data: [20, 50, 30],
backgroundColor: [
'rgba(231, 76, 60, 1)',
'rgba(255, 164, 46, 1)',
'rgba(46, 204, 113, 1)'
],
borderColor: [
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)',
'rgba(255, 255, 255 ,1)'
],
borderWidth: 0
}]},
options: {
cutout: 33,
rotation: -90,
circumference: 180,
maintainAspectRatio: false,
legend: { display: false },
plugins:{
tooltip: { enabled: false },
// override default percentage
arrowPlugin: { value: .70 }
}
},
plugins:[arrowPlugin]
}
const chart1 = document.getElementById('chart1')
new Chart(chart1, options1);
const chart2 = document.getElementById('chart2')
new Chart(chart2, options2);
const chart3 = document.getElementById('chart3')
new Chart(chart3, options3);
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<div style="width:500px;height:184px">
<canvas id="chart1" width="500" height="184"></canvas>
<canvas id="chart2" width="500" height="184"></canvas>
<canvas id="chart3" width="500" height="184"></canvas>
<div>
the percentage is currently set in the inline plugin-options, default value is set to .5 = 50% (valid range 0 - 1 = 0% - 100%).

Related

I set double YAxis but it doesn't follow the directions(left,right) and datasets

I wanna set double yAxis, so I wrote down the code like below
const data = {
labels: ['a', 'b', 'c', 'd', 'e'],
datasets: [
{
type: 'bar',
label: this.$t('numberOfBuilding'),
data: [100, 20, 30, 5, 5],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(255, 159, 64, 0.2)',
'rgba(255, 205, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(54, 162, 235, 0.2)'
],
borderColor: ['rgb(255, 99, 132)', 'rgb(255, 159, 64)', 'rgb(255, 205, 86)', 'rgb(75, 192, 192)', 'rgb(54, 162, 235)'],
borderWidth: 1,
yAxisId: 'y'
},
// {
// type: 'line',
// fill: true,
// label: this.$t('output') + '(' + this.$t('criteriaMonth') + ')',
// data: [200, 500, 600, 800, 1000],
// borderColor: 'rgba(255, 201, 14, 1)',
// backgroundColor: 'rgba(255, 201, 14, 0.5)',
// lineTension: 0.2,
// yAxisId: 'y1'
// },
{
type: 'line',
fill: true,
label: this.$t('output') + '(' + this.$t('sum') + ')',
data: [300, 100, 700, 249, 588],
borderColor: 'rgba(55, 201, 14, 1)',
backgroundColor: 'rgba(55, 201, 14, 0.5)',
lineTension: 0.2,
yAxisId: 'y1'
}
]
}
const config = {
type: 'scatter',
data: data,
options: {
scales: {
y: {
beginAtZero: true,
position: 'left'
},
y1: {
position: 'right',
grid: {
drawOnChartArea: false
}
}
}
}
}
but it doesn't work properly
yAxis which id is 'y1' is at left and datasets[0] which has 'y' as yAxisId presents with 'y1' axis
it seems like yAxisId doesn't connect well with their own datasets
See the below pictures
[result of above code]
(https://i.stack.imgur.com/0moGR.png)
but my another code is work well I don't know what different it is
here's my another code which works well
const data = {
labels: [
1 + this.$t('month'),
2 + this.$t('month'),
3 + this.$t('month'),
4 + this.$t('month'),
5 + this.$t('month'),
6 + this.$t('month'),
7 + this.$t('month'),
8 + this.$t('month'),
9 + this.$t('month'),
10 + this.$t('month'),
11 + this.$t('month'),
12 + this.$t('month')
],
datasets: [
{
type: 'bar',
label: this.$t('totalConsumption') + '(' + this.unit + ')',
data: this.consumptionData,
borderColor: 'rgb(255, 99, 132)',
backgroundColor: 'rgba(255, 99, 132, 0.2)',
yAxisID: 'y'
},
{
type: 'line',
label: this.$t('temperatureAVG') + '(℃)',
data: this.temperatureData,
fill: false,
borderColor: 'rgb(54, 162, 235)',
yAxisID: 'y1'
}
]
}
const config = {
type: 'scatter',
data: data,
options: {
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true,
position: 'left'
},
y1: {
position: 'right',
grid: {
drawOnChartArea: false
}
}
}
}
}
In the first code, the option name is wrong. You are using yAxisId but the correct one is yAxisID (as in the second sample), id must be uppercase

ECharts unkown series undefined

I am trying to use echarts bar https://echarts.apache.org/examples/en/editor.html?c=bar-label-rotation&lang=ts for displaying data . The problem I have is when trying to add four different bars to a chart I get error: [ECharts] Unkown series undefined. It works fine when there is only one bar. Here is my code:
this.chartOptions = {
grid: {
top: 20,
bottom: 90,
right: 5,
left: 60
},
legend: {
data: [
'Positive Capacity'
'Negative Capacity'
'Positive Energy'
'Negative Energy'
]
},
tooltip: {
trigger: 'axis',
formatter: (val) => `
<div>${format.formatTime('dd.MM.yyyy hh:mm', val[0].data[0])}</div>
<div>${val[0].marker}<span style="float:right"> ${val[0].data[1]} kW</span></div>
`
},
xAxis: {
type: 'time',
name: this.chartTranslations.xAxis,
nameLocation: 'middle',
nameGap: 80,
axisLabel: {
rotate: 45,
formatter: (val) => format.formatTime('dd.MM.yy hh:mm', val)
}
},
yAxis: {
type: 'value',
name: this.chartTranslations.yAxis,
nameLocation: 'middle',
nameGap: 50,
scale: true,
boundaryGap: ['2%', '2%'],
axisLabel : {
formatter: (val) => this.isMegaWatts ? (val/1000 + ' MW') : (val + ' kW')
},
},
series: [
{
name: 'Positive Capacity'
type: 'bar',
barGap: 10,
emphasis: {
focus: 'series'
},
itemStyle: {
color: new graphic.LinearGradient(0, 0, 0, 2.5, [
{
offset: 0,
color: 'rgba(45, 159, 195, 1)'
},
{
offset: 1,
color: 'rgba(255, 255, 255, 0)'
}
])
},
data: this.positiveCapacity
},
{
name: 'Negative Capacity',
type: 'bar',
barGap: 10,
emphasis: {
focus: 'series'
},
itemStyle: {
color: new graphic.LinearGradient(5, 5, 0, 2.5, [
{
offset: 0,
color: 'rgba(45, 159, 195, 1)'
},
{
offset: 1,
color: 'rgba(255, 255, 255, 0)'
}
])
},
data: this.negativeCapacity
},
{
name: 'Positive Energy',
type: 'bar',
barGap: 10,
emphasis: {
focus: 'series'
},
itemStyle: {
color: new graphic.LinearGradient(10, 10, 0, 2.5, [
{
offset: 0,
color: 'rgba(45, 159, 195, 1)'
},
{
offset: 1,
color: 'rgba(255, 255, 255, 0)'
}
])
},
data: this.positiveEnergy
},
{
name: 'Positive Capacity',
type: 'bar',
barGap: 10,
emphasis: {
focus: 'series'
},
itemStyle: {
color: new graphic.LinearGradient(20, 20, 0, 2.5, [
{
offset: 0,
color: 'rgba(45, 159, 195, 1)'
},
{
offset: 1,
color: 'rgba(255, 255, 255, 0)'
}
])
},
data: this.negativeEnergy
}
]
};
Then later setting content with: Echarts.setOption(this.chartOptions);
Thanks for any help or insight.

How to show small values in a chart.js pie chart

I am having trouble displaying small values in my chart.js chart. My issue is very similar to a question asked here:
How to show small values in Flot Pie chart
Does anyone know if there is a workaround in chart.js?
You can use chartjs-plugin-datalabels and define a dataset with same data but weight: 0 for displaying small values outside of the chart.
{
data: data,
weight: 0,
borderWidth: 20,
datalabels: {
formatter: v => v < 5 ? v : ''
}
}
Then also add a datalabels.formatter to the original dataset and make sure, it returns an empty string for small values.
datalabels: {
textAlign: 'center',
formatter: v => v < 5 ? '' : v
}
Please take a look at the runnable code below and see how it works.
const data = [48, 56, 3, 1, 44];
Chart.register(ChartDataLabels);
new Chart('myChart', {
type: 'pie',
data: {
labels: ['red', 'blue', 'green', 'purple', 'gray'],
datasets: [{
data: data,
weight: 0,
borderWidth: 20,
datalabels: {
formatter: v => v < 5 ? v : ''
}
},
{
label: 'My Dataset',
data: data,
backgroundColor: ['rgba(255, 0, 0, 0.2)', 'rgba(0, 0, 255, 0.2)', 'rgba(0, 255, 0, 0.2)', 'rgba(145, 90, 185, 0.2)', 'rgba(124, 124, 124, 0.2)'],
datalabels: {
textAlign: 'center',
formatter: v => v < 5 ? '' : v
}
}
]
},
options: {
responsive: false,
plugins: {
legend: {
display: false
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.8.0/chart.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-datalabels#2"></script>
<canvas id="myChart" height="300"></canvas>

Resizing vue-chartjs height while keeping it responsive

Need help with chart js
ACTUALLY, I'M USING VUE-CHARTJS BUT IT'S JUST A WRAPPER
in the line chart on the left side, the number is increasing by 5(0, 5, 10, 15, etc) I want it to increase by 10 and also decrease the height of the chart so the aspect ratio is something like 16/9
also is it possible to make the left number say 5k+, 10k+, 15k+ instead of just 5, 10, 15
here's my code for the chart
<script>
import { Line } from 'vue-chartjs'
export default {
extends: Line,
data: () => ({
chartdata: {
labels: ['January', 'February', 'March', 'April', 'May','Jun'],
datasets: [
{
data: [12, 20, 27, 22, 14, 10],
borderColor: "#135193",
pointBackgroundColor: "#135193",
pointBorderColor: "#135193",
backgroundColor: 'rgba(255, 255, 255, 0)'
},
{
data: [3, 12, 17, 20, 30, 40],
borderColor: "#FF8811",
pointBackgroundColor: "#FF8811",
pointBorderColor: "#FF8811",
backgroundColor: 'rgba(255, 255, 255, 0)'
}
]
},
options: {
responsive: true,
legend: {
display: false
}
}
}),
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>
Yes, you can just use CSS to set the dimensions of the canvas and set maintainAspectRatio to false in the options, for the ticks you can use the tick callback:
const labels = ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"];
const options = {
type: 'line',
data: {
labels,
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
borderColor: 'red',
backgroundColor: 'pink'
}]
},
options: {
maintainAspectRatio: false,
scales: {
yAxes: [{
ticks: {
callback: (val) => (`${val}K`)
}
}]
}
}
}
const ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
canvas {
max-height: 180px;
max-width: 320px;
}
<body>
<canvas id="chartJSContainer" width="600" height="400"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js"></script>
</body>
Okay it turns out its as simple as wrapping the chart with a container and set height of that container as needed

Trying to get _index of clicked bar in ChartJS

I have a bar chart in vue-charts where when clicked I want to display the background data in a table. This is the render
startPie: function(canvas, type){
let chart = new Chart(canvas, {
type: type,
data: {
labels: this.labels,
datasets: this.chart_data
},
options: {
responsive: true,
animation:{ animateScale:true },
title: { display: false },
legend: { display: false },
scales: {
yAxes: [{
gridLines: {
color: "#989898"
},
ticks: {
fontColor: "#989898",
fontSize: 16,
beginAtZero: true,
callback: function(value) {
let ranges = [
{ divider: 1e6, suffix: 'M' },
{ divider: 1e3, suffix: 'k' }
];
function formatNumber(n) {
for (let i = 0; i < ranges.length; i++) {
if (n >= ranges[i].divider) {
return (n / ranges[i].divider).toString() + ranges[i].suffix;
}
}
return n;
}
return '$' + formatNumber(value);
}
}
}],
xAxes: [{
ticks: {
fontColor: "#989898",
fontSize: 12
}
}]
},
plugins: {
datalabels: {
anchor: 'center',
font: {
size: 16,
weight: 'bold'
},
formatter: function(value, context) {
return '$' + Number(value).toLocaleString();
},
color: 'white'
}
},
'onClick':(evt, item) => {
console.log('CLICK', item[0]);
}
}
})
}
In the onClick Event in the console I can see the index
CLICK ChartElement {_chart: Chart, _datasetIndex: 0, _index: 4,
hidden: false, _xScale: ChartElement, …}
I can't access it though without an error. I have tried
item[0]._index, item[0]['_index'], item[0]['ChartElement']._index, item[0]['ChartElement']['_index']
Any help is appreciated.
Unfortunately, the onClick event handler is poorly documented. You could try to define the data in a separate variable outside of the chart configuration.
const data = [55, 68, 82, 48, 75, 45, 67];
Then, you can define the onClick event handler as follows:
options: {
...
onClick: (event, item) => {
const idx = chart.getElementAtEvent(event)[0]._index;
console.log(data[idx]);
}
}
const labels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"];
const data = [55, 68, 82, 48, 75, 45, 67];
let chart = new Chart(document.getElementById('myChart'), {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: "My First Dataset",
data: data,
backgroundColor: ["rgba(255, 99, 132, 0.2)", "rgba(255, 159, 64, 0.2)", "rgba(255, 205, 86, 0.2)", "rgba(75, 192, 192, 0.2)", "rgba(54, 162, 235, 0.2)", "rgba(153, 102, 255, 0.2)", "rgba(201, 203, 207, 0.2)"],
borderColor: ["rgb(255, 99, 132)", "rgb(255, 159, 64)", "rgb(255, 205, 86)", "rgb(75, 192, 192)", "rgb(54, 162, 235)", "rgb(153, 102, 255)", "rgb(201, 203, 207)"],
borderWidth: 1
}]
},
options: {
responsive: true,
title: {
display: false
},
legend: {
display: false
},
scales: {
yAxes: [{
gridLines: {
color: "#989898"
},
ticks: {
fontColor: "#989898",
fontSize: 16,
beginAtZero: true
}
}]
},
plugins: {
datalabels: {
anchor: 'center',
font: {
size: 16,
weight: 'bold'
},
formatter: function(value, context) {
return '$' + Number(value).toLocaleString();
},
color: 'white'
}
},
onClick: (evt, item) => {
const idx = chart.getElementAtEvent(event)[0]._index;
console.log(data[idx]);
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.js"></script>
<canvas id="myChart" height="80"></canvas>