issue in creating stacked horizontal bar-chart in chartJs - javascript

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

Related

Angular Chart.JS Only One Canvas Rendering

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

implementing horizontal bar chart

I am a noob in angular. I already have a bar-chart component and I am using that component in several places across the project. now I want to implement the horizontal bar chart by modifying that bar chart component but I am stuck at this point and not moving forward. there are no errors and below code implementing a normal bar chart. Thanks in advance
bar-chart component
dataCtx: any;
bar_chart: any;
#ViewChild('barChart') barChartRef: ElementRef;
#Input() data = [];
#Input() type: string;
#Input() hoverData: Array<string>;
#Input() yLabel: any;
#Input() xLabel: any;
#Input() label?: string;
#Input() barLabel?: string;
#Input() nameObj?: any;
#Input() showLabel: boolean;
#Input() charType: string;
color = [];
#Output() onSegClick = new EventEmitter<any>();
colors: Array<string> = ["rgba(98, 228, 98, 1)", "rgba(248, 227, 117, 1)", "rgba(250, 99,131, 1)", 'red', 'blue', 'violet', 'orange'];
constructor() { }
ngOnInit() {
}
ngAfterViewInit() {
this.renderChart();
}
ngOnChanges() {
if (this.barChartRef)
this.renderChart();
}
renderChart() {
let self = this;
this.dataCtx = this.barChartRef.nativeElement.getContext('2d');
let gradient_1 = this.dataCtx.createLinearGradient(0, 0, 0, 250);
gradient_1.addColorStop(0, ' #c4743e');
gradient_1.addColorStop(1, 'transparent');
let gradient_2 = this.dataCtx.createLinearGradient(0, 0, 0, 250);
gradient_2.addColorStop(0, 'beige');
gradient_2.addColorStop(1, 'transparent');
let gradient_3 = this.dataCtx.createLinearGradient(0, 0, 0, 250);
gradient_3.addColorStop(0, '#2f7ca7');
gradient_3.addColorStop(1, "transparent");
this.bar_chart = new Chart(this.dataCtx, {
type: this.charType || 'bar',
data: {
labels: this.nameObj.map(obj => obj.name),
datasets: this.setChartData()
},
options: {
legend: {
display: this.showLabel,
labels: {
padding: 20,
fontStyle: 'bold',
fontSize: 16,
}
},
title: {
display: this.label ? true : false,
text: this.label,
fontStyle: 'bold',
fontSize: 20,
},
showAllTooltips: true,
toolTips: {
mode: 'index',
intersect: true
},
scales: {
xAxes: [{
categoryPercentage: 0.65,
// barPercentage: 1.0,
// barThickness: 50,
maxBarThickness: 50,
display: true,
scaleLabel: {
display: true,
fontStyle: 'bold',
labelString: this.yLabel
},
ticks: {
autoSkip: false
},
gridLines: {
color: 'rgba(88, 88, 88, 0.35)',
lineWidth: 2.5
}
}],
yAxes: [{
// stacked: true,
display: true,
scaleLabel: {
display: true,
fontStyle: 'bold',
labelString: this.xLabel
},
ticks: {
min: 0,
max: 100,
},
gridLines: {
color: 'rgba(0, 78, 162, 0.5)',
lineWidth: 0.5
}
}]
},
responsive: true,
onClick: function (evt, arr) {
if (arr[0]) {
self.onSegClick.emit(arr[0]._index);
}
},
}
});
}
cohortProf(options) {
let cohortData = [{
data: this.data.map(coh => Math.floor(coh.proficiency * 100)),
backgroundColor: '#0080FF',
options
}]
return cohortData;
}
testData() {
let testData = [];
this.data.forEach((d, i) => {
let val = Math.floor(d.data * 100);
testData.push(val);
this.color.push('#' + (Math.random() * 0xFFFFFF << 0).toString(16));
// this.color.push('hsl('+ val +', 100%, 50%)')
});
return testData;
}
testProf(options) {
let testData = [{
data: this.testData(),
backgroundColor: this.color,
options
}]
return testData;
}
subjectProf(options) {
let subData = [];
let strat = this.hoverData;
this.data.filter((d, index) => { subData.push({ "data": d, "backgroundColor": this.colors[index], options, label: strat[index] }) });
return subData;
}
setChartData() {
let dataSet: any;
let fixed_options = {
borderColor: 'tranparent',
borderWidth: 2,
pointBorderColor: 'transparent',
pointBackgroundColor: 'transparent',
pointHoverBackgroundColor: "#fff",
pointHighlightFill: "#fff",
pointRadius: 3,
pointHitRadius: 20,
pointBorderWidth: 1,
};
switch (this.type) {
case 'test': {
dataSet = this.testProf(fixed_options);
break;
}
case 'cohort': {
dataSet = this.cohortProf(fixed_options);
break;
}
case 'grouped-chart': {
dataSet = this.subjectProf(fixed_options);
break;
}
case 'single-bar': {
dataSet = [{
data: this.data,
backgroundColor: this.colors,
label: 'Analytics'
}];
break;
}
default: {
break;
}
}
return dataSet;
}
}
reusing the same component to implement horizontal bar chart
horizantalChart = {
data:[[10,20],[30,40]]
}
<bar-chart [type]="'single-bar'" [hoverData]="['Experts Avg. Score', 'Others Avg. Score']" barLabel="Proficiency"
[data]="horizontalChart.data" [nameObj]="uploadAnalytics.analytics" yLabel="Quizzes" chartType="horizontalBar"
[xLabel]="'Average Upload Score'" [showLabel]="true" (onSegClick)="selectBar($event)"></bar-chart>
The output of the code looks like this
Inside the renderChart method of your bar-chart component, the chart is currently created as follows:
this.bar_chart = new Chart(this.dataCtx, {
type: 'bar',
...
This will always create a vertical bar chart. It should be rewritten as follows in order to consider the type provided by the #Input() decorator.
this.bar_chart = new Chart(this.dataCtx, {
type: this.type,
...
Probably this.bar_chart is then no longer an appropriate name and should be amended to avoid future misunderstandings.

Angular: want to display names inside the bars of a chart

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.

How to make points in chartjs draggable?

Question
I'm looking to make 3 points on a graph draggable between 0 and 100. I'm looking to do this in React with ChartJS via react-chartjs-2.
Here is a fiddle with everything setup (js also below).
Extra Info
The fiddle uses some random version of react-chartjs-2 because I couldn't figure out how to import. On my local setup I use import { Line } from 'react-chartjs-2'; but I'm not sure how to do that in jsfiddle. Webdev is super new to me.
What have I tried so far?
I tried using a few chartjs plugins (like this one) that claimed
to do draggable points, but I couldn't figure out how to get them
working in React. This might be the easiest solutin.
I tried adding my own event listeners for mouseDown/Up/Enter/Leave,
but I was unable to attach these to the actual points. If I just have
access to <Line /> is there a way in React for me to attach to the
points themselves? If I could get the coordinates and have these
events, I could kludge together a solution.
I tried searching on the chartjs and react-chartjs-2 docs, but I
couldn't find anything that would let me drag, or attach the right
listeners.
Code
var Line = reactChartjs2.Line;
const options = {
tooltips: {enabled: true},
scales: {
xAxes: [{
gridLines: {display: false, color: 'grey',},
ticks: {fontColor: '#3C3C3C', fontSize: 14,},
}],
yAxes: [{
scaleLabel: {display: true, labelString: 'Color Strength', fontSize: 14,},
ticks: {
display: true,
min: -5,
max: 100,
scaleSteps: 50,
scaleStartValue: -50,
maxTicksLimit: 4,
fontColor: '#9B9B9B',
padding: 30,
callback: point => (point < 0 ? '' : point),
},
gridLines: {
display: false,
offsetGridLines: true,
color: '3C3C3C',
tickMarkLength: 4,
},
}],
},
};
class DraggableGraph extends React.Component {
state = {
dataSet: [0, 0, 0],
labels: ['red', 'green', 'blue'],
};
render() {
const data = {
labels: this.state.labels,
datasets: [{
data: this.state.dataSet,
borderColor: '9B9B9B',
borderWidth: 1,
pointRadius: 10,
pointHoverRadius: 10,
pointBackgroundColor: '#609ACF',
pointBorderWidth: 0,
spanGaps: false,
}],
};
return (
<div>
<Line
data={data}
options={options}
legend={{display: false}}
plugins={{}}
/>
</div>
);
}
}
ReactDOM.render(<DraggableGraph />, document.getElementById('app'));
You can do this by using chartjs-plugin-dragData. You have to set dragData: true within options object to use this plugin in chart js. Here I have provided updated code.
var Line = reactChartjs2.Line;
const options = {
tooltips: {enabled: true},
scales: {
xAxes: [{
gridLines: {display: false, color: 'grey',},
ticks: {fontColor: '#3C3C3C', fontSize: 14,},
}],
yAxes: [{
scaleLabel: {display: true, labelString: 'Color Strength', fontSize: 14,},
ticks: {
display: true,
min: -5,
max: 100,
scaleSteps: 50,
scaleStartValue: -50,
maxTicksLimit: 4,
fontColor: '#9B9B9B',
padding: 30,
callback: point => (point < 0 ? '' : point),
},
gridLines: {
display: false,
offsetGridLines: true,
color: '3C3C3C',
tickMarkLength: 4,
},
}],
},
legend:{
display: false
},
dragData: true,
onDragStart: function (e) {
console.log(e)
},
onDrag: function (e, datasetIndex, index, value) {
console.log(datasetIndex, index, value)
},
onDragEnd: function (e, datasetIndex, index, value) {
console.log(datasetIndex, index, value)
}
};
class DraggableGraph extends React.Component {
state = {
dataSet: [0, 0, 0],
labels: ['red', 'green', 'blue'],
};
render() {
const data = {
labels: this.state.labels,
datasets: [{
data: this.state.dataSet,
borderColor: '9B9B9B',
borderWidth: 1,
pointRadius: 10,
pointHoverRadius: 10,
pointBackgroundColor: '#609ACF',
pointBorderWidth: 0,
spanGaps: false,
}],
};
return (
<div>
<Line
data={data}
options={options}
/>
</div>
);
}
}
ReactDOM.render(<DraggableGraph />, document.getElementById('app'));
https://jsfiddle.net/4mdenzjx/

Change color of line along labels Chart.js

I am trying to change the colour and thickness of the lines along the Y and X axis.
I don't know what I am looking for in the documentation but have named them line in the code for now.
What is the line called and what should I name it for it to work?
The lines inside the red mark I want to keep but remove grid.
HTML
<canvas id="canvas-1"></canvas>
JS
var randomScalingFactor = function(){ return Math.round(Math.random()*100)};
var lineChartData = {
labels : ['January','February','March','April','May','June','July'],
datasets : [
{
label: 'My First dataset',
labelColor : '#fff',
fontColor : '#fff' ,
backgroundColor : 'rgba(220,220,220,0.2)',
borderColor : 'rgba(220,220,220,1)',
pointBackgroundColor : 'rgba(220,220,220,1)',
pointBorderColor : '#fff',
data : [randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor(),randomScalingFactor()]
}
]
}
var options = {
responsive: true,
maintainAspectRatio: false,
legend: {
fontColor: "white",
},
scales: {
xAxes: [{
gridLines: {
display: true,
drawBorder: true,
color: "green",
},
ticks: {
fontColor: "white",
},
}],
yAxes: [{
stacked: true,
gridLines: {
display: true,
drawBorder: true,
color: "blue",
},
ticks: {
fontColor: "white",
beginAtZero: true,
}
}]
}
};
var ctx = document.getElementById('canvas-1');
var chart = new Chart(ctx, {
type: 'line',
data: lineChartData,
options: options
});
To change the color and thickness of lines (along x and y axis), set color and lineWidth property respectively, for both axis­'s grid-lines, like so :
scales: {
xAxes: [{
gridLines: {
display: false,
color: 'green',
lineWidth: 3
},
...
}],
yAxes: [{
gridLines: {
display: false,
color: '#07C',
lineWidth: 3
},
...
}]
}
ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩
var randomScalingFactor = function() {
return Math.round(Math.random() * 100)
};
var lineChartData = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [{
label: 'My First dataset',
labelColor: '#fff',
fontColor: '#fff',
backgroundColor: 'rgba(220,220,220,0.2)',
borderColor: 'rgba(220,220,220,1)',
pointBackgroundColor: 'rgba(220,220,220,1)',
pointBorderColor: '#fff',
data: [randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor(), randomScalingFactor()]
}]
}
var options = {
responsive: true,
maintainAspectRatio: false,
legend: {
fontColor: "white",
},
scales: {
xAxes: [{
gridLines: {
display: false,
color: 'green',
lineWidth: 3
},
ticks: {
fontColor: "white",
},
}],
yAxes: [{
stacked: true,
gridLines: {
display: false,
color: '#07C',
lineWidth: 3
},
ticks: {
fontColor: "white",
beginAtZero: true,
}
}]
}
};
var ctx = document.getElementById('canvas-1');
var chart = new Chart(ctx, {
type: 'line',
data: lineChartData,
options: options
});
canvas { background: #222 }
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="canvas-1"></canvas>
EDIT:
For those looking to change the generated graph line (not the grid lines):
The line options are for the line type graph, similar as you'll have a doughnut type and so on. I believe you figured that out, right?
A quick look in my code showed the option datasetStrokeWidth which you can use for the thickness. more info
The color option can be found under strokeColor for the style options.
As chart.js combines data- & style options, you're options will look something like this:
var lineChartData = {
line: {
datasets: [
{
strokeColor: '#15bedb'
}
]
}
};
var lineChartStyle = {
line: {
datasetStrokeWidth: 1
}
};
var ctx = document.getElementById('canvas-1');
var chart = new Chart(ctx, {
type: 'line',
data: lineChartData,
options: lineChartStyle
});

Categories