fpcjh
fpcjh

Reputation: 283

Google Charts/Visualization - dismiss tooltip on click away

Using Google Charts (haven't migrated to the Material ones yet), one can make tooltips require a click by using the {trigger: 'selection'} option. However, using this the tooltip cannot be dismissed unless the user clicks another data point in the chart - they can't just click anywhere.

Is there a way to make it so the tooltip dismisses when anywhere outside said tooltip is clicked? Little more fluid that way.

Upvotes: 4

Views: 3336

Answers (4)

Orwellophile
Orwellophile

Reputation: 13953

April, 2023

An effective one-liner, insert before calling chart.draw()

google.visualization.events.addListener(chart, 'ready', (e) =>
    chart.container.addEventListener('click',
        () => chart.container.querySelector('.google-visualization-tooltip')
            ? chart.setSelection() : 0))

change chart to match the name of your chart.

Upvotes: 0

George Birbilis
George Birbilis

Reputation: 2930

based on dennisr2000's answer I did this:

function onChartSelection(e) {
  var selection = chart.getSelection([e]); //note: if currently selected datapoint is clicked, selection is emptied ([] received)
  var dataPointIndex = (selection.length != 0)? selection[0].row : -1; //using -1 for deselection

  if (_chartSelectionChangedCallback != null)
    _chartSelectionChangedCallback(dataPointIndex);
  }

function plotElevationsDistances(elevations, distances, selectionCallback) {
  //console.log('elevations: ', JSON.stringify(elevations));
  //console.log('distances: ', JSON.stringify(distances));

  chart =
    //new google.visualization.ColumnChart(document.getElementById('chart_div')); 
    /**/new google.visualization.LineChart(document.getElementById('chart_div'));

  // Add data selection handler:
  google.visualization.events.addListener(chart, 'select', onChartSelection);
  google.visualization.events.addListener(chart, 'onmouseover', function(e){
      chart.setSelection([{row: e.row, column: e.column}]);
      onChartSelection(e);
  });

  var data = new google.visualization.DataTable();
  //data.addColumn('string', '# Marker');
  /**/data.addColumn('number', 'Distance (km)');
  data.addColumn('number', 'Elevation (m)');
  data.addColumn({type: 'string', role: 'tooltip', 'p': {'html': true}});

  var elevationCount = elevations.length;
  for (var i = 0; i < elevationCount; i++)
    data.addRow([
        /*''*/distances[i],
        elevations[i],
        '<div class="chartTooltip" onClick="$(this).closest(\'.google-visualization-tooltip\').hide()">Distance: <strong>' + distances[i] + ' km</strong><br />Elevation: <strong>' + elevations[i] + ' m</strong></div><div class="chartTooltipCloseBtn" onClick="$(this).closest(\'.google-visualization-tooltip\').hide()" draggable="false" title="Close" aria-label="Close" type="button" onClick ><img class="chartTooltipCloseBtnImg" src="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224px%22%20height%3D%2224px%22%20viewBox%3D%220%200%2024%2024%22%20fill%3D%22%23000000%22%3E%0A%20%20%20%20%3Cpath%20d%3D%22M19%206.41L17.59%205%2012%2010.59%206.41%205%205%206.41%2010.59%2012%205%2017.59%206.41%2019%2012%2013.41%2017.59%2019%2019%2017.59%2013.41%2012z%22%2F%3E%0A%20%20%20%20%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%0A%3C%2Fsvg%3E%0A"></button>'
        ]);

  chart.draw(data, chartOptions);
}

combined with these styles:

.chartTooltip {
    margin:10px;
    text-align: left;
}

.chartTooltipCloseBtn {
    background: rgba(0, 0, 0, 0) none repeat scroll 0% 0%;
    display: block;
    border: 0px none;
    margin: 0px;
    padding: 0px;
    position: absolute;
    cursor: pointer;
    -moz-user-select: none;
    top: -6px;
    right: -6px;
    width: 30px;
    height: 30px;
    outline: currentcolor none medium;
    opacity: 0.6;
}

.chartTooltipCloseBtn:hover {
    opacity: 1;
}

.chartTooltipCloseBtnImg {
    .pointer-events: none;
    display: block;
    width: 14px;
    height: 14px;
    margin: 8px;
}

The styles are based on the x shown by Google Maps infoboxes

Note the two listeners (I didn't want to clear selection on hover, but instead reselect the hovered point) and the "onClick" attribute in the tooltip.

Note that I have the close action on both the tooltip (useful for touch screens) AND on the x button for mouse users with a hover effect on that button as the maps infobox also does (maps infobox doesn't seem to close on touch btw, just with the x button)

The callback I have in onChartSelection is cause setSelection on the chart via the API doesn't seem to fire a selection event, only manual actions do. So like that I do selection on hover as if the user had clicked on the data point and the tooltip is shown immediately and persists (like a combined "selection" and "focus" mode for the "tooltip.trigger", which Google isn't providing out of the box)

Upvotes: 1

dennisr2000
dennisr2000

Reputation: 46

I was able to get something similar to work: not to get the tooltip to vanish when you click away, but when you click on the tooltip iteself. Maybe you can add a close button to the tooltip.

First, it has to be an html tooltip:

tooltip: { isHtml: true }

Then you must add the following somewhere in the string html that you pass to the chart (assuming jQuery):

$("<div></div>").attr("onclick", "$(this).closest('.google-visualization-tooltip').hide()")

Or something similar if you're not using jQuery. This only seems to work for an inner div of the html content you pass for the tooltip, so this needs to be a child div.

Also, you will need to add the following event handler to the chart:

google.visualization.events.addListener(chart, "onmouseover", function(event){
      chart.setSelection(null);
});

Otherwise the tooltip will pop back up when you hover the chart.

Upvotes: 1

Vadim Gremyachev
Vadim Gremyachev

Reputation: 59358

You could attach a click event handler for the body element to clear the chart's selection as demonstrated below:

Example

google.setOnLoadCallback(drawChart);

var chart;
function drawChart() {

    var data = google.visualization.arrayToDataTable([
        ['Year', 'Fixations'],
        ['2015', 80],
        ['2016', 90],
        ['2017', 100],
        ['2018', 90],
        ['2019', 80], ]);

    var options = {
        tooltip: {
            isHtml: true,
            trigger: 'selection'
        },
        legend: {
            position: 'none'
        },
        bar: {
            groupWidth: '90%'
        },
        colors: ['#A61D4C'],
        enableInteractivity: true
    };

    chart = new google.visualization.ColumnChart(document.getElementById('tooltip_rotated'));

    chart.draw(data, options);
    addEvent(document.querySelector('body'),'click',clearSelection);
}


function clearSelection (e) {
    if (!document.querySelector('#tooltip_rotated').contains(e.srcElement)) {   
       chart.setSelection();
    }
}


function addEvent(element, evnt, funct){
  if (element.attachEvent)
   return element.attachEvent('on'+evnt, funct);
  else
   return element.addEventListener(evnt, funct, false);
}
<script type="text/javascript" src="https://www.google.com/jsapi?autoload={'modules':[{'name':'visualization','version':'1.1','packages':['corechart']}]}"></script>
<div id="tooltip_rotated" style="width: 400px; height: 400px;"></div>

Upvotes: 2

Related Questions