When I use:
chart.getChart().getSelection()[0]
on a chart (from a chartwrapper, hence the getChart() first), the getSelection() function returns
only a row-property but no column property even though my 'chart' is a table and clicking anywhere within it should return both a row and column property.
Is this a known google charts bug? Does anyone know of a workaround?
Also I have found this topic on google groups:
https://groups.google.com/forum/#!topic/google-visualization-api/O_t7-s96A9w
here they say:
Currently the Table object only supports row selection and therefore the column property is always undefined. If this is important for you, you can catch these events by yourself by adding some special html code int he formatted value of each cell.
Anyone have an idea how to do this?
Even though google.visualization.table supports row selection only (it explains why column property returns null), you could consider the following approach to access column property:
google.load('visualization', '1', {
packages: ['table']
});
google.setOnLoadCallback(drawTable);
function drawTable() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('number', 'Salary');
data.addColumn('boolean', 'Full Time Employee');
data.addRows([
['Mike', {
v: 10000,
f: '$10,000'
},
true
],
['Jim', {
v: 8000,
f: '$8,000'
},
false
],
['Alice', {
v: 12500,
f: '$12,500'
},
true
],
['Bob', {
v: 7000,
f: '$7,000'
},
true
]
]);
var table = new google.visualization.Table(document.getElementById('table_div'));
google.visualization.events.addListener(table, 'select', function(){
selectHandler(table);
});
table.draw(data, {
showRowNumber: false
});
}
function selectHandler(table) {
var selection = table.getSelection();
if(selection.length === 0)
return;
var e = event || window.event;
var cell = e.target; //get selected cell
document.getElementById('output').innerHTML = "Row: " + selection[0].row + " Column: " + cell.cellIndex;
}
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<div id="table_div"></div>
<div id="output"></div>
You can format your values with HTML, and pass 'allowHtml: true' in your draw options. Then your HTML can raise the event / execute the js that you want it to when a user clicks on the cell value.
For example, the items below will raise an alert when clicked on:
function drawTable() {
var data = new google.visualization.DataTable();
data.addColumn('string', 'Name');
data.addColumn('number', 'Salary');
data.addColumn('boolean', 'Full Time Employee');
data.addRows([
['Ted', {v: 10000, f: '<span onclick="alert(0)">$10,000</span>'}, true],
['Jim', {v:8000, f: '<span onclick="alert(1)">$8,000</span>'}, false],
['Alice', {v: 12500, f: '<span onclick="alert(2)">$12,500</span>'}, true],
['Bob', {v: 7000, f: '<span onclick="alert(3)">$7,000</span>'}, true]
]);
var table = new google.visualization.Table(document.getElementById('table_div'));
google.visualization.events.addListener(table, 'select', function () {
var s = table.getSelection();
document.getElementById('row').innerHTML = s[0].row;
document.getElementById('col').innerHTML = s[0].column;
console.log(s);
});
table.draw(data, {showRowNumber: true, allowHtml: true});
}
google.load('visualization', '1', {packages:['table'], callback: drawTable});
See:
http://jsfiddle.net/fZzch/2/
A cleaner approach is to use a custom formatter:
How to write a custom formatter for Google DataTables (for use on visualisation api)
Related
I succeeded to create a sheet, but horizontal and vertical alignments are set to defaults, not the ones I tried to set.
Here is the code
spreadsheet_body = {
'properties': {
'title': str("sme_"+jour_heure.read()),
'defaultFormat': {
'horizontalAlignment': 'LEFT',
'verticalAlignment': 'MIDDLE'
}
}
}
print(spreadsheet_body)
# Création du fichier Google Sheet
request = service_sheet.spreadsheets().create(body=spreadsheet_body)
response = request.execute()
print (response)
My sheet is correctly created by vertical and horizontal alignments are not set.
print (spreadsheet_body)
prints:
{'properties': {'title': 'sme_18_04_2020\n', 'defaultFormat': {'horizontalAlignment': 'LEFT', 'verticalAlignment': 'MIDDLE'}}}
but
print (response)
prints:
{'spreadsheetId': '1F2o5F8B-efoAOkg-d3z_2tGcPhvlp8gtcvGOGkGvAGI', 'properties': {'title': 'sme_18_04_2020\n', 'locale': 'en_US', 'autoRecalc': 'ON_CHANGE', 'timeZone': 'Etc/GMT', 'defaultFormat': {'backgroundColor': {'red': 1, 'green': 1, 'blue': 1}, 'padding': {'top': 2, 'right': 3, 'bottom': 2, 'left': 3}, 'verticalAlignment': 'BOTTOM', 'wrapStrategy': 'OVERFLOW_CELL', 'textFormat': {'foregroundColor': {}, 'fontFamily': 'arial,sans,sans-serif', 'fontSize': 10, 'bold': False, 'italic': False, 'strikethrough': Fal ./..
Title is OK but verticalAlignment is not ...
What did I do wrong ?
i believe you want to create new sheet with required alignment, with your code everything is a string like "horizontalAlignment": "LEFT" anything between "" is string and line ends with ; instead of ,
try this for creating new sheet and alignment
function alignment(){
//change sheet name as per your requirement
var ss = SpreadsheetApp.getActiveSpreadsheet().insertSheet("yousheet");
var range = ss.getRange("A1:Z");
range.setHorizontalAlignment('left').setVerticalAlignment('middle');
}
I need to draw graphs with my sql server data .
So I have my servlet that select all data I need and transform it to json , then I forward all data to my jsp.
what I want is to show information like names in my pie graph .
this is my servlet :
PreparedStatement ps = c.prepareStatement("select SUM(ChiffreAffaire)as CA,M500_NOM from V502_client where Annee=? and Mois=2 group by M500_NOM");
ps.setString(1, name);
ResultSet resultSet = ps.executeQuery();
while(resultSet.next()){
yVal = resultSet.getFloat("CA");
nom=resultSet.getString("M500_NOM");
map = new HashMap<Object,Object>(); map.put("x", nom);map.put("y",yVal); list.add(map);
dataPoints = gsonObj.toJson(list);
}
request.getSession().setAttribute("data", dataPoints);
RequestDispatcher rd = request.getRequestDispatcher("graph.jsp");
rd.forward(request, response);
and this is the script to show my graph :
<script type="text/javascript">
<% String shared1 = (String)request.getSession().getAttribute("data");%>
window.onload = function() {
var chart = new CanvasJS.Chart("chartContainer", {
animationEnabled: true,
exportEnabled: true,
title: {
text: "Représentation graphique"
},
data: [{
type: "pie", //change type to bar, line, area, pie, etc
showInLegend: "true",
startAngle: 40,
dataPoints: <%out.print(shared1);%>
}]
});
chart.render();
}
</script>
<div id="chartContainer" style="height:370px; width:600px;"></div>
The result of this is shown like :
I want to be like this :
Try to define legendText on your dataset and indicate, which property contains the label ('x' in your case).
data: [{
type: "pie",
showInLegend: true,
legendText: "{x}",
startAngle: 40,
dataPoints: <%out.print(shared1);%>
}]
Please note that every label (x property) should be different for a pie chart.
I've got a list I'm trying to pull an object from using _.get but following that selection I need to loop over the object to create a new property. So far I've been successful using a combination of _.get and _.map as shown below but I'm hoping I can use _.chain in some way.
var selected = _.get(results, selectedId);
return _.map([selected], result => {
var reviews = result.reviews.map(review => {
var reviewed = review.userId === authenticatedUserId;
return _.extend({}, review, {reviewed: reviewed});
});
return _.extend({}, result, {reviews: reviews});
})[0];
Is it possible to do a transform like this using something other than map (as map required me to break this up/ creating an array with a solo item inside it). Thank you in advance!
I can see that you're creating unnecessary map() calls, you can simply reduce all those work into something like this:
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
The defaults() method is similar to extend() except once a property is set, additional values of the same property are ignored.
var selectedId = 1;
var authenticatedUserId = 1;
var results = {
1: [
{ userId: 1, text: 'hello' },
{ userId: 2, text: 'hey' },
{ userId: 1, text: 'world?' },
{ userId: 2, text: 'nah' },
]
};
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
document.body.innerHTML = '<pre>' + JSON.stringify(output, 0, 4) + '</pre>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>
I'm using Dojo GridX with many modules, including filter:
grid = new Grid({
cacheClass : Cache,
structure: structure,
store: store,
modules : [ Sort, ColumnResizer, Pagination, PaginationBar, CellWidget, GridEdit,
Filter, FilterBar, QuickFilter, HiddenColumns, HScroller ],
autoHeight : true, autoWidth: false,
paginationBarSizes: [25, 50, 100],
paginationBarPosition: 'top,bottom',
}, gridNode);
grid.filterBar.applyFilter({type: 'all', conditions: [
{colId: 'type', condition: 'equal', type: 'Text', value: 'car'}
]})
I've wanted to access the items, that are matching the filter that was set. I've travelled through grid property in DOM explorer, I've found many store references in many modules, but all of them contained all items.
Is it possible to find out what items are visible in grid because they are matching filter, or at least those that are visible on current page? If so, how to do that?
My solution is:
try {
var filterData = [];
var ids = grid.model._exts.clientFilter._ids;
for ( var i = 0; i < ids.length; ++i) {
var id = ids[i];
var item = grid.model.store.get(id);
filterData.push(item);
}
var store = new MemoryStore({
data : filterData
});
} catch (error) {
console.log("Filter is not set.");
}
I was able to obtain filtered gridX data rows using gridX Exporter. Add this Exporter module to your grid. This module does exports the filtered data. Then, convert CSV to Json. There are many CSV to Json conversion javasripts out there.
this.navResult.grid.exporter.toCSV(args).then(this.showResult, this.onError, null)
Based on AirG answer I have designed the following solution. Take into account that there are two cases, with or without filter and that you must be aware of the order of rows if you have applied some sort. At least this works for me.
var store = new Store({
idProperty: "idPeople", data: [
{ idPeople: 1, name: 'John', score: 130, city: 'New York', birthday: '31/02/1980' },
{ idPeople: 2, name: 'Alice', score: 123, city: 'Wáshington', birthday: '07/12/1984' },
{ idPeople: 3, name: 'Lee', score: 149, city: 'Shanghai', birthday: '8/10/1986' },
...
]
});
gridx = new GridX({
id: 'mygridx',
cacheClass: Cache,
store: store,
...
modules: [
...
{
moduleClass: Dod,
defaultShow: false,
useAnimation: true,
showExpando: true,
detailProvider: gridXDetailProvider
},
...
],
...
}, 'gridNode');
function gridXDetailProvider (grid, rowId, detailNode, rendered) {
gridXGetDetailContent(grid, rowId, detailNode);
rendered.callback();
return rendered;
}
function gridXGetDetailContent(grid, rowId, detailNode) {
if (grid.model._exts.clientFilter._ids === undefined || grid.model._exts.clientFilter._ids === 0) {
// No filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._cache._priority.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._cache._priority.indexOf(rowId)).item().idPeople;
} else {
// With filter, with or without sort
detailNode.innerHTML = 'Hello ' + grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().name + " with id " +
grid.row(grid.model._exts.clientFilter._ids.indexOf(rowId)).item().idPeople;
}
}
Hope that helps,
Santiago Horcajo
function getFilteredData() {
var filteredIds = grid.model._exts.clientFilter._ids;
return grid.store.data.filter(function(item) {
return filteredIds.indexOf(item.id) > -1;
});
}
I am working on dynamic flot graph with 3 series. My need is to hide/show series when clicked on legend. I have seen different examples that will work fine for static graphs but for dynamic graph, even it works first time but when graph is updated with new data values then everything is displaying with default options. once I hide the series, I want it to be hided until I click again to show it.
Here is my code. Basically, I am fetching data from JSON and updating the flot graph dynamically in 10 sec intervals. so new data will be shown every 10 sec and this is where the series is showing back again.
<div id="placeholder4" style="width:1000px;height:300px;background:#C89175"></div>
<script type="text/javascript">
$(function() {
somePlot = null;
togglePlot = function(seriesIdx)
{
var someData = somePlot.getData();
someData[seriesIdx].lines.show = !someData[seriesIdx].lines.show;
somePlot.setData(someData);
somePlot.draw();
}
// Initilizaiton of Series and Counter
var i = 0;
var data_Total = [[], [], []];
// data_Total[0] : Stip Data
// data_Total[1] : Decline Data
// data_Total[2] : Volume Data
//Setting Options for Graph Display
var options = {
points: { show: true },
//legend: {toggle: true },
series: {
lines: { show: true }
},
legend: {
labelFormatter: function(label, series){
return ''+label+'';
}
},
grid: {backgroundColor: "#FCFCFC", labelMargin:12,hoverable: true,tickColor:"#AD5C5C" },
xaxis: { mode: "categories", show:true,color:"white",axisLabel:'Time Series' },
yaxis:{show:true,color:"white",min:0,max:10000,axisLabel:'Total/ Stip/ Decline'}
}
//Function that will be called recursively with specified Time Interval
function fetchData() {
//Function that will push data in to Series1 thru an ajax call
function getDPSStipData(series) {
var stipItem = [series.data[i][0], series.data[i][1]];
data_Total[0].push(stipItem);
}
$.ajax({
url: "./JSon/stipdpssec.json",
method: 'GET',
dataType: 'json',
success: getDPSStipData
});
//Function that will push data in to Series2 thru an ajax call
function getDPSDeclineData(series) {
var declineItem = [series.data[i][0], series.data[i][1]];
data_Total[1].push(declineItem);
}
$.ajax({
url: "./JSon/declinedpssec.json",
method: 'GET',
dataType: 'json',
success: getDPSDeclineData
});
//Function that will push data in to Series3 thru an ajax call
function getDPSTotalVolumeData(series) {
var totalVolItem = [series.data[i][0], series.data[i][1]];
data_Total[2].push(totalVolItem);
}
$.ajax({
url: "./JSon/totaldpssec.json",
method: 'GET',
dataType: 'json',
success: getDPSTotalVolumeData
});
//Moving forward the ticks if size > 10
if (data_Total[0].length > 10)
{
data_Total[0] = data_Total[0].splice(1,10);
data_Total[1] = data_Total[1].splice(1,10);
data_Total[2] = data_Total[2].splice(1,10);
}
// Plotting of Graph
//$.plot($("#placeholder4"), [{ data: data_Total[2], label: "TotalVolume"},{ data: data_Total[0], label: "Stip",yaxis:2 }, { data: data_Total[1], label: "Decline",yaxis:2 }], options);
somePlot=$.plot($("#placeholder4"), [{ data: data_Total[2], label: "TotalVolume",idx:0},{ data: data_Total[0], label: "Stip",color: "green",idx:1 }, { data: data_Total[1], label: "Decline",color:"red",idx:2 }], options);
i++;
}
//fetchData
setInterval(fetchData, 10000);
});
</script>
Here's a quick example I put together for you.
somePlot = null;
togglePlot = function(seriesIdx)
{
var someData = somePlot.getData();
someData[seriesIdx].lines.show = !someData[seriesIdx].lines.show;
somePlot.setData(someData);
somePlot.draw();
}
var data = [
{
label: 'foo',
color: 'red',
data: [[1, 300], [2, 300], [3, 300], [4, 300], [5, 300]],
idx: 0},
{
label: 'bar',
color: 'blue',
data: [[1, 800], [2, 600], [3, 400], [4, 200], [5, 0]],
idx: 1},
{
label: 'baz',
color: 'yellow',
data: [[1, 100], [2, 200], [3, 300], [4, 400], [5, 500]],
idx: 2},
{
label: 'dart',
color: 'green',
data: [[1, 500], [2, 350], [3, 400], [4, 700], [5, 50]],
idx: 3}
];
somePlot = $.plot($("#placeholder"), data, {
series: {
lines: {
show: true
}
},
legend: {
labelFormatter: function(label, series){
return ''+label+'';
}
}
});
You can provide legend clicks in a way that survives rerendering the graph like so:
HTML:
<div id=graph></div>
JS:
$('#graph').on('click', 'div.legend tr', function() {
var tr = $(this);
var index = tr.parent().find('tr').index(tr);
// Do something with the fact they clicked item (index)
});
There's nothing stored in the legend marking what each row represents, so you'll need to bring that info in from someplace else - all the above code does is get you the index of the legend item clicked.
For usability you should tell the user this is clickable:
CSS:
#graph div.legend tr {
cursor: pointer;
}