I am using a Google Pie Chart for data representation. The chart's tooltips include action items that users can click on. To keep the tooltips open long enough for users to click the items, I have opted to have the tooltips show on click/selection rather than on hover:
tooltip: { trigger: 'selection' }
The problem now is that the only way to close these tooltips is to either make another selection on the chart (thus showing another tooltip) or to click the same legend/pie slice value that was previously selected.
This is clunky; for good UX, I want to allow users to dismiss tooltips simply by clicking the empty space around the pie chart.
So far the closest solution I have found is in this question, but the first answer does not work and the second does not allow the tooltip to be closed by click-away. The problem appears to be that all of the whitespace around the chart is still considered part of the chart itself rather than a separate element. I tried to get around this limitation by checking the type of the clicked element to see whether it was the whitespace as shown below:
function clearChartSelection(e) {
if (!chartDOMElement.contains(e.srcElement) || e.srcElement.tagName.toUpperCase() == 'RECT') {
chart.setSelection();
}
}
Unfortunately, this didn't work either as the legend element sometimes renders as a rectangle type instead of text (I'm still trying to figure out what causes this). In pie charts, legend clicks also set the selection, and I want to keep this functionality.
Right now I'm investigating the following two paths, but without luck:
Some other way to distinguish between the slices/legend and the empty chart area, or
Somehow prevent the click event if the selection event is also triggered.
I'm definitely open to any other ideas that may resolve this issue. The functionality I want is pretty common for tooltips in general, so hopefully I've just missed something obvious.
in addition to the body click,
use the chart's click event
see following working snippet...
google.charts.load('current', {
packages:['corechart']
}).then(function () {
var data = google.visualization.arrayToDataTable([
['Label', 'Value'],
['A', 1],
['B', 2],
['C', 2],
['D', 2],
['E', 7]
]);
var options = {
tooltip: {
trigger: 'selection'
}
};
var container = document.getElementById('chart_div');
var chart = new google.visualization.PieChart(container);
google.visualization.events.addListener(chart, 'click', clearSelection);
document.body.addEventListener('click', clearSelection, false);
chart.draw(data, options);
function clearSelection(e) {
if (!container.contains(e.srcElement)) {
chart.setSelection();
}
}
});
html, body {
height: 100%;
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="chart_div"></div>
Related
I'm trying to implement a page with infinite scroll and add tooltips to some items. Infinite scroll works fine, but tooltips only appear on the first page, before adding new items with the scroll. This is the example:
https://stage.superbiajuridico.es/news/
The tooltip is in the small yellow circle, when placing the cursor over it. If you scroll down, in the following pages, the rest of the tooltips are not built, although I'm using the append event to build them each time the page is reloaded.
Apparently the code is very simple and I do not know what I'm doing wrong:
// TOOLTIPS
// ------------------
var miTootip = $('.tooltip-item');
new Tooltip(miTootip, {
// options
});
// INFINITE SCROLL
// ------------------
var inf = $('.infinite-scroll-container').infiniteScroll({
// options
});
inf.on('append.infiniteScroll', function(event, response, path, items) {
// THIS IS THE PART THAT DOESN'T WORK
new Tooltip(miTootip, {
// options
});
});
This is not working. I'have not much experience with JS so I think I'm doing wrong something obvious.
EDIT: When trying to codepen, I realized that the error is elsewhere. The tooltip only appears in the first item (it does not have to do with infinite-scroll). This is the pen: https://codepen.io/aitormendez/pen/yRGyZW
As I understand, your new Tooltip(miTootip) takes HtmlElement and replaces with tooltip. So in your append.infiniteScroll event's callback you have to add element with class .tooltip-item, and then create Tooltip.
UPD
You selected .tooltip-item and with this element, using Tooltip constructor, created tooltip, just for one item. So, if you want this tooltip for all items, that this tooltip need, you have to do smth like that:
inf.on('append.infiniteScroll', function(event, response, path, items)
{
$('.infinite-scroll-container').append('<div class="tooltip-item"></div>')
const miTooltip = $('.tooltip-item')
new Tooltip(miTooltip, {
// options
});
});
Tooltips must to be created iterating the jQuery object with a loop.
let myTooltip = $('.tooltip-item');
myTooltip.each(function(){
new Tooltip(this, {
title: "Tooltip",
trigger: "hover",
});
})
I am using google charts and am manually positioning the vaxis titles by
$($('text').filter(':contains("Recurrence Interval")')[0]).attr('x', '220');
$($('text').filter(':contains("Hazard Score")')[0]).attr('x', '50');
$($('text').filter(':contains("Hazard Score")')[0]).attr('y', '225');
The thing is that the first line works 100% fine. The next two lines don't seem to work when in my code. However when I run the bottom two lines in my console, it works. This is all wrapped by a google chart setOnLoadCallBack function so the charts should have been loaded already.
need to wait for the chart's 'ready' event to fire,
before making modifications
set the event listener before drawing the chart, e.g.
var chartDiv = document.getElementById('chart_div');
var chart = new google.visualization.BarChart(chartDiv);
google.visualization.events.addListener(chart, 'ready', function () {
$($('text').filter(':contains("Recurrence Interval")')[0]).attr('x', '220');
$($('text').filter(':contains("Hazard Score")')[0]).attr('x', '50');
$($('text').filter(':contains("Hazard Score")')[0]).attr('y', '225');
});
chart.draw(data, options);
if animation is being used, listen for the 'animationfinish' event instead
I am trying to drill up using my own button but having difficulties.
JSfiddle with multi drilldown
$( "#backbtn" ).click(function(e) {
setChartC(name, categories, data, '', 1);
alert(chartC.xAxis[0]);
});
I have levels, how can I access the drilldown.level?
exporting: {
enabled: true,
buttons: {
customButton: {
text: 'Go Back',
onclick: function () {
var drilldown = chartC.drilldown;
alert(chartC.level);
}
}
}
Cant seem to access the level as i got drill down. is there any way I can access the level
You can use the native Highcharts back button. You can see an example here (link author here).
However, if you want to add a custom button, I don't believe that Highcharts have an easy way for that. If you find that I'm wrong, please correct me.
So, to add a custom back button, you need to track what is the current chart that you are showing. Knowing what is the current, you could look into a dictionary to find which level it is. To get the current chart, you can track the click events:
plotOptions: {
column: {
point: {
events: {
click: function () {
console.log("I'm at: " + this.drilldown.name)
}
}
}
}
}
Regarding the custom back button, look this JSFiddle.
Add this HTML:
<input type="button" id="backbtn" value="Back">
And this JS:
$("#backbtn").click(function(e) {
setChart(name, categories, data);
});
Since the variables name, categories and data were defined with the values of the top-level chart, clicking in this button will restore to the top-level.
If you create a tree object with all charts and their name/categories/data info, and if you know the current chart, you can set the Chart with its parent data to implement the custom back button.
I have a sitiuation with Twitter Bootsrap popovers. I managed to make them work to show remote content via iframes, but the problem is I have a Google visualization chart (table) and it has links to trigger popovers depending on the cells values.
The table visualization is set to allow html and it works okay even to trigger modals, but not popovers. They just work when outside of the table.
For you guys to have an idea of what's going on I've placed the full code in jsFidle.http://jsfiddle.net/TyPowers/xLkcY/
Though external references are loaded in the same order (which happens to be an issue sometimes), in jsFidle the popoovers outside of the table don't work either.
$(function(){
$(window).load(function(){
var img = '<iframe frameborder="0" scrolling="no" height="220" width="420"
src="http://dxlite.g7vjr.org/?dx=LU5DX&limit=10"></iframe>';
$("#blob").popover({title: 'Last 10 spots for the selected station',
content: img, html:true});
$('[rel="popover"]').popover();
})
});
So to see the actual issue please take a look at http://qsl.net/lu5dx/dxo/
The comment in the first record of the table has exactly the same code as the popoevers outside of the table, but it doesn't work. Someone suggested placing a span class, but it didn't work either.
Your help is much appreciated.
Thanks in advance.
What you need to do to fix the popover links is initialize them in a "ready" event handler for the table. Add this to your drawVisualization function after you create the cTable object, but before calling the dashboard's #draw method:
google.visualization.events.addListener(cTable, 'ready', function () {
$('#' + cTable.getContainerId() + ' [rel="popover"]').popover();
});
A few other things to note that might help: you don't need to pre-load the "table" and "corechart" packages - the ChartWrapper and ControlWrapper objects will take care of loading the necessary libraries for you (preloading doesn't hurt, but it's not going to gain you anything either). You also don't need to specify the dataTable parameter for the ChartRangeFilter - that is handled by the Dashboard. The ChartRangeFilter minRangeSize option is a sub-option of the ui option, not ui.chartOptions, so it should be set up like this:
options: {
ui: {
chartOptions: {
height: 70,
chartArea: {'height': '80%', 'width': '99.5%'},
width: '100%',
hAxis: {
format: 'MMM d y'
},
label : 'End Date Filter'
},
// 1 day in milliseconds = 24 * 60 * 60 * 1000 = 86,400,000
minRangeSize: 86400000,
chartView: {
// Display a single series (DXPedition End Date) to filter the table visualization.
columns: [7, {type: 'number', calc: function() { return 0;}}]
}
},
// Filter by the DXPedition End Date axis.
filterColumnIndex: 7
}
Also, it might help with the data-loading problem if you switch the spreadsheet url to use the tq parameter instead of the ccc parameter:
var query = new google.visualization.Query('https://docs.google.com/spreadsheet/tq?key=0AmR-D3rOsulZdDJtbmxWeVdXLUliSEhRV0gwNUZsbUE');
The tq parameter tells the spreadsheet API to return a DataTable object. I changed this in a jsfiddle (http://jsfiddle.net/asgallant/xLkcY/10/, also contains the other changes from above) and noticed a dramatic reduction in the number of loading errors (though they did not go away entirely).
I have a question regarding Google Charts (Column Charts) in specific.
"How do I make the "date" clickable so I can open up a modal dialog (jQuery) with an external page?"
I have added an example to illustrate what I mean, this is obviously done in Photoshop.
I am able to bring up a alert dialog when I click any of the bars, but that's not really what I am looking for.
I have tried to search for it, but was unable to find something.
Attached is the code I used for making the bars clickable, maybe someone knows how to modify that without having to Google for it.
var handler = function(e) {
var sel = chart.getSelection();
sel = sel[0];
if (sel && sel['row'] && sel['column']) {
var message = "Hi..";
alert(message);
}
}
google.visualization.events.addListener(chart, 'select', handler);
Any assistance would be very much appreciated.
- Robert.
If you use a 'click' handler instead of a 'select' handler, you can more easily interact with other parts of the chart.
Here's an example: http://jsfiddle.net/6LJhv/6/
Your event object, e, will have a targetID property.
This targetID is not well documented, but if you run the debugger, you can get a sense of what IDs look like.
On the various axis charts (Line, Column, etc.) the targetID of the axis labels look something like this: hAxis#0#label#1. To break that down, it means that you clicked on the second label of the first horizontal axis (0 based index).
Given that, we can dissect the targetID to figure out which label you clicked on from the data if it's discrete.
(If your data is continuous, there isn't necessarily a 1:1 relationship with the labels and rows of data)
var handler = function(e) {
var parts = e.targetID.split('#');
if (parts.indexOf('label') >= 0) {
var idx = parts[parts.indexOf('label') + 1];
alert(data.getValue(0, parseInt(idx)));
}
};
google.visualization.events.addListener(chart, 'click', handler);