I'm using ChartJs library in my project and i was trying to show the tooltip of a pie chart both on slice hover or on legend hover, by default the library shows only tooltip on slice hover,
i was trying to do the following onHover function
onHover: function (event, legendItem) {
var index = legendItem.datasetIndex;
var label = this.chart.data.datasets[index].label
return label;
}
But the following function still had no effects..
The whole code of the chart config is the following:
optionsPagamenti = {
maintainAspectRatio: false,
legend: {
display: true,
position: "right",
labels: {
usePointStyle: true,
boxWidth: 6
},
onHover: function (event, legendItem) {
var index = legendItem.datasetIndex;
var label = this.chart.data.datasets[index].label
return label;
}
},
tooltips: {
backgroundColor: '#f5f5f5',
titleFontColor: '#333',
bodyFontColor: '#666',
bodySpacing: 4,
xPadding: 12,
intersect: 1,
displayColors: false,
callbacks: {
title: function (tooltipItem, data) {
return data['labels'][tooltipItem[0]['index']];
},
label: function (tooltipItem, data) {
return "€" + data['datasets'][0]['data'][tooltipItem['index']].toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,').replace(/[,.]/g, m => (m === ',' ? '.' : ','));
}
}
},
responsive: true,
};
So how could i show the tooltip on legend hover?
Solved with the following method:
onHover: function (event, legendItem) {
var chart = this.chart;
var index = legendItem.index;
var segment = chart.getDatasetMeta(0).data[index];
chart.tooltip._active = [segment]
chart.tooltip.update()
chart.draw()
}
And i've also added a onLeave method to toggle off the tooltip
onLeave: function (event, legendItem) {
var chart = this.chart;
var index = legendItem.index;
chart.tooltip._active = []
chart.tooltip.update()
chart.draw()
}
Related
I recently came across this really nice example: https://jsfiddle.net/BlackLabel/7t59w4po/
Basically, what it does is that it synchronizes the drag of a line in one graph in all the other graphs.
I was wondering if someone could help me out to reproduce the same example, but instead of one vertical line, I would like to have two. Is this possible?
Thank you!
JS Code:
/*
The purpose of this demo is to demonstrate how multiple charts on the same page
can be linked through DOM and Highcharts events and API methods. It takes a
standard Highcharts config with a small variation for each data set, and a
mouse/touch event handler to bind the charts together.
*/
/**
* In order to synchronize tooltips and crosshairs, override the
* built-in events with handlers defined on the parent element.
*/
['mousemove', 'touchmove', 'touchstart'].forEach(function(eventType) {
document.getElementById('container').addEventListener(
eventType,
function(e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
// Find coordinates within the chart
event = chart.pointer.normalize(e);
// Get the hovered point
point = chart.series[0].searchPoint(event, true);
if (point) {
point.highlight(e);
}
}
}
);
});
/**
* Override the reset function, we don't need to hide the tooltips and
* crosshairs.
*/
Highcharts.Pointer.prototype.reset = function() {
return undefined;
};
/**
* Highlight a point by showing tooltip, setting hover state and draw crosshair
*/
Highcharts.Point.prototype.highlight = function(event) {
event = this.series.chart.pointer.normalize(event);
this.onMouseOver(); // Show the hover marker
this.series.chart.tooltip.refresh(this); // Show the tooltip
this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
};
/**
* Synchronize zooming through the setExtremes event handler.
*/
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(
e.min,
e.max,
undefined,
false, {
trigger: 'syncExtremes'
}
);
}
}
});
}
}
/**
* Synchronize annotations drag&drop
*/
function syncAnnotations(e) {
var thisChart = this.chart;
var newX = this.options.shapes[0].points[0].x
if (e.type !== 'afterUpdate') {
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
chart.annotations[0].update({
labels: [{
point: {
x: newX
}
}],
shapes: [{
points: [{
x: newX,
xAxis: 0,
y: 0
}, {
x: newX,
xAxis: 0,
y: 1000
}]
}]
});
}
});
}
}
// Get the data. The contents of the data file can be viewed at
Highcharts.ajax({
url: 'https://cdn.jsdelivr.net/gh/highcharts/highcharts#v7.0.0/samples/data/activity.json',
dataType: 'text',
success: function(activity) {
activity = JSON.parse(activity);
activity.datasets.forEach(function(dataset, i) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function(val, j) {
return [activity.xData[j], val];
});
var chartDiv = document.createElement('div');
chartDiv.className = 'chart';
document.getElementById('container').appendChild(chartDiv);
Highcharts.chart(chartDiv, {
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} km'
}
},
yAxis: {
title: {
text: null
}
},
annotations: [{
draggable: 'x',
animation: {
defer: false
},
events: {
drag: syncAnnotations,
afterUpdate: syncAnnotations
},
shapes: [{
strokeWidth: 3,
type: 'path',
points: [{
x: 3,
y: 0,
xAxis: 0
}, {
x: 3,
y: 1000,
xAxis: 0
}]
}],
labels: [{
point: {
x: 3,
y: 30,
xAxis: 0
},
shape: 'rect',
formatter: function(e) {
// Use shape options because value is available there. Label use translation only
return this.target.annotation.shapes[0].options.points[0].x.toFixed(3);
}
}]
}],
tooltip: {
positioner: function() {
return {
// right aligned
x: this.chart.chartWidth - this.label.width,
y: 10 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
}
});
You only need to add another annotation:
annotations: [{
...,
{
...
}],
And improve the syncAnnotations function a little bit:
function syncAnnotations(e) {
var thisChart = this.chart;
var newX = this.options.shapes[0].points[0].x
var index = this.chart.annotations.indexOf(this);
if (e.type !== 'afterUpdate') {
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
chart.annotations[index].update({
...
});
}
});
}
}
Live demo: https://jsfiddle.net/BlackLabel/jwtLc379/
API Reference: https://api.highcharts.com/highcharts/annotations
How to enforce that the tooltip show up only when mouse pointer is inside the chart area and not when on navigator scrollbar or on time range selectors in the top?
http://jsfiddle.net/1p4f5kny/
/*
The purpose of this demo is to demonstrate how multiple charts on the same page can be linked
through DOM and Highcharts events and API methods. It takes a standard Highcharts config with a
small variation for each data set, and a mouse/touch event handler to bind the charts together.
*/
$(function () {
/**
* In order to synchronize tooltips and crosshairs, override the
* built-in events with handlers defined on the parent element.
*/
$('#container').bind('mousemove touchmove touchstart', function (e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
event = chart.pointer.normalize(e.originalEvent); // Find coordinates within the chart
point = chart.series[0].searchPoint(event, true); // Get the hovered point
if (point) {
point.highlight(e);
}
}
});
/**
* Override the reset function, we don't need to hide the tooltips and crosshairs.
*/
Highcharts.Pointer.prototype.reset = function () {
return undefined;
};
/**
* Highlight a point by showing tooltip, setting hover state and draw crosshair
*/
Highcharts.Point.prototype.highlight = function (event) {
this.onMouseOver(); // Show the hover marker
this.series.chart.tooltip.refresh(this); // Show the tooltip
this.series.chart.xAxis[0].drawCrosshair(event, this); // Show the crosshair
};
/**
* Synchronize zooming through the setExtremes event handler.
*/
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function (chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, { trigger: 'syncExtremes' });
}
}
});
}
}
// Get the data. The contents of the data file can be viewed at
// https://github.com/highcharts/highcharts/blob/master/samples/data/activity.json
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=activity.json&callback=?', function (activity) {
$.each(activity.datasets, function (i, dataset) {
// Add X values
/*dataset.data = Highcharts.map(dataset.data, function (val, j) {
return [activity.xData[j], val];
});*/
$('<div class="chart">')
.appendTo('#container')
.highcharts('StockChart', {
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} km'
}
},
yAxis: {
title: {
text: null
}
},
tooltip: {
positioner: function () {
return {
x: this.chart.chartWidth - this.label.width, // right aligned
y: -1 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
shared: false,
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
});
});
Insted of binding events on the container, you can use point mouseOver event to synchronize tooltips:
series: [{
point: {
events: {
mouseOver: function(e) {
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
if (chart !== this.series.chart) {
point = chart.series[0].points[this.index];
chart.tooltip.refresh([point]);
}
}
}
}
},
...
}]
Live demo: http://jsfiddle.net/BlackLabel/g0brx52d/
API Reference: https://api.highcharts.com/highcharts/series.line.point.events.mouseOver
I have two functions. FunctionToChangeBarChart and getPreviousDayValues. I want to draw jqPlot barchart in each function. So i wrote code for drawing bar chart in a fuction LoadBarChart and called this function both FunctionToChangeBarChart and getPreviousDayValues functoins. The problem is that the bar chart redraws, one over another, in each function call.
how can i refresh the bar chart?
FunctionToChangeBarChart = function(event){
var totalNoUsers = 10;
var tempStart = 4;
var pendingTaskCount = 7;
var completedTaskCount = 2;
LoadBarChart(totalNoUsers,tempStart,pendingTaskCount,completedTaskCount);
});
getPreviousDayValues = function(Event){
var totalUsers = 20;
var tempStart = 4;
var pendingTaskCount = 9;
var completedTaskCount = 3;
LoadBarChart(totalUsers,tempStart,pendingTaskCount,completedTaskCount);
}
function LoadBarChart(total,start,pending,complete,todayVal){
var s1 = [total, start, pending, complete];
var ticks = ['total', 'started', 'pending','completed' ];
plot1 = $.jqplot('chart1', [s1], {
animate: !$.jqplot.use_excanvas,
seriesDefaults:{
renderer:$.jqplot.BarRenderer,
rendererOptions: {barMargin: 0 , varyBarColor : true},
pointLabels: { show: true }
},
title:{text:"Task Status and Users"},
grid: {
background: 'transparent', // CSS color spec for background color of grid.
drawBorder:false,
drawGridlines:false,
shadow:false
},
axes: {
xaxis: {
renderer: $.jqplot.CategoryAxisRenderer,
ticks: ticks,
tickOptions : {
// showGridline : false
}
},
yaxis: {
tickOptions : {
// showGridline : false
},
// label:'Status',
labelRenderer: $.jqplot.CanvasAxisLabelRenderer
}
},
seriesColors: [ "#000", "#ccc", "red","green"],
highlighter: { show: false }
});
$('#chart1').bind('jqplotDataClick',
function (ev, seriesIndex, pointIndex, data) {$('#info1').html('series: '+seriesIndex+', point: '+pointIndex+', data: '+data);
});
}
I am using Synchronized chart of Highcharts to demonstrate the statistics.
For reference : http://www.highcharts.com/demo/synchronized-charts.
Here, when the chart is getting plotted for the first time, no data points is selected. As, the cursor enters into the chart area, the tooltip, crosshairs and data points get highlighted. It works as expected.
The modification I need is, when the user comes out of the chart, the chart should look like as it was in the loading stage.
i.e. If the cursor is not on any of the chart,then no data points should remain selected. In other words, the tooltip, crosshair and the highlighted shadow on data point should get removed.
Thanks in advance for any help or suggestion.
use mouseleave to detect when the mouse is out of the container:
$('#container').bind('mouseleave', function(e) {
use hide method to hide the tooltip and hide Crosshair method to hide the crosshair:
chart.tooltip.hide(point);
chart.xAxis[0].hideCrosshair();
Check the example (jsfiddle):
$(function() {
$('#container').bind('mouseleave', function(e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
event = chart.pointer.normalize(e.originalEvent);
point = chart.series[0].searchPoint(event, true);
point.onMouseOut();
chart.tooltip.hide(point);
chart.xAxis[0].hideCrosshair();
}
});
$('#container').bind('mousemove touchmove touchstart', function(e) {
var chart,
point,
i,
event;
for (i = 0; i < Highcharts.charts.length; i = i + 1) {
chart = Highcharts.charts[i];
event = chart.pointer.normalize(e.originalEvent); // Find coordinates within the chart
point = chart.series[0].searchPoint(event, true); // Get the hovered point
if (point) {
point.onMouseOver(); // Show the hover marker
chart.tooltip.refresh(point); // Show the tooltip
chart.xAxis[0].drawCrosshair(event, point); // Show the crosshair
}
}
});
/**
* Override the reset function, we don't need to hide the tooltips and crosshairs.
*/
Highcharts.Pointer.prototype.reset = function() {
return undefined;
};
/**
* Synchronize zooming through the setExtremes event handler.
*/
function syncExtremes(e) {
var thisChart = this.chart;
if (e.trigger !== 'syncExtremes') { // Prevent feedback loop
Highcharts.each(Highcharts.charts, function(chart) {
if (chart !== thisChart) {
if (chart.xAxis[0].setExtremes) { // It is null while updating
chart.xAxis[0].setExtremes(e.min, e.max, undefined, false, {
trigger: 'syncExtremes'
});
}
}
});
}
}
// Get the data. The contents of the data file can be viewed at
// https://github.com/highcharts/highcharts/blob/master/samples/data/activity.json
$.getJSON('https://www.highcharts.com/samples/data/jsonp.php?filename=activity.json&callback=?', function(activity) {
$.each(activity.datasets, function(i, dataset) {
// Add X values
dataset.data = Highcharts.map(dataset.data, function(val, j) {
return [activity.xData[j], val];
});
$('<div class="chart">')
.appendTo('#container')
.highcharts({
chart: {
marginLeft: 40, // Keep all charts left aligned
spacingTop: 20,
spacingBottom: 20
},
title: {
text: dataset.name,
align: 'left',
margin: 0,
x: 30
},
credits: {
enabled: false
},
legend: {
enabled: false
},
xAxis: {
crosshair: true,
events: {
setExtremes: syncExtremes
},
labels: {
format: '{value} km'
}
},
yAxis: {
title: {
text: null
}
},
tooltip: {
positioner: function() {
return {
x: this.chart.chartWidth - this.label.width, // right aligned
y: -1 // align to title
};
},
borderWidth: 0,
backgroundColor: 'none',
pointFormat: '{point.y}',
headerFormat: '',
shadow: false,
style: {
fontSize: '18px'
},
valueDecimals: dataset.valueDecimals
},
series: [{
data: dataset.data,
name: dataset.name,
type: dataset.type,
color: Highcharts.getOptions().colors[i],
fillOpacity: 0.3,
tooltip: {
valueSuffix: ' ' + dataset.unit
}
}]
});
});
});
});
I have two bar charts, one of them shows top ten categories, the other one shows min ten categories.
There is no problem with top ten bar chart, but I use the very same code to draw min ten bar chart that I used in top ten bar chart, but here is the result.
This is top ten:
And this is min ten:
As you can see above image, min ten chart's bars look like damaged and labels below the bars can't be seen.
And here is the codes that produce these results:
MinTen produced html which feeds the bar chart:
var initCatMinTenBarChart = function ()
{
var dataMin = new Array();
var ticks = [[0, 'Kozmetik'],[1, 'Ev&Yaşam'],[2, 'Cep Telefonu'],[3, 'Ayakkabı'],[4, 'Bilgisayar'],[5, 'Beyaz Eşya']];var labels = ['Kozmetik','Ev&Yaşam','Cep Telefonu','Ayakkabı','Bilgisayar','Beyaz Eşya'];var minTenCat_d1 = 18;var minTenCat_d2 = 12;var minTenCat_d3 = 8;var minTenCat_d4 = 7;var minTenCat_d5 = 6;var minTenCat_d6 = 4;
var isempty = false;
var d_min_ten_cat_bar = [[0,18],[1,12],[2,8],[3,7],[4,6],[5,4]];
dataMin.push({
label: labels,
data: d_min_ten_cat_bar,
bars: {
show: true,
barWidth: 0.2,
order: 1
}
});
if (!isempty) {
$.plot("#MinTenCatBarChart", dataMin, $.extend(true, {}, Plugins.getFlotDefaults(), {
legend: {
show: false
},
series: {
lines: { show: false },
points: { show: false }
},
grid: {
hoverable: true,
clickable: true
},
tooltip: true,
tooltipOpts: {
content: function (label, x, y) { return 'İçerik Sayısı: ' + y; }
},
bars: {
align: "center",
barWidth: 0.1
},
xaxis: {
align: "center",
ticks: ticks
},
yaxis: {
tickLength: 0
}
}));
}
}
TopTen produced html data which feeds the bar chart:
var initCatTopTenBarChart = function ()
{
var dataTop = new Array();
var ticks = [[0, 'Kozmetik'],[1, 'Ev&Yaşam'],[2, 'Cep Telefonu'],[3, 'Ayakkabı'],[4, 'Bilgisayar'],[5, 'Beyaz Eşya']];var labels = ['Kozmetik','Ev&Yaşam','Cep Telefonu','Ayakkabı','Bilgisayar','Beyaz Eşya'];var topTenCat_d1 = 18;var topTenCat_d2 = 12;var topTenCat_d3 = 8;var topTenCat_d4 = 7;var topTenCat_d5 = 6;var topTenCat_d6 = 4;
var isempty = false;
var d_top_ten_cat_bar = [[0,18],[1,12],[2,8],[3,7],[4,6],[5,4]];
dataTop.push({
label: labels,
data: d_top_ten_cat_bar,
bars: {
show: true,
barWidth: 0.2,
order: 1
}
});
if (!isempty) {
$.plot("#TopTenCatBarChart", dataTop, $.extend(true, {}, Plugins.getFlotDefaults(), {
legend: {
show: false
},
series: {
lines: { show: false },
points: { show: false }
},
grid: {
hoverable: true,
clickable: true
},
tooltip: true,
tooltipOpts: {
content: function (label, x, y) { return 'İçerik Sayısı: ' + y; }
},
bars: {
align: "center",
barWidth: 0.1
},
xaxis: {
align: "center",
ticks: ticks
},
yaxis: {
tickLength: 0
}
// tick olasyına bak 0,10 arası işlemez burda max-min şeyapmak lazım
}));
}
}
Maybe the positioning is off because of when the chart is being rendered? Try drawing the charts only once their corresponding tab is selected and visible.