I am having issue with the default tooltip that chartjs provides as I can not add html inside the tooltips. I had been looking at how i can add the html/jsx inside the tooltip. I see an example with using customized tooltips here Chart JS Show HTML in Tooltip.
can someone point me an example how to achieve the same with react-chartjs-2 library?
You have to use the custom callback in the tooltip property to define your own positioning and set the hovered dataset in the component state
state = {
top: 0,
left: 0,
date: '',
value: 0,
};
_chartRef = React.createRef();
setPositionAndData = (top, left, date, value) => {
this.setState({top, left, date, value});
};
render() {
chartOptions = {
"tooltips": {
"enabled": false,
"mode": "x",
"intersect": false,
"custom": (tooltipModel) => {
// if chart is not defined, return early
chart = this._chartRef.current;
if (!chart) {
return;
}
// hide the tooltip when chartjs determines you've hovered out
if (tooltipModel.opacity === 0) {
this.hide();
return;
}
const position = chart.chartInstance.canvas.getBoundingClientRect();
// assuming your tooltip is `position: fixed`
// set position of tooltip
const left = position.left + tooltipModel.caretX;
const top = position.top + tooltipModel.caretY;
// set values for display of data in the tooltip
const date = tooltipModel.dataPoints[0].xLabel;
const value = tooltipModel.dataPoints[0].yLabel;
this.setPositionAndData({top, left, date, value});
},
}
}
return (
<div>
<Line data={data} options={chartOptions} ref={this._chartRef} />
{ this.state.showTooltip
? <Tooltip style={{top: this.state.top, left: this.state.left}}>
<div>Date: {this.state.date}</div>
<div>Value: {this.state.value}</div>
</Tooltip>
: null
}
</div>
);
}
You can use the tooltips supplied by React Popper Tooltip or roll your own - pass the top and left to the tooltip for positioning, and the date and value (in my example) should be used to show the data in the tooltip.
If anyone looking answer customization of tooltip and gradient chart here is my code:
My Packages:
"react": "^17.0.2"
"chart.js": "^3.7.1"
"react-chartjs-2": "^4.1.0"
"tailwindcss": "^3.0.23"
ToopTip Component:
import React, { memo } from "react";
import { monetarySuffix } from "#src/helpers/util";
// tooltip.js
const GraphTooltip = ({ data, position, visibility }) => {
return (
<div
className={`absolute px-4 py-3.5 rounded-lg shadow-lg bg-chart-label-gradient text-white overflow-hidden transition-all duration-300 hover:!visible
${visibility ? "visible" : "invisible"}
`}
style={{
top: position?.top,
left: position?.left,
}}
>
{data && (
<>
<h5 className="w-full mb-1.5 block text-[12px] uppercase">
{data.title}
</h5>
<ul className="divide-y divide-gray-100/60">
{data.dataPoints.map((val, index) => {
return (
<li
key={index}
className="m-0 py-1.5 text-base font-rubik font-medium text-left capitalize last:pb-0"
>
{val?.dataset.label}
{":"} {monetarySuffix(val?.raw)}
</li>
);
})}
</ul>
</>
)}
</div>
);
};
export default memo(GraphTooltip);
Chart Component
import React, { useMemo, useState, useRef, useCallback } from 'react';
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
Filler,
} from 'chart.js';
import { Line } from 'react-chartjs-2';
import GraphTooltip from './chart-tooltip';
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
Filler
);
const GradientChart = () => {
const [tooltipVisible, setTooltipVisible] = useState(false);
const [tooltipData, setTooltipData] = useState(null);
const [tooltipPos, setTooltipPos] = useState(null);
const chartRef = useRef(null);
const data = {
labels: [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'Agust',
'September',
'October',
'November',
'December',
],
datasets: [
{
fill: true,
backgroundColor: (context) => {
const chart = context.chart;
const { ctx, chartArea } = chart;
if (!chartArea) {
return;
}
return createGradient(
ctx,
chartArea,
'#F46079',
'#F46079',
'rgba(255,255,255,0)'
);
},
borderColor: '#F46079',
lineTension: 0.4,
pointRadius: 5,
pointHoverRadius: 10,
pointBackgroundColor: '#FE5670',
pointBorderColor: '#ffffff',
pointBorderWidth: 1.5,
label: 'Sales',
data: [
4500, 2800, 4400, 2800, 3000, 2500, 3500, 2800, 3000, 4000, 2600,
3000,
],
},
{
fill: true,
backgroundColor: (context) => {
const chart = context.chart;
const { ctx, chartArea } = chart;
if (!chartArea) {
return;
}
return createGradient(
ctx,
chartArea,
'#2f4b7c',
'#2f4b7c',
'rgba(255,255,255,0)'
);
},
borderColor: '#2f4b7c',
lineTension: 0.4,
pointRadius: 5,
pointHoverRadius: 10,
pointBackgroundColor: '#FE5670',
pointBorderColor: '#ffffff',
pointBorderWidth: 1.5,
label: 'Commision',
data: [
5000, 3500, 3000, 5500, 5000, 3500, 6000, 1500, 2000, 1800, 1500,
2800,
],
},
{
fill: true,
backgroundColor: (context) => {
const chart = context.chart;
const { ctx, chartArea } = chart;
if (!chartArea) {
return;
}
return createGradient(
ctx,
chartArea,
'#665191',
'#665191',
'rgba(255,255,255,0)'
);
},
borderColor: '#665191',
lineTension: 0.4,
pointRadius: 5,
pointHoverRadius: 10,
pointBackgroundColor: '#FE5670',
pointBorderColor: '#ffffff',
pointBorderWidth: 1.5,
label: 'Transaction',
data: [
1000, 2000, 1500, 2000, 1800, 1500, 2800, 2800, 3000, 2500, 3500,
2800,
],
},
],
};
const createGradient = (ctx, chartArea, c1, c2, c3) => {
const chartWidth = chartArea.right - chartArea.left;
const chartHeight = chartArea.bottom - chartArea.top;
const gradient = '';
const width = '';
const height = '';
if (!gradient || width !== chartWidth || height !== chartHeight) {
width = chartWidth;
height = chartHeight;
gradient = ctx.createLinearGradient(
0,
chartArea.bottom,
0,
chartArea.top
);
gradient.addColorStop(0, c3);
gradient.addColorStop(0.5, c2);
gradient.addColorStop(1, c1);
}
return gradient;
};
const customTooltip = useCallback((context) => {
if (context.tooltip.opacity == 0) {
// hide tooltip visibilty
setTooltipVisible(false);
return;
}
const chart = chartRef.current;
const canvas = chart.canvas;
if (canvas) {
// enable tooltip visibilty
setTooltipVisible(true);
// set position of tooltip
const left = context.tooltip.x;
const top = context.tooltip.y;
// handle tooltip multiple rerender
if (tooltipPos?.top != top) {
setTooltipPos({ top: top, left: left });
setTooltipData(context.tooltip);
}
}
});
const options = useMemo(() => ({
responsive: true,
scales: {
y: {
grid: {
display: false,
},
},
},
interaction: {
mode: 'index',
intersect: false,
},
plugins: {
legend: {
display: false,
},
title: {
display: false,
},
tooltip: {
enabled: false,
position: 'nearest',
external: customTooltip,
},
},
}));
return (
<div className="grad-chart-wrapper w-full relative">
<Line options={{ ...options }} data={data} ref={chartRef} />
{tooltipPos && (
<GraphTooltip
data={tooltipData}
position={tooltipPos}
visibility={tooltipVisible}
/>
)}
</div>
);
};
export default GradientChart;
Remember to think in React here (which is not always easy). Use the mycustomtooltipfunction to set state in your React class (specifically, add the tooltip that is passed to mycustometooltipfunction to the state - this will result in render being invoked. Now in the render function of your class, check if that state exists and add the JSX for your tooltip.
class MyChart extends Component {
constructor(props) {
super(props);
this.state = {
tooltip : undefined
};
}
showTooltip = (tooltip) => {
if (tooltip.opacity === 0) {
this.setState({
tooltip : undefined
});
} else {
this.setState({
tooltip
});
}
}
render() {
const { tooltip } = this.state;
let options = {
...
tooltips : {
enabled : false,
custom : this.showTooltip,
}
}
let myTooltip;
if (tooltip) {
// MAKE YOUR TOOLTIP HERE - using the tooltip from this.state.tooltip, or even have a tooltip JSX class
}
return (
<div>
{myTooltip}
<Line ref="mygraph" key={graphKey} data={data} options={options} height={graphHeight} width={graphWidth}/>
</div>
)
}
}
`
this.chart.chart_instance.canvas.getBoundingClientRect();
If you get some error with chart_instance you should check parent of element value.
Try this:
this.chart.chartInstance.canvas.getBoundingClientRect();
Related
Here is my div with canvas for line chart:
<div
x-data="{
lineChartLabels: #entangle('lineChartLabels'),
lineChartData: #entangle('lineChartData'),
init() {
const labels = `${this.lineChartLabels}`;
const data = {
labels: labels,
datasets: [{
backgroundColor: 'lightblue',
data: this.lineChartData,
fill: true,
label: `{{__('site.report.values')}}`,
}]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
ticks: {
callback: function (value) {
const date = new Date(Number(value) * 1000);
return date.toISOString().substring(11,23);
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: function (context) {
const date = new Date(Number(context.formattedValue) * 1000);
return date.toISOString().substring(11,23);
}
}
}
}
}
};
const myChart = new Chart(
this.$refs.canvas,
config
);
Livewire.on('updateTheChart', () => {
myChart.destroy();
myChart.data.datasets[0].data = this.lineChartData;
myChart.data.labels = this.lineChartLabels;
myChart.update();
})
}
}">
<canvas id="myChart" x-ref="canvas" style="height: 33vh;width: 50vw;"></canvas>
</div>
And here is an example of values(which represent seconds):
[49.66,47.26,46.88,49.81]
and for x axis which represents dates:
["04-Feb-17","06-May-17","28-Oct-17","20-Dec-17"]
But when it renders it shows like this:
Can somebody tell me why chartjs does not show x-asis in the proper way and how to fix it?
The problem is this line const labels = `${this.lineChartLabels}`; you are creating a script, what you need ist the array, so with other words: const labels = this.lineChartLabels; remove the string interpolation.
Disclaimer: I'm guessing abit, because I'm not acquainted with laravel-livewire and alpine.js, but that line of code looks like the culprit to me.
Here the two different Version, side by side:
const labels = ["04-Feb-17","06-May-17","28-Oct-17","20-Dec-17"];
const data = {
labels: labels,
datasets: [{
backgroundColor: 'lightblue',
data: [49.66,47.26,46.88,49.81],
fill: true,
label: `Correct Version`,
}]
};
const config = {
type: 'line',
data: data,
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
ticks: {
callback: function (value) {
const date = new Date(Number(value) * 1000);
return date.toISOString().substring(11,23);
}
}
}
},
plugins: {
tooltip: {
callbacks: {
label: function (context) {
const date = new Date(Number(context.formattedValue) * 1000);
return date.toISOString().substring(11,23);
}
}
}
}
}
};
new Chart(
document.getElementById('chart'),
config
);
config.data.labels = `${["04-Feb-17","06-May-17","28-Oct-17","20-Dec-17"]}`;
config.data.datasets[0].label = `Incorrect Version`;
let chart2 = new Chart(
document.getElementById('chart2'),
config
);
<script src="//cdn.jsdelivr.net/npm/chart.js"></script>
<div class="chart" style="float:left;height:184px; width:300px;font-family: Arial">
<canvas id="chart" ></canvas>
</div>
<div class="chart" style="float:left;height:184px; width:300px;font-family: Arial">
<canvas id="chart2" ></canvas>
</div>
I'm trying to use Charts.js on an AWS Lambda function to create a chart image (png).
However, for some reason it plots the axes, but no data.
this is my code:
export const plotData = (values: number[]): Buffer | null => {
const canvas = createCanvas(800, 600);
let ctx: ChartItem = canvas as unknown as ChartItem;
const plugin: Plugin = {
id: "customCanvasBackgroundColor",
beforeDraw: (chart: any, _args: any, options: any) => {
const { ctx: context } = chart;
context.save();
context.globalCompositeOperation = "destination-over";
context.fillStyle = options.color || "#99ffff";
context.fillRect(0, 0, chart.width, chart.height);
context.restore();
},
};
const chart = new Chart(ctx, {
type: "line",
data: {
datasets: [
{
label: "ph",
data: values.map((y) => ({
y,
t: new Date(),
})),
borderWidth: 2,
borderColor: "red",
backgroundColor: "rgb(255, 0, 0, 0.5)",
},
],
},
options: {
responsive: false,
animation: false,
scales: {
y: {
beginAtZero: true,
},
},
plugins: {
legend: {
position: "top",
},
title: {
display: true,
text: "TEstuibg",
},
customCanvasBackgroundColor: {
color: "rgba(255,255,255, 1)",
},
},
},
plugins: [plugin],
});
// chart.draw();
chart.update();
return canvas.toBuffer("image/png");
};
And this is what it is rendering when I call plotData([100, 200, 300, 400, 500, 1600]):
I am already disabling animations and responsiveness. Is there something else I need to do?
I would create the image on the onComplete event, than everything should be visible, atleast this works in browsers.
from the documentation: "...The animation configuration provides callbacks which are useful for synchronizing an external draw to the chart animation....", but works surely for your image creating process. link to documentation
...
options: {
animation:{
duration: 0, // "no" animation
onComplete: () => {
...
// create image
...
}
}
}
...
Ofcourse: in this case your function plotData would have to be async or pass a callback function for when the event onComplete fires.
Trying to create a gradient background for my Line chart. The solution I tried to implement is not working. See screenshot:
I implemented canvas's createLinearGradient() to no avail. What else could I be doing wrong?
Edit: I added all my imports, including the Filler. This way it still doesn't work.
import { Line } from "react-chartjs-2";
import {
Chart as ChartJS,
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
Filler,
ScriptableContext,
} from "chart.js";
ChartJS.register(
CategoryScale,
LinearScale,
PointElement,
LineElement,
Title,
Tooltip,
Legend,
Filler
);
function Linechart() {
const labels = ["January", "February", "March", "April", "May", "June"];
const dataLineChart = {
labels: labels,
datasets: [
{
backgroundColor: (context: ScriptableContext<"line">) => {
const ctx = context.chart.ctx;
const gradient = ctx.createLinearGradient(0, 0, 0, 200);
gradient.addColorStop(0, "rgba(250,174,50,1)");
gradient.addColorStop(1, "rgba(250,174,50,0)");
return gradient;
},
label: "UST",
fill: "start",
borderColor: "#8E95DF",
data: [0, 10, 5, 2, 20, 30, 45],
},
],
};
const configLineChart = {
type: "line",
dataLineChart,
elements: {
line: {
tension: 0.35,
},
},
plugins: {
filler: {
propagate: false,
},
},
};
return (
<div>
<div className="px-5 py-3">Fund Profits</div>
<Line data={dataLineChart} options={configLineChart}></Line>
</div>
);
}
export default Linechart;
Edit: When changing this const gradient = ctx.createLinearGradient(0, 0, 0, 200); to const gradient = ctx.createLinearGradient(0, 0, 0, 500); my gradient becomes visible. Can someone explain how that value works?
I wanted to create a context menu on my line graph. When the user hovers across a point, they can right click and will see a context menu so that they can trigger more action.
Is this possible with chart.js?
Thanks,
Derek
AFAIK there is no native support for context menu from Chart.js, but you can create it using HTML and handle it.
This is an example:
var timestamp = [],
speed = [10, 100, 20, 30, 40, 100, 40, 60];
for (var k = speed.length; k--; k>0) {
timestamp.push(new Date().getTime()-60*60*1000*k);
}
var canvas = document.getElementById('chart');
var BB = canvas.getBoundingClientRect(),
offsetX = BB.left,
offsetY = BB.top;
var ctx = canvas.getContext("2d");
var data = {
labels: timestamp,
datasets: [{
data: speed,
label: "speed",
backgroundColor: ['rgba(0, 9, 132, 0.2)'],
borderColor: ['rgba(0, 0, 192, 1)'],
borderWidth: 1,
}
]
};
var options = {
scales: {
yAxes: [{
ticks: {
beginAtZero: true,
}
}],
xAxes: [{
type: 'time',
}]
}
};
var chart = new Chart(ctx, {
type: 'line',
data: data,
options: options
});
var $menu = $('#contextMenu');
canvas.addEventListener('contextmenu', handleContextMenu, false);
canvas.addEventListener('mousedown', handleMouseDown, false);
function handleContextMenu(e){
e.preventDefault();
e.stopPropagation();
var x = parseInt(e.clientX-offsetX);
var y = parseInt(e.clientY-offsetY);
$menu.css({left:x,top:y});
$menu.show();
return(false);
}
function handleMouseDown(e){
$menu.hide();
}
menu = function(n){
console.log("select menu "+n);
$menu.hide();
}
#chart {
width: 100%;
height: 100%;
}
#contextMenu{
position:absolute;
border:1px solid red;
background:white;
list-style:none;
padding:3px;
}
.menu-item:hover {
background: #dddddd;
text-decoration: underline;
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id=canvasContainer>
<canvas id="chart"></canvas>
<ul id="contextMenu" style="display:none;">
<li class="menu-item" onclick="menu(1)">Menu 1</li>
<li class="menu-item" onclick="menu(2)">Menu 2</li>
</ul>
</div>
For anyone looking for this, #beaver's answer does not have access to the clicked item (data point), you can save the state in onHover and use it in contextmenu.
options: {
events: ['click', 'mousemove'],
onHover: function(e, fields){
const lx = e.layerX;
const bars = fields.filter(({_view: {x,width}}) => (x - width/2) <= lx && lx <= (x + width/2));
const data = bars.map(({_index, _datasetIndex}) => this.data.datasets[_datasetIndex].data[_index]);
this.hoveredItem = {bars, data, fields};
},
},
plugins: [
{
afterInit: (chart) =>
{
var menu = document.getElementById("contextMenu");
chart.canvas.addEventListener('contextmenu', handleContextMenu, false);
chart.canvas.addEventListener('mousedown', handleMouseDown, false);
function handleContextMenu(e){
e.preventDefault();
e.stopPropagation();
menu.style.left = e.clientX + "px";
menu.style.top = e.clientY + "px";
menu.style.display = "block";
console.log(chart.hoveredItem);
return(false);
}
function handleMouseDown(e){
menu.style.display = "none";
}
}
}
],
https://codepen.io/elizzk/pen/xxZjQvJ
is there any way to change style of hover as well as the tooltip with chartjs or ng2-charts? I want to hide the hover points and only display them whenever I hover on them along with the indicator as the line. Here is the exact chart model I want to build:
https://interactive-bitcoin-price-chart-foxkmkynmg.now.sh/
Thank you in advance for your tips.
EDIT: I followed instructions of GRUNT to apply this chart option into my Angular app, the full chart is shown with tooltip whenever I hover, but the line-trace indicator is not. Here are my codes:
plugin-hoverline.ts:
export class PluginHoverline {
posX: null;
isMouseOut:boolean = false;
drawLine(chart, posX) {
const ctx = chart.ctx,
x_axis = chart.scales['x-axis-0'],
y_axis = chart.scales['y-axis-0'],
x = posX,
topY = y_axis.top,
bottomY = y_axis.bottom;
if (posX < x_axis.left || posX > x_axis.right) return;
// draw line
ctx.save();
ctx.beginPath();
ctx.moveTo(x, topY);
ctx.lineTo(x, bottomY);
ctx.lineWidth = chart.options.lineOnHover.lineWidth;
ctx.strokeStyle = chart.options.lineOnHover.lineColor;
ctx.stroke();
ctx.restore();
};
beforeInit(chart) {
chart.options.events.push('mouseover');
};
afterEvent(chart, event) {
if (!chart.options.lineOnHover || !chart.options.lineOnHover.enabled) return;
if (event.type !== 'mousemove' && event.type !== 'mouseover') {
if (event.type === 'mouseout') this.isMouseOut = true;
chart.clear();
chart.draw();
return;
}
this.posX = event.x;
this.isMouseOut = false;
chart.clear();
chart.draw();
this.drawLine(chart, this.posX);
var metaData = chart.getDatasetMeta(0).data,
radius = chart.data.datasets[0].pointHoverRadius,
posX = metaData.map(e => e._model.x);
posX.forEach(function(pos, posIndex) {
if (this.posX < pos + radius && this.posX > pos - radius) {
chart.updateHoverStyle([metaData[posIndex]], null, true);
chart.tooltip._active = [metaData[posIndex]];
} else chart.updateHoverStyle([metaData[posIndex]], null, false);
}.bind(this));
chart.tooltip.update();
};
afterDatasetsDraw(chart, ease) {
if (!this.posX) return;
if (!this.isMouseOut) this.drawLine(chart, this.posX);
};
}
banner.component.ts: (chart component)
import { Component, OnInit } from '#angular/core';
import { HistoricalBpiService } from '../../services/historical-bpi.service';
import { PluginHoverline } from './plugin-hoverline';
#Component({
selector: 'app-banner',
templateUrl: './banner.component.html',
styleUrls: ['./banner.component.scss']
})
export class BannerComponent implements OnInit {
private dataUrl: string = 'historical/close.json';
constructor(
private historicalBpiService:HistoricalBpiService
) {}
// lineChart
public lineChartData:any = [
{ data:[], label: 'Bitcoin price' }
];
public lineChartLabels:Array<any> = [];
public lineChartOptions:any = {
responsive: true,
maintainAspectRatio: false,
layout: {
padding: 0
},
lineOnHover: {
enabled: true,
lineColor: '#bbb',
lineWidth: 1
},
scales: {
yAxes: [{
display: true,
scaleLabel: {
display: false,
labelString: 'USD'
},
ticks: {
display: false
},
gridLines: {
display: true,
tickMarkLength: 0
}
}],
xAxes: [{
ticks: {
display: false
},
gridLines: {
display: false,
tickMarkLength: 0
}
}]
},
elements: {
point: {
radius: 3
},
line: {
tension: 0.4, // 0 disables bezier curves
}
},
hover: {
mode: 'nearest',
intersect: false
},
tooltips: {
mode: 'nearest',
intersect: false,
backgroundColor: 'rgb(95,22,21)',
callbacks: {
label: function (tooltipItems, data) {
return data.datasets[tooltipItems.datasetIndex].label + ' : ' + '$' + tooltipItems.yLabel.toLocaleString();
},
labelColor: function(tooltipItem, chart) {
var dataset = chart.config.data.datasets[tooltipItem.datasetIndex];
return {
backgroundColor : dataset.backgroundColor
}
}
}
}
};
public lineChartColors:Array<any> = [
{
backgroundColor: 'rgba(199,32,48,0.8',
borderColor: 'rgb(95,22,21);',
pointBackgroundColor: 'rgba(218,208,163,0.8)',
pointHoverBackgroundColor: 'rgba(218,208,163,0.8)',
pointHoverBorderColor: 'rgb(218,208,163)',
pointHoverRadius: 6,
steppedLine: false
}
];
public lineChartLegend:boolean = false;
public lineChartType:string = 'line';
// events
public chartClicked(e:any):void {
console.log(e);
}
public chartHovered(e:any):void {
console.log(e);
}
ngOnInit(){
this.historicalBpiService.getBpiData(this.dataUrl)
.subscribe(
res => {
//this.lineChartData = Object.keys(res.bpi).map(function (key) { return res.bpi[key];});
this.lineChartData[0].data = Object.values(res.bpi);
this.lineChartLabels = Object.keys(res.bpi);
//console.log(this.lineChartData,this.lineChartLabels);
}
)
}
}
template:
<div class="chart">
<canvas baseChart height="360px"
[datasets]="lineChartData"
[labels]="lineChartLabels"
[options]="lineChartOptions"
[colors]="lineChartColors"
[legend]="lineChartLegend"
[chartType]="lineChartType"
(chartHover)="chartHovered($event)"
(chartClick)="chartClicked($event)"></canvas>
</div>
Unfortunately there is no built-in functionality for this yet. However you can use this chart plugin (once created for my own purpose) to achieve your goal.
To utilize the plugin, set the following option in your chartÂ's options config :
lineOnHover: {
enabled: true,
lineColor: '#bbb',
lineWidth: 1
}
also, make sure to set the following properties for your dataset :
pointRadius: 0,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'white'
see - live demo
This answer is to build on top of GRUNT's answer above to be able to display if its a multiline graph:
Just change the following (in the code snippet he provide here):
posX.forEach(function(pos, posIndex) {
if (this.posX < pos + radius && this.posX > pos - radius) {
chart.updateHoverStyle([metaData[posIndex]], null, true);
chart.tooltip._active = [metaData[posIndex]];
} else chart.updateHoverStyle([metaData[posIndex]], null, false);
}.bind(this));
to:
posX.forEach(function(pos, posIndex) {
var metaDatum = []
if (this.posX < pos + radius && this.posX > pos - radius) {
chart.data.datasets.forEach((dataset, ind) => {
metaDatum.push(chart.getDatasetMeta(ind).data[posIndex]);
})
chart.updateHoverStyle(metaDatum, null, true);
chart.tooltip._active = metaDatum;
} else {
metaDatum.push(metaData[posIndex]);
chart.updateHoverStyle(metaDatum, null, false);
}
}.bind(this));