Different color for each bar in a bar graph in ChartJS and VueJS - vue.js

I want each color of the bar is different depending on the data I have in the database. The problem is when I used the codes below it only change the first bar the rest is not. How can I change each bar? Can somebody help me with my problem? Here's my code below
dynamicColor : function() {
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
return "rgba(" + r + "," + g + "," + b + ", 0.5)";
},
poolColors : function(a) {
var pool = [];
for(var i = 0; i < a; i++) {
pool.push(this.dynamicColor());
}
return pool;
},
retrieveDistributedPerDayByLine : function() {
var self = this;
axios.post(this.urlRoot + this.api + "retrieve_transaction_per_day.php")
.then(response => {
console.log(response);
vm.distributed_per_day = response.data
var ctxChart = self.$refs.myChart.getContext('2d');
var myChart = new Chart(ctxChart, {
type: 'bar',
data: {
labels: vm.distributed_per_day.map(item => item.Day),
datasets: [{
label: 'Total Amount',
data: vm.distributed_per_day.map(item => item.Amount),
backgroundColor: [
this.poolColors(vm.distributed_per_day.length)
],
borderColor: [
this.poolColors(vm.distributed_per_day.length)
],
borderWidth: 1
}]
},
reponsive: true,
options: {
title : {
display : true,
text : "Distrubuted Reports per Day",
fontFamily: "sans-serif",
fontSize: 18
},
legend: {
display: false
},
tooltips: {
enabled: true,
padding: 10
}
}
});
}).catch(e => {
console.log(e)
});
},

the this.poolColors method is returning an array so you are passing an array inside an array hence it is considered as one element ... it should be like this :
backgroundColor: this.poolColors(vm.distributed_per_day.length),
borderColor: this.poolColors(vm.distributed_per_day.length)

Related

Vue-Charts label numbers to the side of a bar chart

I am using a Nuxt application with vue-charts. I have a barchart that I trying to see if there is a way to callback the numbers next to the chart. Some what like this
My barchart options look like this now.
barLostDollarChartOptions: {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
title: {
display: true,
text: 'Daily NP Opportunity Costs'
},
scales: {
yAxes: [{
//Sets the Max value after re-rendering chart
beforeFit: function (scale){
let maxValue = 0
if (scale.chart.config && scale.chart.config.data && scale.chart.config.data.datasets) {
scale.chart.config.data.datasets.forEach(dataset => {
if (dataset && dataset.data) {
dataset.data.forEach(value => {
if (value > maxValue) {
maxValue = value
}
})
}
})
}
// After, set max option !!!
scale.options.ticks.max = maxValue
},
// afterFit: function (scale){
// console.log('yAxes',scale)
// let arr = Object.values(scale.chart.config.data.datasets[0].data);
// let min = Math.min(...arr);
// let max = Math.max(...arr);
// maxValueArray.push(max)
// // console.log( `Min value: ${min}, max value: ${max}` );
//
// }
}
],
xAxes: [{
ticks:{
callback: function(value, index, values) {
if(parseInt(value) >= 1000){
// console.log(value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","))
return '$' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
} else {
return '$' + value;
}
},
},
}]
}
},
But I am trying to see if there is a way that I can call back the number and render it next to the bar? any ideas?
You can use the datalabels plugin for this:
Chart.plugins.register(ChartDataLabels);
var options = {
type: 'horizontalBar',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: 'orange'
}]
},
options: {
plugins: {
datalabels: {
anchor: 'end',
align: 'end',
formatter: (val) => ('$' + val)
}
}
}
}
var ctx = document.getElementById('chartJSContainer').getContext('2d');
new Chart(ctx, options);
<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>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chartjs-plugin-datalabels/1.0.0/chartjs-plugin-datalabels.js"></script>
</body>

how can I show the data label on the dot of the graph? ng2chart

