Show values on top of bars in chart.js - javascript

Please refer this Fiddle : https://jsfiddle.net/4mxhogmd/1/
I am working on chart.js
If you see in fiddle, you will notice that value which is top on bar is not properly displayed in some cases(goes outside the canvas)
While research I came across this link how to display data values on Chart.js
But here they used tooltip also for same cases to the text tweak inside of bars.
I don't want this.
var ctx = document.getElementById("myChart");
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ["2 Jan", "9 Jan", "16 Jan", "23 Jan", "30 Jan", "6 Feb", "13 Feb"],
datasets: [{
data: [6, 87, 56, 15, 88, 60, 12],
backgroundColor: "#4082c4"
}]
},
options: {
"hover": {
"animationDuration": 0
},
"animation": {
"duration": 1,
"onComplete": function () {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function (bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
legend: {
"display": false
},
tooltips: {
"enabled": false
},
scales: {
yAxes: [{
display: false,
gridLines: {
display : false
},
ticks: {
display: false,
beginAtZero:true
}
}],
xAxes: [{
gridLines: {
display : false
},
ticks: {
beginAtZero:true
}
}]
}
}
});
What I want is to show value on top only, for all cases.

I pulled out the data from being defined inside of myChart that way I could pull out the max value from the dataset. Then inside of the yAxes you can set the max ticks to be the max value + 10 from your data set. This ensures that the top bars in the graph will not go off the edge of the canvas and not display their value.
var ctx = document.getElementById("myChart");
debugger;
var data = {
labels: ["2 Jan", "9 Jan", "16 Jan", "23 Jan", "30 Jan", "6 Feb", "13 Feb"],
datasets: [{
data: [150, 87, 56, 50, 88, 60, 45],
backgroundColor: "#4082c4"
}]
}
var myChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
"hover": {
"animationDuration": 0
},
"animation": {
"duration": 1,
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
legend: {
"display": false
},
tooltips: {
"enabled": false
},
scales: {
yAxes: [{
display: false,
gridLines: {
display: false
},
ticks: {
max: Math.max(...data.datasets[0].data) + 10,
display: false,
beginAtZero: true
}
}],
xAxes: [{
gridLines: {
display: false
},
ticks: {
beginAtZero: true
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.5.0/Chart.bundle.js"></script>
<canvas id="myChart" width="100" height="100"></canvas>

The fastest way I found to do this was to use this plugin: https://github.com/chartjs/chartjs-plugin-datalabels
Labels can be added to your charts simply by importing the plugin to the js file e.g.:
import 'chartjs-plugin-datalabels'
And if you want to apply it values on top (globally), simply set these options in your code:
Chart.defaults.global.plugins.datalabels.anchor = 'end';
Chart.defaults.global.plugins.datalabels.align = 'end';
More options can be found here: https://chartjs-plugin-datalabels.netlify.com/options.html

Here is a more robust solution that will display the datapoint value inside the bar for cases where the axis height is close to the bar height. In other words, this will display the value above the bar and/or below the bar if the text will extend beyond the canvas visible area.
Chart.plugins.register({
afterDraw: function(chartInstance) {
if (chartInstance.config.options.showDatapoints) {
var helpers = Chart.helpers;
var ctx = chartInstance.chart.ctx;
var fontColor = helpers.getValueOrDefault(chartInstance.config.options.showDatapoints.fontColor, chartInstance.config.options.defaultFontColor);
// render the value of the chart above the bar
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = fontColor;
chartInstance.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
var scaleMax = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
var yPos = (scaleMax - model.y) / scaleMax >= 0.93 ? model.y + 20 : model.y - 5;
ctx.fillText(dataset.data[i], model.x, yPos);
}
});
}
}
});
You can enable your chart to use the plugin by adding the below property in your chart options.
showDatapoints: true,

This worked in my case.(plugins section below)
options: {
responsive: true,
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}]
},
plugins: {
datalabels: {
anchor: 'end',
align: 'top',
formatter: Math.round,
font: {
weight: 'bold'
}
}
}
}
Happy Coding.

