I created a bar chart component and this is working fine. However I run into problems when trying to display multiple charts with the same component. I'm generating "tiles" dynamically through an ngFor and inside each tile there's a component. The issue is that only the first tile is generating a chart and the rest of the tiles are not. Apologies in advance if I did not provide enough information just let me know and I'll provide more.
ngFor
<div *ngFor="let productLevel of productLevels" class="col-xl-2 col-lg-3 col-md-3 col-sm-4 col-6" align="center">
<app-health-tile [routerLink]="['/details/',group,productLevel.plId]" [title]="productLevel.plId" [up]="productLevel.up" [warning]="productLevel.warning" [down]="productLevel.down"></app-health-tile>
</div>
health-tile.component.ts
<div id="tile" [ngClass]="{'error': error, 'warning': issue, 'healthy': healthy}" align="left">
<div>{{title}}</div>
<app-barchart></app-barchart>
<div id="counter">
{{up}} <i class="fa fa-long-arrow-up" aria-hidden="true"></i>
{{warning}} <i class="fa fa-exclamation" aria-hidden="true"></i>
{{down}} <i class="fa fa-long-arrow-down" aria-hidden="true"></i>
</div>
</div>
barchart.component.ts
import { Component, OnInit } from '#angular/core';
import { Chart } from 'chart.js';
#Component({
selector: 'app-barchart',
templateUrl: './barchart.component.html',
styleUrls: ['./barchart.component.css']
})
export class BarchartComponent implements OnInit {
barChart = [];
constructor() { }
ngOnInit(): void {
this.barChart = new Chart('canvas', {
type: 'bar',
data: {
backgroundColor: "#FFFFFF",
labels: ['4H', '4L', 'Close'],
datasets: [{
label: '# of Inc.',
data: [2,3,1],
borderColor: '#FFFFFF',
backgroundColor: "#FFFFFF",
}]
},
options: {
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
xAxes: [{
display: true,
gridLines: {
// display: false,
drawOnChartArea: false,
zeroLineColor: '#FFFFFF',
color: '#FFFFFF',
fontStyle: "bold",
},
ticks: {
fontColor: '#FFFFFF',
fontFamily: 'Lato',
fontStyle: "bold",
precision:0
},
}],
yAxes: [{
display: true,
gridLines: {
drawOnChartArea: false,
zeroLineColor: '#FFFFFF',
color: '#FFFFFF',
fontStyle: "bold",
},
ticks: {
fontColor: '#FFFFFF',
fontFamily: 'Lato',
fontStyle: "bold",
precision:0
},
}],
}
}
});
}
}
Problem was with your canvas id, you should pass dynamic ids to your chart.
For example:
You have to pass dynamic ids from your component to the canvas.
and you have instantiate your Chart in ngAfterViewInit ie. after View gets initialized.
Your chart template should be like this:
<div class="chart-container">
<canvas [id]="chartId" >{{ barChart }}</canvas>
</div>
barchart test
and in your component it should be like this:
export class BarchartComponent implements OnInit {
#Input() chartId:string;
barChart = [];
constructor(
) { }
ngOnInit(): void {
setTimeout(() => {
this.barChart = new Chart(this.chartId, {
type: 'bar',
data: {
backgroundColor: "#000000",
labels: ['4H', '4L', 'Close'],
datasets: [{
label: '# of Inc.',
data: [2,3,1],
borderColor: '#000000',
backgroundColor: "#000000",
}]
},
options: {
maintainAspectRatio: false,
legend: {
display: false
},
scales: {
xAxes: [{
display: true,
gridLines: {
// display: false,
drawOnChartArea: false,
zeroLineColor: '#000000',
color: '#000000',
fontStyle: "bold",
},
ticks: {
fontColor: '#000000',
fontFamily: 'Lato',
fontStyle: "bold",
precision:0
},
}],
yAxes: [{
display: true,
gridLines: {
drawOnChartArea: false,
zeroLineColor: '#000000',
color: '#000000',
fontStyle: "bold",
},
ticks: {
fontColor: '#000000',
fontFamily: 'Lato',
fontStyle: "bold",
precision:0
},
}],
}
}
}, 100);
})
}
}
Here is the working demo for the same.
demo
Related
Just a warning: I am new to chart.js!
I have a couple of horizontal bar charts and it works fine except one issue that I cannot shake off. I have 5 labels in y-axis but the legend on top of the graph only shows one small rectangle in the color of the first (topmost) bar and even that does not display the label itself, followed by list of labels. I thought it would display each label next to small bar same color as in chart.
Unfortunately, this is an intranet app and I cannot provide a link but here is what I have (data is passed to this function from an ajax call):
function drawRespChart(chartLabels, chartData) {
var ctx = $("#rtChart");
console.log("Labels Array: " + chartLabels);
console.log("Data Array: " + chartData);
if (chartRespTime)
chartRespTime.destroy();
var chart = {
labels: chartLabels,
datasets: [
{
label: chartLabels,
backgroundColor: ["#c45850", "#e8c3b9", "#3cba9f", "#8e5ea2", "#3e95cd"],
data: chartData
}
]
};
chartRespTime = new Chart(ctx, {
type: 'horizontalBar',
data: chart,
datalabels: {
anchor: 'end',
align: 'start',
},
options: {
title: {
display: true,
text: 'IDC Database Response Time (mili-seconds)'
},
legend: {
display: true,
labels: {
fontColor: 'rgb(255, 99, 132)'
}
},
scales: {
xAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Count'
},
ticks: {
major: {
fontStyle: 'bold',
fontColor: '#FF0000'
}
}
}],
yAxes: [{
display: true,
scaleLabel: {
display: true,
labelString: 'Response Time (ms)'
}
}]
},
plugins: {
datalabels: {
color: 'white',
display: function (context) {
return context.dataset.data[context.dataIndex] > 15;
},
font: {
weight: 'bold'
},
formatter: Math.round
}
},
maintainAspectRatio: true,
responsive: true,
showInlineValues: true,
centeredInllineValues: true,
tooltipCaretSize: 0
}
});
}
This is what I see in console window:
Labels Array: 0-350,350-700,700-1000,1000-1500
Data Array: 5065,32,27,3
What I see as legend is one rectangle, same color as first bar, followed by list of labels.
It seems that charts.js labels only works when you split the datasets.
Leaving an example.
https://jsfiddle.net/code4mk/1j62ey38/
datasets: [ {
label: 'Result',
fill:false,
data: aDatasets1,
backgroundColor: '#E91E63',
},
{
label: 'Result2',
fill:false,
data: aDatasets2,
backgroundColor: '#E91E93',
}];
I have a stacked bar chart where the tooltip shows Label: $value & I would like this to be set as space-between so Label is aligned to the left & $value is aligned to the right, allowing all the numerical values to align. For example:
Label 1: $10,000
Label 2: $50,000
Label 3: $100,000
Here is the calculator. Just press the compound button to show the chart.
https://youthful-euclid-784d05.netlify.app
ChartJS options:
// Configuration options go here
options: {
responsive: true,
maintainAspectRatio: true,
legend: {
display: true,
position: "bottom"
},
scales: {
xAxes: [{
ticks: {
fontSize: 16,
fontFamily: "Roboto Condensed"
},
gridLines: {
display: false,
},
scaleLabel: {
display: true,
labelString: 'Year',
fontSize: 16,
fontFamily: "Roboto Condensed"
},
stacked: true,
}],
yAxes: [{
stacked: true,
ticks: {
maxTicksLimit: 5,
beginAtZero: true,
fontSize: 12,
fontFamily: "Roboto Condensed",
callback: function (value, index, values) {
if (parseInt(value) >= 1000) {
return (
numeral(value).format("$0a")
// "$" + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
);
} else {
// return "$" + value;
}
},
},
}, ],
},
legend: {
display: true,
labels : {
fontSize: 14,
fontFamily: "Roboto Condensed",
},
},
chart: {
},
tooltips: {
// displayColors: false,
yAlign: "bottom",
callbacks: {
title: function (tooltip, data) {
return `After ${tooltip[0].label} Years`;
},
label: function(tooltipItems, data) {
return ` ${data.datasets[tooltipItems.datasetIndex].label}: ${formatCurrency(tooltipItems.value)}`;
},
},
// bodyAlign: "center",
titleFontSize: 15,
titleMarginBottom: 10,
bodySpacing: 10,
bodyFontSize: 12,
mode: "x",
xPadding: 10,
yPadding: 10,
// bodySpacing: "5"
},
}
I need to create a stacked horizontal bar chart and for the below code the chart is coming as horizontal but it is not stacked. I have created a seperate component for chart and using it in another component I gone through few stacked overflow articles but didn't help. I not able to find out the issue. any help is very appreciated.
horizontal-chart.component.ts
export class HorizontalBarchartComponent implements OnInit {
dataCtx: any;
bar_chart: any;
#ViewChild('horizontalbarChart') horizontalbarChartRef: ElementRef;
#Input() data = [];
#Input() yLabel: any;
#Input() xLabel: any;
#Input() nameObj?: any;
#Input() stacked:boolean;
#Input() hoverData:Array<any>;
colors: Array<string> = ["rgba(98, 228, 98, 1)", "rgba(248, 227, 117, 1)", "rgba(250, 99,131, 1)"]
constructor() { }
ngAfterViewInit() {
this.renderChart();
}
ngOnChanges() {
if (this.horizontalbarChartRef){
this.renderChart();
}
}
renderChart() {
this.dataCtx = this.horizontalbarChartRef.nativeElement.getContext('2d');
this.bar_chart = new Chart(this.dataCtx, {
type: 'horizontalBar',
data: {
labels: this.nameObj.map(obj => obj.name),
datasets:this.setData()
},
options: {
legend: {
display: true,
position: 'bottom',
labels: {
padding: 20,
fontStyle: 'bold',
fontSize: 12,
}
},
scales: {
xAxes: [{
stacked: true,
position:'top',
display: true,
scaleLabel: {
display: true,
fontStyle: 'bold',
labelString: this.yLabel
},
ticks: {
autoSkip: false,
beginAtZero: true,
max:10
},
gridLines: {
display:false,
}
}],
yAxes: [{
stacked: true,
categoryPercentage: 1,
maxBarThickness: 50,
display: true,
scaleLabel: {
display: true,
fontStyle: 'bold',
labelString: this.xLabel
},
ticks: {
min: 0,
},
gridLines: {
display:false
}
}]
},
responsive: true,
}
});
}
setData(){
let fixed_options ={
borderColor: 'transparent',
borderWidth: 2,
pointBorderColor: 'transparent',
pointBackgroundColor: 'transparent',
pointHoverBackgroundColor: "#fff",
pointHighlightFill: "#fff",
pointRadius: 3,
pointHitRadius: 20,
pointBorderWidth: 1,
}
if(this.stacked){
let subData = [];
this.data.filter((d,index) => { subData.push({"data":d, "backgroundColor": this.colors[index],"label": this.hoverData[index], fixed_options }) });
return subData;
}
else{
return [{"data": this.data,"backgroundColor":'rgba(98, 228, 98, 1)',"label":`Upload/Sketch's Per Factor Scores`}]
}
}
}
another.component.html
<horizontal-barchart class="col-md-10" [data]="horizontalBar.data" yLabel="Percentage"
[xLabel]="'student names'" [nameObj]="quizOrTestAnalysis" [stacked]="true"
[hoverData]="['Proficient Answers', 'Elimination Answers', 'Random Answers']">
</horizontal-barchart>
another.component.ts
horizontalBar = {
data:[[10],[20],[30]],
}
The output of the provided code
I had set ticks:{max:10} on x:axis which restricting the chart from showing further data
I have a problem when I want to fill my chart with my api.
My chart's extraOptions are set, but when I want to render my chart with it, it takes defaults options.
Here is my component:
import { Bar, mixins } from 'vue-chartjs';
export default {
name: 'bar-chart',
extends: Bar,
mixins: [mixins.reactiveProp],
props: {
extraOptions: Object,
chartData: Object,
},
data() {
return {
ctx: null
};
},
methods: {
},
mounted() {
this.renderChart(
this.chartData,
this.extraOptions
);
this.$watch('chartData', (newVal, oldVal) => {
if (!oldVal) {
console.log(this.extraOptions)
this.renderChart(
this.chartData,
this.extraOptions
);
}
}, { immediate: true });
}
};
And my overview with my Options and call api:
<div class="row">
<div class="col-lg-4">
<card>
<bar-chart :height="heightChart" :extraOptions="optionsBar" :chart-data="BarData"> </bar-chart >
</card>
</div>
</div>
</template>
<script>
import Loading from 'src/components/Dashboard/Layout/LoadingMainPanel.vue'
import LineChart from 'src/components/UIComponents/Charts/LineChart.vue'
import pieca from 'src/components/UIComponents/Charts/pieca.vue'
import Clock from './Clock.vue'
import BarChart from 'src/components/UIComponents/Charts/BarChart'
import axios from 'axios'
const WorldMap = () => ({
component: import('./../Maps/WorldMap.vue'),
loading: Loading,
delay: 200
})
export default {
components: {
LineChart,
pieca,
Clock,
BarChart
},
/**
* Chart data used to render stats, charts. Should be replaced with server data
*/
data () {
return {
optionsLine: {
responsive: true,
maintainAspectRatio: false,
title: {
display: true,
text: 'CA Mensuel/12 mois',
fontSize: 17,
fontFamily: "'Montserrat', 'Helvetica Neue', Arial, sans-serif",
fontStyle: 'normal',
fontColor: 'black',
}
},
optionsBar: {
maintainAspectRatio: false,
legend: {
display: false,
labels: {
fontColor: '#ced4da'
}
},
title: {
display: true,
text: 'Cmd/Transporteur',
fontSize: 17,
fontFamily: "'Montserrat', 'Helvetica Neue', Arial, sans-serif",
fontStyle: 'normal',
fontColor: 'black',
},
responsive: true,
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
mode: "nearest",
intersect: 0,
position: "nearest"
},
legend: {
display:true,
position: 'bottom'
},
scales: {
yAxes: [{
stacked: true,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.1)',
zeroLineColor: "transparent",
},
ticks: {
suggestedMin: 60,
suggestedMax: 120,
padding: 20,
fontFamily: "'Poppins',sans-serif",
fontColor: "#ced4da"
}
}],
xAxes: [{
stacked: true,
gridLines: {
drawBorder: false,
color: 'rgba(29,140,248,0.1)',
zeroLineColor: "transparent",
},
ticks: {
padding: 20,
fontFamily: "'Poppins',sans-serif",
fontColor: "#ced4da"
}
}]
}
},
heightChart: 255,
BarData: {
},
And my api request:
axios
.get('api_url')
.then(response => (globalthis.BarData = response.data.transporteur_jour
))
I think my chart is rendering with my extraOptions and when it's fill with api data, it takes the defaults options. When I don't call my api and fill the labels directly in my overview, it works.
How can I do to keep my extraOptions ?
Thanks
i had the same problem with chart data in nuxt.js
add a key to your component and when you get the api response change the value of the key . Vue will re-render the component after this change
my component :
<LineChartComponent :chart-data="datacollection" :height="400" :key="datacollection.key"></LineChartComponent>
Im using chartjs to display some data. Im trying to dynamically add data to datasets array but its not working.
Using additional plugins :-- Legend() Plugin
this.chart = new Charts ('LineChart',
{
type: 'bar',
data: {
labels: this.graphdates,
// data : this.graphname,
datasets: [
{
label: 'prizemoney',
data: this.graphprize,
backgroundColor: "#0000FF",
value : this.grpdata,
},
{
label: 'Bid Amount',
data: this.graphbid,
backgroundColor: "#FF1493",
},
],
plugins: [
Chartist.plugins.legend()
]
},
options: {
animation: {
duration: 10,
},
plugins: [ legend() ],
legend: {
labels: {
// This more specific font property overrides the global property
fontColor: 'black',
series : this.graphname,
}
},
responsive: true,
maintainAspectRatio: false,
tooltips: {
mode: 'label',
backgroundColor: '#FFF',
titleFontSize: 16,
titleFontColor: '#0066ff',
bodyFontColor: '#000',
bodyFontSize: 14,
displayColors: false
},
scales: {
xAxes: [{
stacked: true,
barPercentage: 0.6,
gridLines: { display: false },
ticks: {
fontSize: 15
},
scaleLabel: {
display: true,
labelString: 'Auction Date',
fontSize: 25,
fontStyle: "bold",
},
}],
yAxes: [{
stacked: true,
ticks: {
fontSize: 15
},
scaleLabel: {
display: true,
labelString: 'Amount',
fontSize: 25,
fontStyle: "bold",
}
}],
},
legend: {display: true}
}
});
Want to display the some data in the bars i.e. on Y-axis.