https://valor-software.com/ng2-charts/#/LineChart
That is the link I followed for the line chart. I was able to show the data on the pie graph but it seems like different on this line chart. Like the graph below, how can I show data on the graph?
Update
I added a long line of code below. Typescript file can be also found in the the link above.
html
<div class="flex">
<div class="flex-item">
<div style="display: block;">
<canvas
baseChart
height="30vh"
width="70vw"
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="lineChartOptions"
[colors]="lineChartColors"
[legend]="lineChartLegend"
[chartType]="lineChartType"
[plugins]="lineChartPlugins"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)"
></canvas>
</div>
</div>
</div>
ts
import { Component, OnInit, ViewChild } from "#angular/core";
import { BaseChartDirective, Color, Label } from "ng2-charts";
import { ChartDataSets, ChartOptions } from "chart.js";
import * as pluginAnnotations from "chartjs-plugin-annotation";
#Component({
selector: "kt-chart1",
templateUrl: "./chart1.component.html",
styleUrls: ["./chart1.component.scss"],
})
export class Chart1Component implements OnInit {
public lineChartData: ChartDataSets[] = [
{
data: [180, 33, 200, 300, 333, 270, 200],
label: "Cost",
yAxisID: "y-axis-1",
},
];
public lineChartLabels: Label[] = [
"01/05/2020",
"02/05/2020",
"03/05/2020",
"04/05/2020",
"05/05/2020",
"06/05/2020",
"07/05/2020",
];
public lineChartOptions: ChartOptions & { annotation: any } = {
plugins: {
labels: {
fontColor: ["green", "white", "red"],
precision: 2,
textShadow: true,
render: function (args) {
return args.value + "(" + args.toFixed(1) + "%)";
},
position: "inside",
},
datalabels: {
formatter: () => {
return null;
},
},
},
responsive: true,
scales: {
// We use this empty structure as a placeholder for dynamic theming.
xAxes: [{}],
yAxes: [
{
id: "y-axis-1",
position: "right",
gridLines: {
color: "rgba(255,0,0,0.3)",
},
ticks: {
fontColor: "red",
},
},
],
},
annotation: {
annotations: [
{
type: "line",
mode: "horizontal",
scaleID: "y-axis-1",
value: "200",
borderColor: "red",
borderWidth: 2,
label: {
enabled: true,
fontColor: "orange",
content: "200",
},
},
],
},
tooltips: {
callbacks: {
label: (item, data) => {
console.log(item);
return "Cost: " + item.xLabel + " " + item.yLabel;
},
},
},
};
public lineChartColors: Color[] = [
{
// grey
backgroundColor: "rgba(148,159,177,0.2)",
borderColor: "rgba(148,159,177,1)",
pointBackgroundColor: "rgba(148,159,177,1)",
pointBorderColor: "#fff",
pointHoverBackgroundColor: "#fff",
pointHoverBorderColor: "rgba(148,159,177,0.8)",
},
{
// dark grey
backgroundColor: "rgba(77,83,96,0.2)",
borderColor: "rgba(77,83,96,1)",
pointBackgroundColor: "rgba(77,83,96,1)",
pointBorderColor: "#fff",
pointHoverBackgroundColor: "#fff",
pointHoverBorderColor: "rgba(77,83,96,1)",
},
{
// red
backgroundColor: "rgba(255,0,0,0.3)",
borderColor: "red",
pointBackgroundColor: "rgba(148,159,177,1)",
pointBorderColor: "#fff",
pointHoverBackgroundColor: "#fff",
pointHoverBorderColor: "rgba(148,159,177,0.8)",
},
];
public lineChartLegend = true;
public lineChartType = "line";
public lineChartPlugins = [pluginAnnotations];
#ViewChild(BaseChartDirective, { static: true }) chart: BaseChartDirective;
constructor() {}
ngOnInit() {
}
public randomize(): void {
for (let i = 0; i < this.lineChartData.length; i++) {
for (let j = 0; j < this.lineChartData[i].data.length; j++) {
this.lineChartData[i].data[j] = this.generateNumber(i);
}
}
this.chart.update();
}
private generateNumber(i: number) {
return Math.floor(Math.random() * (i < 2 ? 100 : 1000) + 1);
}
// events
public chartClicked({
event,
active,
}: {
event: MouseEvent;
active: {}[];
}): void {
console.log(event, active);
}
public chartHovered({
event,
active,
}: {
event: MouseEvent;
active: {}[];
}): void {
console.log(event, active);
}
public hideOne() {
const isHidden = this.chart.isDatasetHidden(1);
this.chart.hideDataset(1, !isHidden);
}
public pushOne() {
this.lineChartData.forEach((x, i) => {
const num = this.generateNumber(i);
const data: number[] = x.data as number[];
data.push(num);
});
this.lineChartLabels.push(`Label ${this.lineChartLabels.length}`);
}
public changeColor() {
this.lineChartColors[2].borderColor = "green";
this.lineChartColors[2].backgroundColor = `rgba(0, 255, 0, 0.3)`;
}
public changeLabel() {
this.lineChartLabels[2] = ["1st Line", "2nd Line"];
// this.chart.update();
}
}
Instead of using chartjs-plugin-annotation, you can draw the labels directly on the canvas using the Plugin Core API. It offers a number of hooks that can be used to perform custom code. In your case, you could use the afterDraw hook and register it in the ngOnInit method as follows:
ngOnInit(): void {
Chart.pluginService.register({
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0']; // would be 'y-axis-1' in your code sample
ctx.save();
chart.data.labels.forEach((l, i) => {
var value = chart.data.datasets[0].data[i];
var x = xAxis.getPixelForValue(l);
var y = yAxis.getPixelForValue(value);
ctx.textAlign = 'center';
ctx.font = '12px Arial';
ctx.fillStyle = 'red';
ctx.fillText(value, x, y - 15);
});
ctx.restore();
}
});
}
Please have a look at this StackBlitz to see how it works.