You can use add some padding-top inside your chart options
layout: {
padding: {
left: 0,
right: 0,
top: 30,
bottom: 0
}
},

You can consider plugin which show data value on top of each bar.
plugins: {
afterDatasetsDraw: function (context, easing) {
var ctx = context.chart.ctx;
context.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
if (dataset.data[i] != 0) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
var textY = model.y + (dataset.type == "line" ? -3 : 15);
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'start';
ctx.textBaseline = 'middle';
ctx.fillStyle = dataset.type == "line" ? "black" : "black";
ctx.save();
ctx.translate(model.x, textY-15);
ctx.rotate(4.7);
ctx.fillText(dataset.data[i], 0, 0);
ctx.restore();
}
}
});
}
}
live code: Link

Try these options:
animation: {
duration: 1,
onComplete: function({ chart }) {
const ctx = chart.ctx;
chart.config.data.datasets.forEach(function(dataset, i) {
const meta = chart.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
const data = dataset.data[index];
ctx.fillText(data, bar.x, bar.y - 5);
});
});
}
}

this works in my case but its show values in mid of the bar.
chart.chart.config.options.animation["onComplete"] = function () {
var ctx = chart.chart.ctx;
ctx.font = '22px "Helvetica Neue", Helvetica, Arial, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function (dataset) {
for (var i = 0; i < dataset.data.length; i++) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model,
scale_max = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._yScale.maxHeight;
ctx.fillStyle = '#444';
var y_pos = model.y + 50;
if ((scale_max - model.y) / scale_max >= 0.5)
y_pos = model.y + 20;
ctx.fillText(dataset.data[i], model.x, y_pos);
}
});
}

var ctx = document.getElementById("myChart");
debugger;
var data = {
labels: ["2 Jan", "9 Jan", "16 Jan", "23 Jan", "30 Jan", "6 Feb", "13 Feb"],
datasets: [{
data: [150, 87, 56, 50, 88, 60, 45],
backgroundColor: "#4082c4"
}]
}
var myChart = new Chart(ctx, {
type: 'bar',
data: data,
options: {
"hover": {
"animationDuration": 0
},
"animation": {
"duration": 1,
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index];
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
legend: {
"display": false
},
tooltips: {
"enabled": false
},
scales: {
yAxes: [{
display: false,
gridLines: {
display: false
},
ticks: {
max: Math.max(...data.datasets[0].data) + 10,
display: false,
beginAtZero: true
}
}],
xAxes: [{
gridLines: {
display: false
},
ticks: {
beginAtZero: true
}
}]
}
}
});

Related

How to add images to chart labels with vue-chartjs?

