Show label for every data point in line chart - chart.js

I use a line chart rendered by Chart.js. I use multiple datasets whereas dataset consists of one data point (x,y) only (given from the business domain).
The chart displays the information about each point (x,y,label) when hovering it, however I'd like to have a label next to each point by default/everytime that shows the respective label.
I could not find any solution during my research.
Any pointers? Is that actually possible to achieve with Chart.js?

It is possible to do this with chart.js using the plugins API. Here is an example of a plugin that I use in production to show labels for all data points when the chart renders.
Note, I currently only use bar charts so you might have to tweak some things for line charts. As you will also see, I added a new options property called showDatapoints that I can set to true in order to use the plugin on certain graphs.
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);
}
});
}
}
});

Related

Chart JS pass in custom data for points

I am trying to create a line chart plugin that will draw reference letters under some points. To do so, the plugin uses a custom afterDatasetsDraw function to perform the drawing. However, I am unable to find a way to pass in the reference letters for the desired points. Below is an example of what I'm trying to achieve with the red circled letters.
Does anyone have an idea on how to pass in the reference letters for the corresponding points?
Thanks.
I would just define some configuration properties for your new plugin and use one of those properties to define where the point reference should be located and what the reference value should be.
Here is an example of what I mean. This would be in the chart's options property.
pointReferenceLetters: {
display: true,
fontColor: 'green',
references: [
{datasetIndex: 0, dataIndex: 1, reference: 'A'},
{datasetIndex: 1, dataIndex: 2, reference: 'B'},
]
}
The plugin would then use this data to draw the point references. Here is an example showing how a plugin would use this data. Note, I just did a quick implementation to show the concept, this plugin does not draw the reference circle like yours would.
Chart.plugins.register({
afterDraw: function(chartInstance) {
if (chartInstance.config.options.pointReferenceLetters || chartInstance.config.options.pointReferenceLetters.display) {
var references = chartInstance.config.options.pointReferenceLetters.references || [];
var helpers = Chart.helpers;
var ctx = chartInstance.chart.ctx;
var fontColor = helpers.getValueOrDefault(chartInstance.config.options.pointReferenceLetters.fontColor, chartInstance.config.options.defaultFontColor);
// render the value of the chart above the bar
ctx.font = Chart.helpers.fontString(Chart.defaults.global.defaultFontSize + 5, 'normal', Chart.defaults.global.defaultFontFamily);
ctx.textAlign = 'center';
ctx.textBaseline = 'bottom';
ctx.fillStyle = fontColor;
chartInstance.data.datasets.forEach(function (dataset, dsindex) {
for (var i = 0; i < dataset.data.length; i++) {
// note, many browsers don't support the array.find() function.
// if you use this then be sure to provide a pollyfill
var refPoint = references.find(function(e) {
return e.datasetIndex == dsindex && e.dataIndex === i
});
if (refPoint) {
var model = dataset._meta[Object.keys(dataset._meta)[0]].data[i]._model;
ctx.fillText(refPoint.reference, model.x, model.y + 30);
}
}
});
}
}
});
As you an see, the plugin uses the data provided in the pointReferenceLetters.references property to determine when a point reference should be drawn and then uses the values provided as the reference text.
Here is a codepen example that demonstrates all of this.

How to get access to Chart instance related to current tooltip callback in Chart.js