Dynamic column in PDFMAKE

i'm using PdfMake to generate PDFs with on my VueJS app and i would like to know if i can control the impression of columns in my template, for example, using the data who was being printed like an variable.
I'm trying to reach something like this:
let var1: string = 'test';
let var2: string = 'test2';
1) Original code
var dd = {
content: [
{
alignment: 'justify',
columns: [
{
text: 'var1'
},
{
text: 'var2'
}
]
},
],
styles: {
header: {
fontSize: 18,
bold: true
},
bigger: {
fontSize: 15,
italics: true
}
},
defaultStyle: {
columnGap: 50
}
}
2) After/with validation
if var2 == null
var dd = {
content: [
{
alignment: 'justify',
columns: [
{
text: 'var1'
}
]
},
],
styles: {
header: {
fontSize: 18,
bold: true
},
bigger: {
fontSize: 15,
italics: true
}
},
defaultStyle: {
columnGap: 50
}
}
Wouldn't setting a variable outside the document definition suffice?, I believe a piece of code will do the trick.
var columns = [];
var var1; // Defaults to undefined
var var2; // Defaults to undefined
var1 ="";
// If we have a value we add the column
if (var1 !== undefined) {
columns.push({ text: "var1" });
}
if (var2 !== undefined) {
columns.push({ text: "var2" });
}
// PDFMake document definition
var dd = {
content: [
{
alignment: 'justify',
columns: columns
},
]
...
}

How can I put sign (%) on data in ChartJS?

