Change style of hover and tooltip in chartjs or ng2-charts

Hoàng Nguyễn picture Hoàng Nguyễn · Sep 12, 2017 · Viewed 7.3k times · Source

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>

Answer

ɢʀᴜɴᴛ picture ɢʀᴜɴᴛ · Sep 12, 2017

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