I'm using Highstocks with data grouping turned on by default.
When handling the "point -> events -> mouseOver" event,
I want to found the exact x-y location of the hovered point.
What I am doing right now is:
// When data is grouped as daily/weekly
tooltip: {
useHTML: true,
hideDelay: 0,
snap: 0,
backgroundColor: 'rgba(255,255,255,1)',
formatter: function() {
let item;
// When zoomed out and data is grouped or graph grouped by day or week
if(this.series.hasGroupedData) {
// let xPos = this.series.xData[Math.round(this.point.clientX)];
// let yPos = this.series.yData[Math.round(this.point.plotY)];
// find the timestamp in the middle of the timestamp grouping
let maxClientX = Math.round(this.series.groupedData[this.series.groupedData.length - 1].clientX);
let point_position_percent = this.point.clientX / maxClientX;
let point_position_index = Math.round(point_position_percent * this.series.xData.length);
let xPos = this.series.xData[point_position_index];
item = _.find(this.series.options.data, {x:xPos});
}
// When zoomed in
else {
item = this.point;
}
let tooltipFormat = this.key+'<table><tr><td><span style="color:{series.color}">\u25CF</span></td><td>'+this.series.name+': </td>' + '<td><b>'+this.y+'</b></td></tr>' +
'<tr><td></td><td>Data 1: </td>' + '<td><b>'+item.data1+'</b></td></tr>' +
'<tr><td></td><td>Data 2: </td>' + '<td><b>'+item.data2+'</b></td></tr>' +
'<tr><td></td><td>Data 3: </td>' + '<td><b>'+item.data3+'</b></td></tr></table>';
return tooltipFormat;
}
}
It works by simply finding the 'percentage' of the point on the X axis, then converting this percentage to the equivalent index in the data set.
Related
I have some information inside the doughnut chart and want to prevent tooltip blinks when this info is accessed with the mouse.
Check out the attached screenshot below:
I am trying to implement the following solution:
Not show the label tooltip if the label hover is less than 1 second.
If the label hover is more than 1 second (i.e. the cursor is stuck on the label for some time) then I need to show the tooltip.
Check out the following JSFiddle
var chart_data = [6,5,4,3,2,1]
function chart() {
var options = {
type: 'doughnut',
data: {
labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange"],
datasets: [{
label: '# of Votes',
data: chart_data,
backgroundColor: [ "Red", "Blue", "Yellow", "Green", "Purple", "Orange" ],
borderWidth: 1,
}
]
},
options: {
cutoutPercentage : 65,
responsive: false,
tooltips: {
callbacks: { label: label_tooltip }
},
}
}
var ctx = document.getElementById('chart-container').getContext('2d')
new Chart(ctx, options)
}
function label_tooltip(item, data) {
var index = item.index
var name = data.labels[index]
var value = data.datasets[0].data[index]
var tooltip = ' ' + name + ' - ' + value
return tooltip
}
chart()
document.getElementById('chart-info').innerHTML = chart_data.reduce((a, b) => a + b, 0) + '<br>TOTAL'
For a custom tooltip you will need to put enabled: false in your tooltips option. I made a quick example that showcases what you want. It shows the custom tooltip after 1 sec by delaying the making of the table. If you go off the element it will remove it imideatly.
Example: https://jsfiddle.net/Leelenaleee/ks3wgvLp/12/
code:
var tttimer;
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;
}
clearTimeout(tttimer);
tttimer = setTimeout(() => {
// Set caret Position
tooltipEl.classList.remove('above', 'below', 'no-transform');
if (tooltip.yAlign) {
tooltipEl.classList.add(tooltip.yAlign);
} else {
tooltipEl.classList.add('no-transform');
}
function getBody(bodyItem) {
return bodyItem.lines;
}
// Set Text
if (tooltip.body) {
var titleLines = tooltip.title || [];
var bodyLines = tooltip.body.map(getBody);
var innerHtml = '<thead>';
titleLines.forEach(function(title) {
innerHtml += '<tr><th>' + title + '</th></tr>';
});
innerHtml += '</thead><tbody>';
bodyLines.forEach(function(body, i) {
var colors = tooltip.labelColors[i];
var style = 'background:' + colors.backgroundColor;
style += '; border-color:' + colors.borderColor;
style += '; border-width: 2px';
var span = '<span class="chartjs-tooltip-key" style="' + style + '"></span>';
innerHtml += '<tr><td>' + span + body + '</td></tr>';
});
innerHtml += '</tbody>';
var tableRoot = tooltipEl.querySelector('table');
tableRoot.innerHTML = innerHtml;
}
var positionY = this._chart.canvas.offsetTop;
var positionX = this._chart.canvas.offsetLeft;
// Display, position, and set styles for font
tooltipEl.style.opacity = 1;
tooltipEl.style.left = positionX + tooltip.caretX + 'px';
tooltipEl.style.top = positionY + tooltip.caretY + 'px';
tooltipEl.style.fontFamily = tooltip._bodyFontFamily;
tooltipEl.style.fontSize = tooltip.bodyFontSize;
tooltipEl.style.fontStyle = tooltip._bodyFontStyle;
tooltipEl.style.padding = tooltip.yPadding + 'px ' + tooltip.xPadding + 'px';
}, 1000)
};
Credits for clearing timer first to make it work go to one of the mainainers of Chart.js
I'm facing some difficulties while trying to implement 'xAxis clickable' column chart. I'm trying to expose additional Pie charts below my column chart, based on user click on one of the element in xAxis.
The way the first graph is build:
function chartBuilder(data) {
if (data.length === 0) {
return null;
}
var categories = [];
var uniqData = [
{name : 'Fatal', data:[], color:'black', stack: 'fatal'},
{name : 'Critical', data:[], color:'red', stack: 'critical'},
];
_.each(data, function (item) {
categories = categories.concat(item.site);
var fatalValue = {};
fatalValue[item.site] = parseFloat(item.fatal || 0);
uniqData[0].data = uniqData[0].data.concat(fatalValue);
var criticalValue = {};
criticalValue[item.site] = parseFloat(item.critical || 0);
uniqData[1].data = uniqData[1].data.concat(criticalValue);
});
var chartConfig = util.basicConfigChart(categories, uniqData);
chartConfig.yAxis.title = {
text: 'Num Of Events'
};
chartConfig.xAxis.labels = {
formatter: function() {
var ret = this.value,
len = ret.length;
if (len > 10) {
ret = '<strong>' + ret.slice(0,ret.indexOf('_')) + '<br/>' + ret.slice(ret.indexOf('_') + 1, len) + '</strong>';
}
if (len > 25) {
ret = ret.slice(0,25) + '...';
}
return '<strong>' + ret + '</strong>';
},
useHTML: true
};
chartConfig.options.tooltip = {
formatter : function () {
return '<strong>' + this.series.name + '</strong>:' + this.point.y + '<br>Total: ' + this.point.total;
}
};
return chartConfig;
}
So basically, what I need is a way to determine which element in xAxis was clicked, and expose below pie charts with data relevant to this element.
If I understand you correctly, you want to add a click event on the xAxis columns. This can be done using a click event
events: {
click: function (event) {
alert(
'x index: ' + event.point.x + ', \n' +
'series.index: ' + event.point.series.index
);
}
}
This event can be added to a specific series, or to the plotOptions to affect all series.
The code above, will make an alert that shows the relevant indexes.
Working example: https://jsfiddle.net/ewolden/xr17pen6/6/
API on click event: https://api.highcharts.com/highcharts/series.column.events.click
Hi I am trying to pass a variable to my tooltip using setData.
Here is a piece of my code explaining how I am setting the chart data, this code doesn't pass the sensorValue to my tooltip yet:
nitrogenDioxide = [];
$.each(data['NO2'], function(key, value) {
nitrogenDioxide.push([value.ts * 1000, value.rating]);
});
chart_2_1.series[0].setData(nitrogenDioxide);
chart_2_1.series[0].update({name:'Nitrogen Dioxide'}, true);
Here is the code I used to create my tooltip:
tooltip: {
shared: true,
useHTML: true,
formatter: function () {
var tooltipcontent = '<b>' + moment.unix((this.points[0].key / 1000)).format("DD/MM/YYYY HH:mm"); + '</b>';
tooltipcontent += '<table style="width:100%">';
$.each(this.points, function () {
console.log(this);
tooltipcontent += '<tr><td>' + this.y.toLocaleString() + '</td></tr>';
tooltipcontent += '<tr><td>' + sensorValue + '</td></tr>';
});
tooltipcontent += '</table>';
return tooltipcontent;
}
}
As you can see I have a variable called sensorValue in my tooltip. In the foreach loop I have a rating value (y-axis) and a sensor value. I want to pass that sensor value to me tooltip.
I have seen multiple ways of doing this online but none of them set the data the way I do, they do it like so:
new Highcharts.Chart( {
...,
series: [ {
name: 'Foo',
data: [
{
y : 3,
myData : 'firstPoint'
},
{
y : 7,
myData : 'secondPoint'
},
{
y : 1,
myData : 'thirdPoint'
}
]
} ]
} );
I have tried something like this but didn't know how to call this extra value in the tooltip:
nitrogenDioxide = [];
$.each(data['NO2'], function(key, value) {
nitrogenDioxide.push([value.ts * 1000, value.rating, value.value]);
});
In the above code I have pushed the sensor value into the nitrogenDioxide[] array.
I have tried my best to explain what I am trying to do, in my head the explanation makes sense but if it doesnt to you please let me know. Thank you in advance for any help.
I hope I understood correctly what is your issue and the demo posted below will be helpful for you.
When an array with an additional value is passed (sensorValue in your case) it can be retrieved inside formatter using this approach:
get hovered point index: this.point.index
use the point index to get additional value from this.series.userOptions.data array
Code:
Highcharts.chart('container', {
tooltip: {
formatter: function() {
var point = this.point,
series = this.series,
pointIndex = point.index,
text,
additionalValue;
text = '<span style="color:' +
this.color + '">\u25CF</span> ' +
series.name +
': <b>' +
this.y +
'</b><br/>';
additionalValue =
series.userOptions.data[pointIndex][2];
text += '<br> Additional value: ' +
additionalValue;
return text;
}
},
series: [{
data: [
[1, 2, 'aaa'], // 'aaa' is an additional value
[2, 5, 'bbb'],
[3, 9, 'ccc']
]
}],
});
Demo:
https://jsfiddle.net/BlackLabel/3g6om1fw/1/
I am trying to include some extra data from my points in the xAxis label of a Highcharts line chart.
I'm creating my points like this. xAxis is 'datetime' type, and I'm using custom tickPositions (this part works fine).
for (row of results) {
var point = {x:Date.parse(row.time), y:row.value, magicNumber:row.ID};
data_series.data.push(point);
chartConfig.xAxis.tickPositions.push(Date.parse(row.time));
}
In the tooltip I'm able to do the following (this works):
tooltip: {
formatter: function() {
return 'ID: ' + this.point.magicNumber + ' Value:' + this.point.y.toFixed(3);
},
},
How do I do the equivalent in the xAxis formatter? Not clear from the docs if this is possible.
xAxis: {
type: 'datetime',
labels: {
rotation: 90,
formatter: function () {
var ID = **What goes here to obtain magicNumber?**
var datetime = new Date(this.value);
return ID.toString() + ' ' + datetime.toISOString();
}
},
tickPositions: []
}
Try this, console.log(this); should give you a hint if my solution doesn't works.
xAxis: {
type: 'datetime',
labels: {
rotation: 90,
formatter: function () {
console.log(this);
var ID = this.chart.series[0].data[this.pos].magicNumber;
var datetime = new Date(this.value);
return ID.toString() + ' ' + datetime.toISOString();
}
},
tickPositions: []
}
Both formatters has different context, so one way out of that is by iterate on every point of your data (inside of the xAxis.labels.formatter function), find the point which has the same x as this.value, and assign it to some variable. It should be enough, but there is a likelihood of a returning empty object, when none of points won't fit to the tick value.
xAxis: {
type: 'datetime',
labels: {
formatter() {
var points = this.chart.userOptions.series[0].data
var sameTimestampPoint = points.filter(p => p.x === this.value)[0]
var magicValue = sameTimestampPoint ? sameTimestampPoint.magicValue : ""
return magicValue + '<br/>' + this.value
}
}
}
Live example: https://jsfiddle.net/2r8z5wny/
I am trying to make the tooltip when it is 100 + and 1000 + Have a symbol after it on the toolbar but also have it so that shared: true. Also on the graph when it is say 2394 I am after it to round it down to 2.39 so the graph is not so large and then on the tool bar it would show 2.39K.
I have tried quite a bit and I am not able to figure this out look all over stack overflow and not found anything.
http://jsfiddle.net/sb7n32zn/22/
This is what i currently have:
tooltip: {
shared: true,
pointFormat: '<span style="color:{series.color}">{series.name}: <b>{point.y:,.2f}</b><br/>',
}
You need to use a tooltip.formatter which and detect values > 1000. Then use Highcharts.numberFormat and convert number.
formatter: function() {
var points = this.points,
each = Highcharts.each,
txt = '<span style="font-size: 10px">' + points[0].key + '</span><br/>',
H = Highcharts,
value,
numericSymbolDetector;
each(points, function(point, i) {
value = point.y;
numericSymbolDetector = Math.abs(point.y);
if (numericSymbolDetector > 1000) {
value = H.numberFormat(value / 1000, 2, '.','' ) + 'k';
}
txt += '<span style="color:' + point.series.color + '">' + point.series.name + ': <b>' + value + '</b><br/>';
});
return txt;
}
Example:
http://jsfiddle.net/k8783k80/