I want to add the sign (%) next to the value. The problem is when I concatenate sign (%) the pie chart is not showing data: vm.distributed_per_day.map(item => (item.Amount / sum * 100).toFixed(2) + '%'). How can I add the sign (%) to my pie chart? Can somebody help me with my problem? Here's my code
retrieveDistributedPerDayByPie : function() {
var self = this;
var sum = 0;
axios.post(this.urlRoot + this.api + "retrieve_transaction_per_day.php")
.then(response => {
console.log(response);
vm.distributed_per_day = response.data
var ctxChart = self.$refs.myChart2.getContext('2d');
for(var i = 0; i < this.distributed_per_day.length; i++) {
sum += parseFloat(this.distributed_per_day[i].Amount);
}
var myChart2 = new Chart(ctxChart, {
type: 'pie',
data: {
labels: vm.distributed_per_day.map(item => item.Day),
datasets: [{
label: 'Total Amount',
data: vm.distributed_per_day.map(item => (item.Amount / sum * 100).toFixed(2) + '%'),
backgroundColor: this.poolColors(vm.distributed_per_day.length),
borderColor: '#eee',
borderWidth: 2
}]
},
reponsive : true,
options: {
title : {
display : true,
text : "Distributed Reports per Day",
fontFamily: "sans-serif",
fontSize: 18,
},
legend: {
display: false
},
tooltips: {
enabled: true
}
}
});
}).catch(e => {
console.log(e)
});
},
This works on a bar chart, haven't tried it on a pie chart. Hope it works for you.
yAxes: [
{
ticks: {
callback: function (value, index, values) {
return value + " %";
}
}
}
]
This solution worked for me.
tooltips: {
mode: 'label',
callbacks: {
label: function (tooltipItem, data) {
var indice = tooltipItem.index;
return data.labels[indice] + ': ' + data.datasets[0].data[indice] + '%';
}
}
}

kendo bar chart read never contatct server (cache disabled)

When some external event is triggered I need to refresh chart datasource manually calling:
$(".k-chart").data("kendoChart").dataSource.read();
Everytime I call read, datasource requestEnd is called, but, obiviously no response is available on event handler object.
I can't see any error but the webservice specified in datasource.transport.read.url is never reached after the first request.
Chart load data by server only the first time, here is the configuration:
$scope.chartopts = {
charArea: {
height: 500,
},
title: {
position: "bottom",
text: "A / B"
},
legend: {
position: "top",
visible: true
},
chartArea: {
background: "transparent"
},
seriesDefaults: {
labels: {
visible: true,
background: "transparent",
template: "#= category #: (#= value #)",
align: "alignColumn"
}
},
series: [{
startAngle: 180,
categoryField: 'category',
field: 'value',
padding: 0
}],
dataSource: {
transport: {
read: {
url: wsurl,
type: 'POST',
data: {id: id},
dataType: 'json',
cache: false,
}
},
requestEnd: function(e){
if(e.type == 'read' && e.response){//works only the first time
var rsp = [];
var a = e.response.a;
var b = e.response.b;
var tot = a + b;
if(tot!=0){
var pa = parseFloat(100 * a / tot).toFixed(2);
var pb = parseFloat(100 * b / tot).toFixed(2);
}
else {
pa = 0;
pb = 0;
}
rsp = [{
category: "A",
value: a,
color: "#66FF99",
},{
category: "B",
value: b,
color: "#FF9900",
}];
this.data(rsp);
}
}
},
tooltip: {
visible: true,
},
valueAxis: {
majorGridLines: {
visible: false
},
visible: false
},
categoryAxis: {
majorGridLines: {
visible: false
},
line: {
visible: false
}
}
};
Here is the tag:
<div kendo-chart k-options='chartopts' ></div>
I also tried to call refresh method on chart. Widget on screen is refreshed but datasource remain unchanged.
Solved defining schema property in datasource configuration object and adapting/moving all the logic from requestEnd to schema.parse method.
dataSource: {
transport: {
read: {
url: wsurl,
type: 'POST',
data: {id: id},
dataType: 'json',
cache: false,
}
},
schema: {
data: 'results',
total: 'total',
parse: function(data){
var rsp = [];
var a = data.a;
var b = data.b;
var tot = a + b;
if(tot!=0){
var pa = parseFloat(100 * a / tot).toFixed(2);
var pb = parseFloat(100 * b / tot).toFixed(2);
}
else {
pa = 0;
pb = 0;
}
rsp = {results: [{
category: "A",
value: a,
color: "#66FF99",
},{
category: "B",
value: b,
color: "#FF9900",
}], total: 2};
return rsp;
}
}
}
Everytime I need to run datasource.read(), I also refresh chart:
var chart = $(".k-chart").data("kendoChart");
chart.dataSource.read();
chart.refresh();