I want to add flag icons under the country code labels but am completely stuck.
Image of the chart with my current code
The images are named BR.svg, FR.svg and MX.svg and are located under #/assets/icons/flags/
I am using vue#2.6.12 and vue-chartjs#3.5.1 in my project. This is my Chart.vue component:
<script>
import { Bar } from 'vue-chartjs'
export default {
extends: Bar,
data: () => ({
chartdata: {
labels: ['BR', 'FR', 'MX'],
datasets: [
{
label: 'Lorem ipsum',
backgroundColor: '#AF78D2',
data: [39, 30, 30],
}
]
},
options: {
responsive: true,
maintainAspectRatio: false,
legend: {
display: false,
},
tooltips: {
"enabled": false
},
scales : {
xAxes : [ {
gridLines : {
display : false
}
} ],
yAxes: [{
ticks: {
beginAtZero: true,
suggestedMin: 0,
suggestedMax: 40,
stepSize: 5,
}
}]
},
"hover": {
"animationDuration": 0
},
"animation": {
"duration": 1,
"onComplete": function() {
var chartInstance = this.chart,
ctx = chartInstance.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize, Chart.defaults.global.defaultFontStyle, Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
this.data.datasets.forEach(function(dataset, i) {
var meta = chartInstance.controller.getDatasetMeta(i);
meta.data.forEach(function(bar, index) {
var data = dataset.data[index] + '%';
ctx.fillText(data, bar._model.x, bar._model.y - 5);
});
});
}
},
}
}),
mounted () {
this.renderChart(this.chartdata, this.options)
}
}
</script>
This runnable code below is the closest to a solution I have come by hours of searching. But it still won't do the trick because I don't know how to integrate it with what I have.
const labels = ['Red Vans', 'Blue Vans', 'Green Vans', 'Gray Vans'];
const images = ['https://i.stack.imgur.com/2RAv2.png', 'https://i.stack.imgur.com/Tq5DA.png', 'https://i.stack.imgur.com/3KRtW.png', 'https://i.stack.imgur.com/iLyVi.png'];
const values = [48, 56, 33, 44];
new Chart(document.getElementById("myChart"), {
type: "bar",
plugins: [{
afterDraw: chart => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
xAxis.ticks.forEach((value, index) => {
var x = xAxis.getPixelForTick(index);
var image = new Image();
image.src = images[index],
ctx.drawImage(image, x - 12, yAxis.bottom + 10);
});
}
}],
data: {
labels: labels,
datasets: [{
label: 'My Dataset',
data: values,
backgroundColor: ['red', 'blue', 'green', 'lightgray']
}]
},
options: {
responsive: true,
legend: {
display: false
},
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}],
xAxes: [{
ticks: {
padding: 30
}
}],
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="myChart" height="90"></canvas>
When I have added the plugin code into my own code I get an error message saying 'plugins' is already defined in props, but I can't manage to use it somehow.
Anyone who knows how to implement this afterDraw plugin into my code? I appreciate any input.
Thanks a lot in advance! :)
In the mounted of your vue component you can call the addPlugin (has to be done before the renderChart method) like this:
this.addPlugin({
id: 'image-label',
afterDraw: (chart) => {
var ctx = chart.chart.ctx;
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
xAxis.ticks.forEach((value, index) => {
var x = xAxis.getPixelForTick(index);
var image = new Image();
image.src = images[index],
ctx.drawImage(image, x - 12, yAxis.bottom + 10);
});
}
})
Documentation: https://vue-chartjs.org/api/#addplugin
It works in ChartJS version 4.0.1. data needs to return 'plugins':
data() {
return {
plugins: [{
afterDraw: chart => {
const ctx = chart.ctx;
const xAxis = chart.scales['x'];
const yAxis = chart.scales['y'];
xAxis.ticks.forEach((value, index) => {
let x = xAxis.getPixelForTick(index);
ctx.drawImage(images[index], x - 12, yAxis.bottom + 10)
});
}
}],
data: {...
Please note that ctx should be chart.ctx and NOT chart.chart.ctx.. Similarly, it should be chart.scales['x'] and NOT chart.scales['x-axis-0'].
After you return plugins, this needs to be referenced in your Bar component like so..
<Bar :data="data" :options="options" :plugins="plugins"/>

How to plot a single value with line in line chart graph using charts.js?

I need to plot a single value in line chart. Currently i am using charts.JS library for line graph purpose.
The data will be varied some times i'll get the single data inside the data set at that time i need to plot the single value with line in the line chart.
I tried with the charts.js annotation plugin but it wasn't met my requirements. which is like it wis overlapping the plotted point in the graph area.
CODE WHICH I HAD TRIED
createLineChart() {
this.lineChart = new Chart(this.lineCanvas.nativeElement, {
type: "line",
data: {
labels:[],
datasets: [
{
fill: false,
backgroundColor: "#0168FF",
borderColor: "#0168FF",
pointBackgroundColor: "white", // wite point fill
pointBorderWidth: 1, // point border width
lineTension: 0,
pointBorderColor: "blue",
pointRadius: 4,
},
],
},
options: {
scales: {
yAxes: [
{
ticks: {
padding: 20,
beginAtZero: true,
min: 0,
stepSize: 100,
},
gridLines: {
drawBorder: false,
},
},
],
xAxes: [
{
// offset: true,
ticks: {
display: false,
//beginAtZero: true,
min: 0,
},
gridLines: {
zeroLineColor: "transparent",
drawBorder: false,
display: false,
},
//offset:true,
},
],
legend: {
display: false,
},
tooltips: {
enabled: false,
},
},
drawTime: "afterDraw", // (default)
} as ChartOptions,
// plugins: [ChartAnnotation]
},
});
}
To generate dynamic data and plot in the graph area.
generateRandomDataSet(size) {
let yaxisArr = [];
let xaxisArr = [];
let random_data:any = this.getRandomData(size)
let maxYTickVal = Math.max.apply(Math, random_data.map((val) => {return val.yaxis}));
let maxVal = Math.ceil((maxYTickVal+1) / 10) * 10
for(let data of random_data) {
yaxisArr.push(data.yaxis)
xaxisArr.push(data.xaxis)
}
console.log("X-Axis array values : "+xaxisArr)
console.log("Y-Axis array values : "+yaxisArr)
this.lineChart.data.datasets[0].data = yaxisArr
this.lineChart.config.data.labels = []
this.lineChart.config.data.labels = xaxisArr
this.lineChart.config.options.scales.yAxes[0].ticks.max =maxVal
this.lineChart.config.options.scales.yAxes[0].ticks.stepSize = maxVal/2
this.lineChart.update()
}
getRandomData(arraySize) {
let data = []
for(var i=1; i<=arraySize; i++) {
let number = Math.floor(Math.random() * 200) + 1
data.push({'xaxis':i,'yaxis':number})
}
return data
}
with the above code i am getting like
what i need to have
You can define an animation.onComplete function as follows to draw the line in case a single data value is present.
animation: {
onComplete: e => {
var ctx = chart.chart.ctx;
var data = chart.config.data.datasets[0].data;
if (data[0] == null) {
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
var y = yAxis.getPixelForValue(data[1]);
ctx.save();
ctx.globalCompositeOperation='destination-over';
ctx.strokeStyle = 'blue'
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(xAxis.left, y);
ctx.lineTo(xAxis.right, y);
ctx.stroke();
ctx.restore();
}
}
},
This function expects the data array to be of format [null, <value>, null] in case a single value is present, otherwise it will be hard to horizontally center the data point (see this answer). It's up to you to change the generateRandomDataSet() function in a way that it provides such data.
Please have a look at your changed code below.
const chart = new Chart('line-chart', {
type: "line",
data: {
labels: ['', 'A', ''],
datasets: [{
data: [null, 120, null],
fill: false,
backgroundColor: "#0168FF",
borderColor: "#0168FF",
pointBackgroundColor: "white",
pointBorderWidth: 1,
lineTension: 0,
pointBorderColor: "blue",
pointRadius: 4,
}],
},
options: {
legend: {
display: false
},
tooltips: {
enabled: false
},
animation: {
onComplete: e => {
var ctx = chart.chart.ctx;
var data = chart.config.data.datasets[0].data;
if (data[0] == null) {
var xAxis = chart.scales['x-axis-0'];
var yAxis = chart.scales['y-axis-0'];
var y = yAxis.getPixelForValue(data[1]);
ctx.save();
ctx.globalCompositeOperation='destination-over';
ctx.strokeStyle = 'blue'
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(xAxis.left, y);
ctx.lineTo(xAxis.right, y);
ctx.stroke();
ctx.restore();
}
}
},
scales: {
yAxes: [{
ticks: {
padding: 20,
min: 0,
stepSize: 100
},
gridLines: {
drawBorder: false
}
}],
xAxes: [{
ticks: {
display: false
},
gridLines: {
zeroLineColor: "transparent",
drawBorder: false,
display: false
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<canvas id="line-chart" height="80"></canvas>

Label is not showing in ChartJS

I'm using ChartJS for my implementation of charts, but I notice that one of my graph's label is hidden. It is not showing its label above the bar. I've added a screenshot below for the comparison of two different bar graphs. The left graph shows the label even if it is on the very top but the other one is not showing. Please see my screenshot and code below.
function createChart(context, type, bgColor, bdColor, labels, actualData, options = {}){
new Chart(context, {
type: type,
data: {
labels: labels,
datasets: [{
label: "Actual",
backgroundColor: bgColor,
borderColor: bdColor,
data: actualData,
}]
},
options: options
});
}
function getOptions(displayLegend = true){
return {
events: false,
showTooltips: false,
legend: {
display: displayLegend
},
animation: {
duration: 0,
onComplete: function(){
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseLine = 'bottom';
ctx.fillStyle = '#0b7707';
this.data.datasets.forEach(function(dataset){
console.log(dataset);
for(var i = 0; i < dataset.data.length; i++){
for(var key in dataset._meta){
var model = dataset._meta[key].data[i]._model;
ctx.fillText(dataset.data[i], model.x, model.y - 13);
}
}
});
}
}
};
}
I solved this problem by adding an empty title to the chart, so it will create space above the chart and show labels above the bar
options: {
title: {
display: true,
text: ' '
},
....
This looks like a clear case of the datalabels going out of the canvas since the bar takes height dynamically as per the data values. You can set the max y-tick setting to solve this. Here is the jsfiddle -> https://jsfiddle.net/Luaf2tm4/5979/
Hope it helps!
var canvas = document.getElementById('myChart');
var data = {
labels: ["January", "February", "March", "April", "May", "June"],
datasets: [{
label: "My First dataset",
backgroundColor: "rgba(255,99,132,0.2)",
borderColor: "rgba(255,99,132,1)",
borderWidth: 2,
hoverBackgroundColor: "rgba(255,99,132,0.4)",
hoverBorderColor: "rgba(255,99,132,1)",
data: [500, 2000, 800, 600, 950, 890],
}]
};
function getOptions(displayLegend = false) {
return {
events: false,
showTooltips: false,
legend: {
display: displayLegend
},
scales: {
yAxes: [{
display: true,
stacked: true,
ticks: {
stepSize: 200,
min: 0, // minimum value
max: 2200 // maximum value, you can either hard code if you know your datainput, else computer the value through some logic i.e taking the max value from the dataset and adding some extra value to it.
}
}]
},
animation: {
duration: 0,
onComplete: function() {
var ctx = this.chart.ctx;
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontFamily, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseLine = 'bottom';
ctx.fillStyle = '#0b7707';
this.data.datasets.forEach(function(dataset) {
console.log(dataset);
for (var i = 0; i < dataset.data.length; i++) {
for (var key in dataset._meta) {
var model = dataset._meta[key].data[i]._model;
ctx.fillText(dataset.data[i], model.x, model.y - 10);
}
}
});
}
}
};
}
var myBarChart = Chart.Bar(canvas, {
data: data,
options: getOptions()
});

Chart.JS Error: this.scale is undefined

I'm trying since to days and really new to Chart.js. Everything seems to be clear but now i would like to put a label on top of every single bar.
Trying this i get an error: this.scale is undefined. I got the animation.onComplete Snippet out of the net but it seems i make a mistake. The Chart works fine .. i just don't get the labels on top of the bars. Maybe someone can please help me with this ?!
I also have a line chart with the same problem.
var ctx = document.getElementById("chartA").getContext("2d");
Chart.defaults.global.animation.duration = 2400;
Chart.defaults.global.animation.easing = "easeInOutQuad";
Chart.defaults.global.elements.point.radius = 4;
Chart.defaults.global.elements.point.hoverRadius = 5;
Chart.defaults.global.elements.point.hitRadius = 1;
var chart = new Chart(ctx, {
type: "bar",
data: {
labels: ["A","B","C"],
datasets: [{
label: "Test",
backgroundColor: "rgba(255, 99, 132, 0.2)",
borderColor: "#CF2748",
borderWidth: 1,
data: [10,20,30]
}]
},
options: {
tooltips: { mode: 'nearest', intersect: false },
layout: { padding: { left: 20, right: 0, top: 0, bottom: 0 } },
legend: { display: true, position: 'top' },
scales: {
yAxes: [{
ticks: { maxTicksLimit: 9, stepSize: 300, callback: function(value, index, values) { return value+" €"; } }
}]
},
animation: {
onComplete: function () {
var ctx = this.chart.ctx; // this part doesn't work
ctx.font = this.scale.font;
ctx.fillStyle = this.scale.textColor;
ctx.textAlign = "center";
ctx.textBaseline = "bottom";
this.datasets.forEach(function (dataset) {
dataset.bars.forEach(function (bar) {
ctx.fillText(bar.value, bar.x, bar.y - 5);
});
});
}
}
}
});
Thank you so much
Oliver
Thanks #Jeff I was testing around and get closer.
chart.data.datasets.forEach(function (dataset) {
dataset.data.forEach(function (value) {
ctx.fillText(value, x, y);
});
});
Now i have in "value" the right value. But i need to refer X and Y. Where do i get them? If i change X and Y with static value it works but all values were logically printed on the same space.
There are several issues with your code.
You could rather use the following chart plugin to accomplish the same :
Chart.plugins.register({
afterDatasetsDraw: function(chart) {
var ctx = chart.ctx;
chart.data.datasets.forEach(function(dataset, datasetIndex) {
var datasetMeta = chart.getDatasetMeta(datasetIndex);
datasetMeta.data.forEach(function(meta) {
var posX = meta._model.x;
var posY = meta._model.y;
var value = chart.data.datasets[meta._datasetIndex].data[meta._index];
// draw values
ctx.save();
ctx.textBaseline = 'bottom';
ctx.textAlign = 'center';
ctx.font = '16px Arial';
ctx.fillStyle = 'black';
ctx.fillText(value, posX, posY);
ctx.restore();
});
});
}
});
add this plugin at the beginning of your script.
ᴡᴏʀᴋɪɴɢ ᴇxᴀᴍᴘʟᴇ ⧩
Chart.plugins.register({
afterDatasetsDraw: function(chart) {
var ctx = chart.ctx;
chart.data.datasets.forEach(function(dataset, datasetIndex) {
var datasetMeta = chart.getDatasetMeta(datasetIndex);
datasetMeta.data.forEach(function(meta) {
var posX = meta._model.x;
var posY = meta._model.y;
var value = chart.data.datasets[meta._datasetIndex].data[meta._index];
// draw values
ctx.save();
ctx.textBaseline = 'bottom';
ctx.textAlign = 'center';
ctx.font = '16px Arial';
ctx.fillStyle = 'black';
ctx.fillText(value, posX, posY);
ctx.restore();
});
});
}
});
var ctx = document.getElementById("chartA").getContext("2d");
Chart.defaults.global.animation.duration = 2400;
Chart.defaults.global.animation.easing = "easeInOutQuad";
Chart.defaults.global.elements.point.radius = 4;
Chart.defaults.global.elements.point.hoverRadius = 5;
Chart.defaults.global.elements.point.hitRadius = 1;
var chart = new Chart(ctx, {
type: "bar",
data: {
labels: ["A", "B", "C"],
datasets: [{
label: "Test",
backgroundColor: "rgba(255, 99, 132, 0.2)",
borderColor: "#CF2748",
borderWidth: 1,
data: [10, 20, 30]
}]
},
options: {
tooltips: {
mode: 'nearest',
intersect: false
},
layout: {
padding: {
left: 20,
right: 0,
top: 0,
bottom: 0
}
},
legend: {
display: true,
position: 'top'
},
scales: {
yAxes: [{
ticks: {
maxTicksLimit: 9,
stepSize: 300,
callback: function(value, index, values) {
return value + " €";
}
}
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.6.0/Chart.min.js"></script>
<canvas id="chartA"></canvas>

Chartjs hovering over one Chart, shows tooltip across all charts

I am using ChartJS with angular (https://jtblin.github.io/angular-chart.js/)
I am able to get a vertical line in my chart when hovering using How to render a vertical line on hover in chartjs example.
I tried looking for examples of a curved line chart where the X-axis has a shared date range between all charts in DOM, but Y-axis has different values. Hovering over any chart will trigger hover over all available charts and display that vertical line like above with a tool-tip on all charts
tooltips: {
mode: 'x-axis'
},
If I understand what you want correctly, this should do it.
This jsfiddle may be able to help you:
https://jsfiddle.net/vikas12118/k4oveLsb/
var charts = [];
$(document).ready(function () {
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function(ease) {
if (charts) {
for (var i = 0; i < charts.length; i++) {
charts[i].tooltip._active = [];
charts[i].tooltip.update(true);
charts[i].draw();
}
}
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.scales['y-axis-0'].top,
bottomY = this.chart.scales['y-axis-0'].bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#07C';
ctx.stroke();
ctx.restore();
if(charts)
{
showTooltip(chart1.chart.tooltip._active[0]._index);
}
}
}
});
var ctx1 = document.getElementById('myChart1').getContext('2d');
var chart1 = new Chart(ctx1, {
type: 'LineWithLine',
data: {
labels: ['Segment 1', 'Segment 2', 'Segment 3','Segment 4','Segment 5','Segment 6','Segment 7','Segment 8','Segment 9','Segment 10','Segment 11','Segment 12'],
datasets: [{
lineTension: 0,
backgroundColor: "rgb(34,139,34)",
borderColor: "rgb(34,139,34)",
data: [14, 19, 20, 10, 6, 15, 8, 27, 25, 14, 36, 22],
fill: false,
pointRadius: 1.5,
pointHoverRadius: 1,
borderWidth :1.5
}],
},
options: {
maintainAspectRatio: false,
responsive: false,
/*legend: {
display: false
}, s: {
displayColors: false
},*/
hover: {
mode: 'index',
intersect: false,
},
title: {
display: true,
text: ''
},
legend: {
display: false
},
tooltips: {
mode: 'index',
//enabled: false,
intersect: false,
},
}
});
var ctx2 = document.getElementById('myChart2').getContext('2d');
Chart.defaults.LineWithLine = Chart.defaults.line;
Chart.controllers.LineWithLine = Chart.controllers.line.extend({
draw: function(ease) {
Chart.controllers.line.prototype.draw.call(this, ease);
if (this.chart.tooltip._active && this.chart.tooltip._active.length) {
var activePoint = this.chart.tooltip._active[0],
ctx = this.chart.ctx,
x = activePoint.tooltipPosition().x,
topY = this.chart.scales['y-axis-0'].top,
bottomY = this.chart.scales['y-axis-0'].bottom;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = 2;
ctx.strokeStyle = '#07C';
ctx.stroke();
ctx.restore();
}
}
});
var chart = new Chart(ctx2, {
type: 'LineWithLine',
data: {
labels: ['Segment 1', 'Segment 2', 'Segment 3','Segment 4','Segment 5','Segment 6','Segment 7','Segment 8','Segment 9','Segment 10','Segment 11','Segment 12'],
datasets: [{
lineTension: 0,
backgroundColor: "rgb(34,139,34)",
borderColor: "rgb(34,139,34)",
data: [14, 11, 10, 20, 20, 15, 25, 15, 13, 14, 16, 8],
fill: false,
pointRadius: 1.5,
pointHoverRadius: 1,
borderWidth :1.5
}],
},
options: {
maintainAspectRatio: false,
responsive: false,
title: {
display: true,
text: ''
},
legend: {
display: false
},
tooltips: {
mode: 'index',
//enabled: false,
intersect: false,
},
}
});
charts.push(chart)
});
function showTooltip(index) {
if (Array.isArray(charts) && charts.length) {
for (var i = 0; i < charts.length; i++) {
var segment = charts[i].getDatasetMeta(0).data[index];
charts[i].tooltip._active = [segment];
charts[i].tooltip.update(true);
charts[i].draw();
}
}
}
html content
<div>
<canvas style="width: 800px" height="300px" id="myChart1"></canvas></div>
<div>
<canvas style="width: 800px" height="300px" id="myChart2"></canvas></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>

Categories