My chart.js
var ctx_1 = document.getElementById('https_http').getContext('2d');
var myChart_1 = new Chart(ctx_1, {
type: 'horizontalBar',
data: {
labels: ['HTTPS Pages','HTTP Pages'],
datasets: [{
data: [ {{ $array_https_http[0] }}, {{ $array_https_http[1] }}],
backgroundColor: [
'rgb(81, 170, 120)',
'rgb(198, 222, 208)'
]
}]
},
options: {
showAllTooltips: true,
tooltips: {
enabled: true,
displayColors: false,
yPadding: 20,
xPadding: 30,
caretSize: 10,
backgroundColor: 'rgba(240, 240, 240, 1)',
bodyFontSize: 16,
bodyFontColor: 'rgb(50, 50, 50)',
borderColor: 'rgba(0,0,0,1)',
borderWidth: 1,
cornerRadius: 0,
yAlign: 'bottom',
xAlign: 'center',
position: 'custom',
custom: function(tooltip) {
if (!tooltip) return;
// disable displaying the color box;
tooltip.displayColors = false;
},
callbacks: {
// use label callback to return the desired label
label: function(tooltipItem, data) {
return tooltipItem.yLabel + " : " + tooltipItem.xLabel ;
},
// remove title
title: function(tooltipItem, data) {
return;
}
}
},
responsive: false,
legend: { display: false },
scales: {
yAxes: [{
ticks: {
beginAtZero:true,
},
gridLines: {
display: false
},
}],
xAxes: [{
ticks: {
stepSize:100
}
}],
}
}
});
My tooltips code
Chart.Tooltip.positioners.custom = function(elements, position) {
if (!elements.length)
return false;
var em = elements[0]._model;
return {
x: em.x-((em.x-em.base)/2),
y: em.y+em.height/4
}
}
My output
My expected output
Is there anyone can help me how to put those value after the bar like the second picture. I just want to display the value to know even its zero. My custom tooltips was to show a different hover rather than default. All your help are appreciated and thank you in advance.
You can use the chartjs.datalabel plugin for achieving the need. I have created a fiddle for you -> http://jsfiddle.net/Labkrpf4/
Hope it helps!
var ctx_1 = document.getElementById('https_http').getContext('2d');
var myChart_1 = new Chart(ctx_1, {
type: 'horizontalBar',
data: {
labels: ['HTTPS Pages', 'HTTP Pages'],
datasets: [{
data: [0, 430],
backgroundColor: [
'rgb(81, 170, 120)',
'rgb(198, 222, 208)'
]
}]
},
options: {
showAllTooltips: true,
tooltips: {
enabled: true,
displayColors: false,
yPadding: 20,
xPadding: 30,
caretSize: 10,
backgroundColor: 'rgba(240, 240, 240, 1)',
bodyFontSize: 16,
bodyFontColor: 'rgb(50, 50, 50)',
borderColor: 'rgba(0,0,0,1)',
borderWidth: 1,
cornerRadius: 0,
yAlign: 'bottom',
xAlign: 'center',
position: 'custom',
custom: function(tooltip) {
if (!tooltip) return;
// disable displaying the color box;
tooltip.displayColors = false;
},
callbacks: {
// use label callback to return the desired label
label: function(tooltipItem, data) {
return tooltipItem.yLabel + " : " + tooltipItem.xLabel;
},
// remove title
title: function(tooltipItem, data) {
return;
}
}
},
responsive: false,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
},
gridLines: {
display: false
},
}],
xAxes: [{
ticks: {
stepSize: 100
}
}],
},
plugins: {
datalabels: {
align: 'end',
anchor: 'end',
backgroundColor: function(context) {
return context.dataset.backgroundColor;
},
borderRadius: 4,
color: 'white',
formatter: Math.round
}
}
}
});
Related
I created a bar chart using ChartJS. The problem is when a data point is small like 2 length. It align all bars in center.
But I don't want this.
The canvas width is 100% to its wrapper. Bars thickness max 14.Below is my code summary. Please help.
The output is like that but i want to both of them bars align to left.
const dataSet = {
type: 'bar',
labels: labels,
datasets:
data.dataSets.length === 1
? [
{
data: data.dataSets[0].data,
backgroundColor: data.dataSets[0].color,
borderRadius: 20,
borderWidth: 0,
barPercentage: 0.4,
maxBarThickness: 14,
hoverBorderWidth: 1,
hoverBackgroundColor: data.dataSets[0].color,
},
{
xAxisID: 'axisX2',
yAxisID: 'axisY2',
label: ' ',
backgroundColor: '#4C4E6414',
hoverBackgroundColor: '#4C4E6414',
hoverBorderWidth: 0,
borderWidth: 0,
barPercentage: 0.4,
maxBarThickness: 14,
borderRadius: 20,
data: data.dataSets[0].data.map((item: any) => 1000),
},
]
: data.dataSets.map((item: any) => {
return {
data: item.data,
backgroundColor: item.color,
borderRadius: 20,
borderWidth: 0,
barPercentage: 0.4,
maxBarThickness: 14,
hoverBorderWidth: 1,
hoverBackgroundColor: item.color,
};
}),
};
<Bar
id="bar-chart"
data={dataSet}
options={{
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'nearest',
axis: 'x',
intersect: false,
},
plugins: {
legend: {
display: false,
},
tooltip: {
enabled: true,
backgroundColor: '#F7F7F9',
titleColor: 'rgba(76, 78, 100, 0.3)',
titleFont: {
size: 13,
},
bodyColor: 'rgba(76, 78, 100, 0.5)',
filter: function (tooltipItem) {
return data.dataSets.length === 1 ? tooltipItem.datasetIndex !== 1 : true;
},
displayColors: data.dataSets.length === 1 ? false : true,
callbacks: {
label: function (tooltipItem) {
return data.dataSets[tooltipItem.datasetIndex]?.label + ' ' + currency + tooltipItem.formattedValue;
},
labelColor: function (tooltipItem) {
return {
borderColor: 'transparent',
backgroundColor: data.dataSets[tooltipItem.datasetIndex]?.color,
borderWidth: 2,
borderRadius: 5,
};
},
},
},
},
scales: {
x: {
axis: 'x',
beginAtZero: true,
border: {
display: false,
},
grid: {
display: false,
drawTicks: false,
},
ticks: {
display: false,
},
},
y: {
axis: 'y',
beginAtZero: true,
border: {
display: false,
},
grid: {
drawTicks: false,
display: false,
},
ticks: {
display: false,
padding: 0,
mirror: true,
},
},
axisX2: {
axis: 'x',
position: 'left',
beginAtZero: true,
border: {
display: false,
},
grid: {
display: false,
drawTicks: false,
},
ticks: {
display: false,
},
},
axisY2: {
axis: 'y',
position: 'left',
beginAtZero: true,
border: {
display: false,
},
grid: {
drawTicks: false,
display: false,
},
ticks: {
padding: 0,
display: false,
mirror: true,
},
},
},
layout: {
padding: {
left: 0,
right: 0,
top: 0,
bottom: 0,
},
},
}}
/>
I'm having some trouble trying to change the backgroundColor of a specific chart area between two yAxis ticks.This is what I have so far:
And this is what I wanted:
I've seen some similar posts about that and people recommend using Annotation to do this. I tried using it on my chart and it didn't work. This is my first time building a chart with chart.js so I'm still learning. Here's my code:
var profileChart = new Chart(ctx1, {
type: "line",
data: {
labels: ["", "D", "I", "S", "C", ""],
datasets:[{
data: [],
borderWidth: 1,
pointBackgroundColor: "black",
backgroundColor: "black",
borderColor: "black",
fill: false,
lineTension: 0,
yAxisID: 'first-y-axis'
},
{
yAxisID: 'third-y-axis'
}],
},
options: {
title: {
display: true,
text: 'Gráfico do Perfil DISC',
fontSize: 20,
},
scales: {
yAxes: [{
id: 'first-y-axis',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '15px',
labelString: 'Intensity'
},
ticks: {
max: 28,
min: 1,
stepSize: 1
}
},
{
id: 'second-y-axis',
type: 'linear',
position: 'left',
gridLines: {
drawOnChartArea: true
},
ticks: {
display: false,
min: 1,
max: 8,
stepSize: 1
}
},
{
id: 'third-y-axis',
position: 'right',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '10px',
labelString: 'Segment'
},
ticks: {
max: 7.5,
min: 0.5,
stepSize: 1
},
afterTickToLabelConversion: function(scaleInstance) {
scaleInstance.ticks[0] = null;
scaleInstance.ticks[scaleInstance.ticks.length - 1] = null;
scaleInstance.ticksAsNumbers[0] = null;
scaleInstance.ticksAsNumbers[scaleInstance.ticksAsNumbers.length - 1] = null;
},
}]
},
legend: {
display: false
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel;
}
}
}
},
annotation: {
drawTime: "afterDraw",
annotations: [{
id: 'box1',
type: 'box',
yScaleID: 'second-y-axis',
yMin: 12.5,
yMax: 16.5,
backgroundColor: 'grey',
}]
}
});
You can draw the rectangle directly on the canvas using the Plugin Core API. The API offers a range of hooks that may be used for performing custom code.
In your amended code below, I use the beforeDraw hook to draw the rectangle through CanvasRenderingContext2D.fillRect().
var profileChart = new Chart('canvas', {
type: "line",
plugins: [{
beforeDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['first-y-axis'];
ctx.save();
ctx.fillStyle = 'lightgray';
ctx.beginPath();
var yTop = yAxis.getPixelForValue(16.5);
var yBottom = yAxis.getPixelForValue(12.5);
ctx.fillRect(xAxis.left, yTop, xAxis.right - xAxis.left, yBottom - yTop);
ctx.stroke();
ctx.restore();
}
}],
data: {
labels: ["", "D", "I", "S", "C", ""],
datasets: [{
data: [,25.5, 8, 7.5, 11],
borderWidth: 1,
pointBackgroundColor: "black",
backgroundColor: "black",
borderColor: "black",
fill: false,
lineTension: 0,
yAxisID: 'first-y-axis'
},
{
yAxisID: 'third-y-axis'
}
],
},
options: {
title: {
display: true,
text: 'Gráfico do Perfil DISC',
fontSize: 20,
},
scales: {
yAxes: [{
id: 'first-y-axis',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '15px',
labelString: 'Intensity'
},
ticks: {
max: 28,
min: 1,
stepSize: 1
}
},
{
id: 'second-y-axis',
type: 'linear',
position: 'left',
gridLines: {
drawOnChartArea: true
},
ticks: {
display: false,
min: 1,
max: 8,
stepSize: 1
}
},
{
id: 'third-y-axis',
position: 'right',
type: 'linear',
gridLines: {
drawOnChartArea: false
},
scaleLabel: {
display: true,
padding: '10px',
labelString: 'Segment'
},
ticks: {
max: 7.5,
min: 0.5,
stepSize: 1
},
afterTickToLabelConversion: function(scaleInstance) {
scaleInstance.ticks[0] = null;
scaleInstance.ticks[scaleInstance.ticks.length - 1] = null;
scaleInstance.ticksAsNumbers[0] = null;
scaleInstance.ticksAsNumbers[scaleInstance.ticksAsNumbers.length - 1] = null;
},
}
]
},
legend: {
display: false
},
tooltips: {
callbacks: {
label: function(tooltipItem) {
return tooltipItem.yLabel;
}
}
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.bundle.min.js"></script>
<canvas id="canvas" height="200">
I have a created a histogram using chart.js. (Referring Make a Histogram in Chart.js). Now i need a zoom in functionality because by default if i am enabling zoom in chart labels and bars are not in-sync. And my data is too much in chart. so i need with width of bar.
This is my config object.
const config: any = {
type: 'bar',
data: {
labels: xLabelx,
datasets: [ { label: 'Count', backgroundColor: 'rgba(215, 239, 252,0.5)', data: NumberOfVehicle,
borderColor: '#37B1F0', borderWidth: 0.5, hoverBackgroundColor: '#66bcff' } ]
},
options: {
tooltips: {
mode: 'label',
bodyFontSize: 12,
opacity: 0.5,
borderWidth: 5,
callbacks: {
title: (tooltipItems, data) => { return ''; },
label(tooltipItem, data) {
const label = data.datasets[tooltipItem.datasetIndex].label;
const value = data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];
return label + ': ' + value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, '');
} } },
pan: { enabled: true, mode: 'xy', drag: true, speed: 10, threshold: 10 },
zoom: { enabled: true, drag: false, mode: 'x' },
maintainAspectRatio: false,
responsive: false,
legend: {
display: true,
onHover: (event, legendItem) => { document.getElementById('myChart').style.cursor = 'pointer'; },
labels: { fontSize: 14 }},
hover: {
onHover: (e, el) => { $('#myChart').css('cursor', el[0] ? 'pointer' : 'default'); }
},
scales: {
xAxes: [
{ display: false, barPercentage: 1.25, ticks: { max: xLabelx[xLabelx.length - 2] }},
{ display: false, ticks: { autoSkip: false, max: xLabelx[xLabelx.length - 1]}},
{ scaleLabel: { display: true, labelString: 'Range', fontFamily: 'Roboto', fontSize: 14 }}
],
yAxes: [
{ scaleLabel: { display: true, labelString: 'No. of model', fontFamily: 'Roboto', fontSize: 14 },
ticks: { beginAtZero: true, fontSize: 12, userCallback: (label, index, labels) => {
if (Math.floor(label) === label && label >= 0) { return label; } } } } ]
}
}
};
I'm trying to make a live update chart, I could manage to get live update values into the Data and the label part, but I can't seem to make it work for the callback. I have 5 arrays from a separate file with stores 5 different data, the fifth array is the one I need to add into my CallBack part, The values from that array would need to go into another array, so I can use into my function, or just make a path to the callbacks part and add the values there. For the ones I could manage doing the live update, I just made a path to the function.
Chart:
function loadData() {
$.getJSON('loadchart.php', function(response) {
myLineChart.data.datasets[0].data = response[0];
myLineChart.data.datasets[1].data = response[1];
myLineChart.data.datasets[2].data = response[2];
myLineChart.data.datasets[3].data = response[3];
myLineChart.data.labels = response[4];
myLineChart.update();
});
}
loadData();
setInterval(loadData, 5000);
var lbl = [];
var ctx1 = document.getElementById('mychart1').getContext('2d');
var myLineChart = new Chart(ctx1, {
type: 'line',
data: {
labels: lbl,
datasets: [
{
label: "Corrente 1",
data: [],
borderWidht: 6,
borderColor: 'red',
backgroundColor: 'transparent'
},
{
label: "Corrente 2",
data: [],
borderWidht: 6,
borderColor: 'blue',
backgroundColor: 'transparent'
},
{
label: "Corrente 3",
data: [],
borderWidht: 6,
borderColor: 'green',
backgroundColor: 'transparent'
},
{
label: "Corrente Total",
data: [],
borderWidht: 6,
borderColor: 'black',
backgroundColor: 'transparent'
},
]
},
options: {
animation:{
update: 0
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}],
xAxes: [{
gridLines: {
display: false
}
}]
},
title: {
display: true,
fontSize: 20,
text: "Gráfico das Correntes"
},
labels: {
fontStyle: "bold",
},
layout: {
padding: {
left: 0,
right: 0,
top: 0,
bottom: 0
}
},
tooltips: {
enabled: true,
mode: 'single',
responsive: true,
backgroundColor: 'black',
titleFontFamily: "'Arial'",
titleFontSize: 14,
titleFontStyle: 'bold',
titleAlign: 'center',
titleSpacing: 4,
titleMarginBottom: 10,
bodyFontFamily: "'Mukta'",
bodyFontSize: 14,
borderWidth: 2,
borderColor: 'grey',
callbacks:{
title: function(tooltipItem, data) {
return data.labels[tooltipItem[0].index];
},
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo[tooltipItem[0]['index']];
},
label: function(tooltipItem, data) {
var label = data.datasets[tooltipItem.datasetIndex].label || '';
if (label) {
label += ': ';
}
label += (tooltipItem.yLabel)+"A";
return label;
}
}
},
aspectRatio: 1,
maintainAspectRatio: false
}
});
This is the part I would need to add the fifht array:
afterTitle: function(tooltipItem, data) {
var tempo = [];
return tempo[tooltipItem[0]['index']];
},
I'm using angular6 and the office highcharts angular wrapper (https://github.com/highcharts/highcharts-angular) in version 2.4.0.
Everything is working good except the labels that can be placed manually on the chart.
I just don't manage to get them refreshed.
I have a graph that can be filtered through the back-end. When I get the new generated data I update the data in my chartOptions which are used in the html as [options]="chartOptions" for the angular component.
The chartOptions are instanciated from my default class like this: this.chartOptions = new GraphConfigSeqAtteptedVsAchived().chartOptions;
The Class looks like this:
`import * as Highcharts from 'highcharts';
export class GraphConfigSeqAtteptedVsAchived{
public chartOptions: any;
constructor(){
this.chartOptions = {
chart: {
height: 600,
width: 620,
events:{load: function(){
this.myTooltip = new Highcharts.Tooltip(this, this.options.tooltip);
}
},
backgroundColor: 'transparent',
},
credits: {
text: 'charname',
href: ''
},
labels: {
},
exporting:{
chartOptions:{
title: {
text:'not set',
style:{
color: '#000000'
},
margin: 0
}
}
},
tooltip: {
enabled: false
},
xAxis: {
min: -10,
max: 0,
width: 535,
title: {
text: 'Rainfall (mm)',
style: {
fontWeight: "bold",
color: '#000000'
}
},
reversed: true,
tickInterval: 1
},
yAxis: {
min: -10,
max: 0,
title: {
text: 'Rainfall (mm)',
style: {
fontWeight: "bold",
color: '#000000'
}
},
reversed: true,
tickInterval: 1
},
title: {
text: ' as',
margin: 0,
style:{
color: 'transparent'
}
},
legend: {
layout: 'vertical',
align: 'left',
verticalAlign: 'top',
x: 100,
y: 90,
floating: true,
backgroundColor: '#FFFFFF',
borderWidth: 1,
navigation: {
enabled: false
}
},
plotOptions: {
scatter: {
stickyTracking: false,
allowPointSelect: true,
marker: {
radius: 3,
states: {
hover: {
enabled: true,
lineColor: 'rgb(100,100,100)'
}
}
},
tooltip: {
headerFormat: '<b>{series.name}</b><br>',
pointFormat: '',
hideDelay: 500
},
symbol: "circle",
events: {
mouseOut: function() {
this.chart.myTooltip.hide();
this.chart.myTooltip.options.enabled = false;
},
mouseOver: function() {
if(this.halo) {
this.halo.attr({
'class': 'highcharts-tracker'
}).toFront();
}
},
click: function(event) {
this.chart.myTooltip.options.enabled = true;
this.chart.myTooltip.refresh(event.point, event);
}
}
},
line:{
events: {
legendItemClick: function () {
return false;
}
}
},
series:{
allowPointSelect: true
}
},
series: [{
type: 'line',
data: [[30, 30], [-30, -30]],
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 1
}
},
showInLegend: false,
color: "rgba(0, 0, 0, 0.6)",
enableMouseTracking: false
},{
type: 'line',
data: [[30, 29.5], [-29.5, -30]],
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 0
}
},
showInLegend: false,
dashStyle: 'ShortDash',
color: "rgba(125, 162, 159, 0.35)",
enableMouseTracking: false
},{
type: 'line',
data: [[29.5, 30], [-30, -29.5]],
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 0
}
},
showInLegend: false,
dashStyle: 'ShortDash',
color: "rgba(125, 162, 159, 0.35)",
enableMouseTracking: false
},{
type: 'line',
data: [[29, 30], [-30, -29]],
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 0
}
},
showInLegend: false,
dashStyle: 'ShortDash',
color: "rgba(197, 144, 161, 0.35)",
enableMouseTracking: false
},{
type: 'line',
data: [[30, 29], [-29, -30]],
marker: {
enabled: false
},
states: {
hover: {
lineWidth: 0
}
},
showInLegend: false,
dashStyle: 'ShortDash',
color: "rgba(197, 144, 161, 0.35)",
enableMouseTracking: false
}]
}
}
}`
The generated data is in the typescript dynamically added and all of that works just fine. Everything is refreshed after I set the updateFlag for [(update)]="updateGraph". The axis titles are also fine.
The only thing that's not refreshed for me are the labels i dynamically added to the chart like this:
let labelTotalNumberOfEyes = {
html : this.translate.instant('GRAPHS.TOTAL_NUMBER_OF_EYES') + ': ' + (scatterSeries.data.length + scatterSeriesRetreatment.data.length),
style : {
left : '330px',
top : '368px',
fontSize : '14px',
backgroundColor: '#FFFFFF',
borderWidth: 1,
}
}
this.chartOptions.labels.items.push(labelTotalNumberOfEyes);
Does someone have any idea what I'm might doing wrong? I don't see any further option than just setting this update flag and it works fine for everything but the labels.
Please let me know if you're missing any information.
Thanks in advance.
This issue is actually a Highcharts bug. I've reported it here: https://github.com/highcharts/highcharts/issues/10429.
As a workaround, you can use Highcharts.SVGRenderer to add a custom label and store reference to it in your component. Next, when updating, call attr() method on the label (Highcharts.SVGElement) and set new options. Check demo and code posted below.
Add a label on chart callback:
constructor() {
const self = this;
this.chartCallback = chart => {
self.chart = chart;
self.label = chart.renderer
.text("test", 100, 100)
.css({
fill: "#555",
fontSize: 16
})
.add()
.toFront();
};
}
call attr() on the label while updating:
update_chart() {
const self = this,
chart = this.chart;
chart.showLoading();
setTimeout(() => {
chart.hideLoading();
self.chartOptions.series = [
{
data: [10, 25, 15],
name: "updatedSerieName"
}
];
self.chartOptions.yAxis.title.text = "updatedData";
self.label
.attr({
text: "test1",
x: 150,
y: 120
})
.css({
fill: "red",
fontSize: 20
});
self.updateFromInput = true;
}, 2000);
}
Demo:
https://codesandbox.io/s/8zo0yvqqwj
API reference:
https://api.highcharts.com/class-reference/Highcharts.SVGRenderer#text
https://api.highcharts.com/class-reference/Highcharts.SVGElement#attr