I am trying to display percentage value inside doughnut chart. To my feature work properly i need to have access to chart instance inside callback. I don't know how to do that?
I handled that using Chart.pluginService beforeDraw event but it doesn't work as I expected.
Is there any way to move code from beforeDraw event inside tooltip callback ?
This is my code
tooltips: {
callbacks: {
label: function (tooltipItem, data) {
var precentage = dataFromDoughnutChart;
localStorage.setItem("per", precentage.toString());
return precentage + "%";
}
}
}
Chart.pluginService.register({
beforeDraw: function (chart) {
var value = "";
var x = localStorage.getItem("per");
if (x != null)
value = x + "%";
var width = chart.chart.width,
height = chart.chart.height,
ctx = chart.chart.ctx;
ctx.restore();
var fontSize = (height / 100).toFixed(2);
ctx.font = fontSize + "em sans-serif";
ctx.textBaseline = "middle";
var text = value,
textX = Math.round((width - ctx.measureText(text).width) / 2),
textY = height / 2;
ctx.fillText(text, textX, textY);
ctx.save();
},
afterEvent: function (chart, event) {
if (event.type == "mouseout") {
localStorage.removeItem("per");
}
}
});
I think the best approach to solving your problem is to actually use custom tooltips instead of attempting a plugin. Here is a working solution that I modified from one of the chart.js sample pages in their repo.
First define a container for the custom tooltip in yout HTML.
<div id="chartjs-tooltip"></div>
Then use the below custom tooltip function. You might have to tweak the centerX calculation for your needs. This function basically calculates the percentage value of the currently active slice (by dividing the datapoint by the total value of datapoints), places it in the custom tooltip div, and positions the div in the center of the doughnut.
Chart.defaults.global.tooltips.custom = function(tooltip) {
// Tooltip Element
var tooltipEl = document.getElementById('chartjs-tooltip');
// Hide if no tooltip
if (tooltip.opacity === 0) {
tooltipEl.style.opacity = 0;
return;
}
// Set Text
if (tooltip.body) {
var total = 0;
// get the value of the datapoint
var value = this._data.datasets[tooltip.dataPoints[0].datasetIndex].data[tooltip.dataPoints[0].index].toLocaleString();
// calculate value of all datapoints
this._data.datasets[tooltip.dataPoints[0].datasetIndex].data.forEach(function(e) {
total += e;
});
// calculate percentage and set tooltip value
tooltipEl.innerHTML = '<h1>' + (value / total * 100) + '%</h1>';
}
// calculate position of tooltip
var centerX = (this._chartInstance.chartArea.left + this._chartInstance.chartArea.right) / 2;
var centerY = ((this._chartInstance.chartArea.top + this._chartInstance.chartArea.bottom) / 2);
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.left = centerX + 'px';
tooltipEl.style.top = centerY + 'px';
tooltipEl.style.fontFamily = tooltip._fontFamily;
tooltipEl.style.fontSize = tooltip.fontSize;
tooltipEl.style.fontStyle = tooltip._fontStyle;
tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
};
Here is the full end-to-end working example via codepen:
Chart.js Doughnut Center Percentage

how to show bar value on the top of each bar in chartjs

I'm using Chartjs to draw some bar charts, I would like to show on the top of each bar the related value, I have not seen any parameters allowing to do that in the documentation.
Is there any way to do that?
You can try
onAnimationComplete: function () {
var ctx = this.chart.ctx;
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);
});
})
}
used following link
http://jsfiddle.net/TZq6q/304/
set "inGraphDataShow: true" in your code it will display all values on top of bar

Changing positions of things during animation

If I have a transform translate thats animating something vertically between say 0 -> 1000, over 5 seconds, is there a way if I have click events to change the horizontal position without interrupting the vertical animation?
p.setTransform(Transform.translate(20,1000,0),
{
duration: 5000,
curve: 'linear'
});
then on some random click, I want to start changing the x position over 100ms or so, and it might have multiple of these before the 5000 duration has finished
I can play with the origin and animate that independently, but I really need pixel control. So is there a way to animate just the x?
If I add a setTransform, it chains after the first one rather than concurrently.
Yes, you most certainly can achieve this. You will want to use a ModifierChain. ModifierChain allows you to chain your modifiers together and control the transforms independently. Check out this example..
Hope this helps!
var Engine = require('famous/core/Engine');
var Surface = require('famous/core/Surface');
var StateModifier = require('famous/modifiers/StateModifier');
var Transform = require('famous/core/Transform');
var ModifierChain = require('famous/modifiers/ModifierChain');
var Easing = require('famous/transitions/Easing');
var context = Engine.createContext();
var surface = new Surface({
size:[200,200],
properties: { backgroundColor:'green' }
});
surface.yState = new StateModifier();
surface.xState = new StateModifier();
var x = 0;
var y = context.getSize()[1] - 200;
surface.on('click',function(){
x += 100;
surface.xState.halt();
surface.xState.setTransform(Transform.translate(x,0,0),{duration:200});
});
surface.chain = new ModifierChain();
surface.chain.addModifier(surface.yState);
surface.chain.addModifier(surface.xState);
context.add(surface.chain).add(surface);
surface.yState.setTransform(Transform.translate(0,y,0), {duration:5000});

Column chart not showing all legends

I'm trying to do a chart using google api, but i have a problem on the bottom of the chart, because i want to show all bars with they respective numbers, there is my code.
I need to describe all the bars with they respective "legends".
var data = new google.visualization.DataTable();
data.addColumn("number", "x");
data.addColumn("number", "y");
for (var i = 0; i < response.x.length; i++) {
data.addRows([[response.x[i], response.y[i]]]);
}
var options = {
colors: ["#30c0cd", "#ee5f3e"],
title: "title"
};
var chart = new google.visualization.ColumnChart($("#dholder")[0]);
chart.draw(data, options);
If your x and y axis are continuous (and not discrete) the google chart api will try to find the best values and will not show every label. Try:
data.addColumn("string", "x");