Pass Custom Parameter to query.send Google Query Language - javascript

I am using google's charts API to create a web-based dashboard. I want to draw many graphs and need to pass custom parameters to the handleDataQueryResponse function from this link: https://developers.google.com/chart/interactive/docs/spreadsheets#sheet-name. This function is called via a query.send(handleDataQueryResponse) call. I would have thought I could do this by calling: query.send(function() { handleDataQueryResponse(parameters) }); but this hasn't been working for me. Any ideas? Open to other approaches to making the query and its handler reusable!
More info on google's javascript chart API here: https://developers.google.com/chart/interactive/docs/quick_start.

something like this work for you?
google.charts.load('current', {
callback: function () {
drawChart0();
drawChart1();
},
packages:['corechart', 'table']
});
function drawChart0() {
var chart = new google.visualization.BarChart(document.getElementById('barchart'));
var query = "http://www.google.com/fusiontables/gvizdata?tq=SELECT 'Label' as beach, 'Pieces total' as Total FROM 1c-FiEDwdwMt55a4AlE8Xuu40rUBR_qeI8ENiHtPV";
var options = {
animation: {
duration: 500,
startup: true,
easing: 'out'
},
chartArea: {
width: '40%'
}
};
sendQuery(query, chart, options);
}
function drawChart1() {
var chart = new google.visualization.Table(document.getElementById('tablechart'));
var query = "https://docs.google.com/spreadsheets/d/19olM1pEF5qQvvKhwSH3d_X4w2DVfOWDwDtZKNFlMY3w/edit#gid=0&tq=select A, B where A >= date '2016-01-01'";
var options = {};
sendQuery(query, chart, options);
}
function sendQuery(query, chart, options) {
new google.visualization.Query(query).send(function (response) {
chart.draw(response.getDataTable(), options);
});
}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<div id="barchart"></div>
<div id="tablechart"></div>

I figured out one solution, and let me tell you, it's not pretty. But it works. As always, happy for improvements and feedback! Thanks #WhiteHat for helping me out.
google.charts.setOnLoadCallback(function() {
drawChart('chart1', 0, 'SELECT A, B, C, D, E', {title: 'Chart 1'})
drawChart('chart2', 1, 'SELECT A, H, I, J', {title: 'Chart 2'})
});
var chartsArray = [];
var optionsArray = [];
var nextID = 0;
function drawChart(tag, id, sqlCommand, options= {}, sheetName='Sheet1', numHeaders=1) {
chartsArray[id] = new google.visualization.ColumnChart(document.getElementById(tag));
optionsArray[id] = options;
var queryString = encodeURIComponent(sqlCommand);
var query = new google.visualization.Query(
'https://docs.google.com/spreadsheets/d/1dfRA_NDsdfED3OEdx-v3ZzA2-oWPS4kU_2mV-PY/gviz/tq?sheet=' + sheetName + '&headers=' + numHeaders.toString() + '&tq=' + queryString);
query.send(handleDataQueryResponse);
}
function handleDataQueryResponse(response, id) {
if (response.isError()) {
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
var data = response.getDataTable();
chartsArray[nextID].draw(data, optionsArray[nextID]);
nextID += 1;
}

Related

Chart JS chart not rendering in ArcGIS popup when using navigation arrows

I'm putting a chart in the popup of my points. On the initial click, the popups display the chart and if I use the forward navigation arrow on the popup, the next chart renders. However, if I use the back arrow the chart will not render again. The method that generates the charts doesn't seem to be firing the second time. Any help is appreciated. My code is below. Popup:
popupTemplate: {
title: "{Location}",
content: [{
type: "text",
text: "Sample Location: {Type} </br> Survey: {Survey} </br> {Location:getSurveyInfo} <div id='chartDiv'><canvas id='chartArea{Location}'>{Location:createChart}</canvas></div>"
},
{
type: "attachments"
}]
}
Chart:
createChart = function (location) {
var date = new Date();
var chartArea = "chartArea" + location;
var sub = location.substring(0, 2);
getData(date.getFullYear(), [[location]], function (data) {
var maxScale = Math.max(...data[0].tData);
var colors = [["#34eb58", "#0000ff"]];
var chartData = buildChartData(name, maxScale, data, colors, null);
var ctx = document.getElementById(chartArea);
var chart = new Chart(ctx, chartData);
}, getChartDataError)
}
I think you should not use the text content type for the popuptemplate. Using a function that return HTML element would be easier in your case.
popupTemplate: {
title: "{Location}",
content: createPopup
}
here your construct your popupElement and insert chart in it:
function createPopup(graphic) {
try {
var location = graphic.getAttribute("Location");
var popupElement = document.createElement("div");
popupElement.innerHTML = "Sample Location: " + graphic.getAttribute("Type") + "</br> Survey: " + graphic.getAttribute("Survey") + "</br>" + getSurveyInfo(location) + "<div class='chartDiv'></div>"
var date = new Date();
var sub = location.substring(0, 2);
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
getData(date.getFullYear(), [[location]], function(data) {
var maxScale = Math.max(...data[0].tData);
var colors = [["#34eb58", "#0000ff"]];
var chartData = buildChartData(name, maxScale, data, colors, null);
var chart = new Chart(ctx, chartData);
}, getChartDataError);
popupElement.querySelector(".chartDiv").appendChild(canvas);
return popupElement;
} catch(error) {
console.error(error)
}
}
See working demo: http://jsfiddle.net/bspa906m/3/

trying to show chessboard js in odoo form widget, no error no pieces

Hi i´m trying to show chessboardjs on a form view in odoo backend, I finally make the widget to show the board, but the pieces are hidden, I don´t know why because seems to work fine, except for the pieces. If I use dragable : true in the options and move a hidden piece then the board is rendered with all the pieces. do I´m missing something, on my code that the chessboard its not rendered well??
here is mi widget code:
(function (instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
openerp.chess_base = function (instance, local) {
local.YourWidgetClassName = instance.web.form.FormWidget.extend({
start: function () {
this.$el.append('<div id="board" style="width: 300px">BOARD GOES HERE</div>'); // creating the board in the DOM
this.onBoard();
},
onBoard: function (position, orientation) {
if (!position) {
this.position = 'start'
} else {
this.position = position
}
if (!orientation) {
this.orientation = 'white'
} else {
this.orientation = orientation
}
this.el_board = this.$('#board');
this.cfg = {
position: this.position,
orientation: this.orientation,
draggable: false,
pieceTheme: '/chess_base/static/img/chesspieces/wikipedia/{piece}.png'
};
this.board = ChessBoard(this.el_board, this.cfg);
}
});
instance.web.form.custom_widgets.add('widget_tag_name', 'instance.chess_base.YourWidgetClassName');
}
})(openerp);
I don't know why but this solve the issue, if someone have an explanation to me please ...
(function (instance) {
var _t = instance.web._t,
_lt = instance.web._lt;
var QWeb = instance.web.qweb;
openerp.chess_base = function (instance, local) {
local.ShowBoard = instance.web.form.FormWidget.extend({
start: function () {
this.$el.append('<div id="board" style="width: 300px">BOARD GOES HERE</div>');
this.show_board();
},
show_board: function () {
var Game = new instance.web.Model("chess.game"),
record_id = this.field_manager.datarecord.id,
record_name = this.field_manager.datarecord.name,
self = this;
self.el_board = self.$('#board');
Game.query(['pgn']).filter([['id', '=', record_id], ['name', '=', record_name]]).all().then(function (data) {
console.log(data);
self.cfg = {
position: data[0].pgn,
orientation: 'white',
pieceTheme: '/chess_base/static/img/chesspieces/wikipedia/{piece}.png'
};
ChessBoard(self.el_board, self.cfg);
});
}
});
instance.web.form.custom_widgets.add('board', 'instance.chess_base.ShowBoard');
}
})(openerp);

Highstock charts give "Uncaught TypeError: Cannot read property 'addPoint' of undefined" error

I am using the highstock charts library for a set of 4 charts. I used the options object and literal notation as described HERE. The 4 charts have the same set of options by default (the renderCharts() function in the code bellow is responsible for that) and there is a charts type picker (the setChatType() function ) with the help of which the user can change the chart type.
See all togheter HERE.
Can anyone please tell me the cause of and solution for this error in the console:
"Uncaught TypeError: Cannot read property 'addPoint' of undefined"?
Thank you!
/* ============ CHARTS OPTIONS BEGIN ============ */
var options = {
chart : {
zoomType: 'x',
events : {
load : function () {
// set up the updating of the chart each second
var series = this.series[0];
setInterval(function () {
var x = (new Date()).getTime();
var y = Math.round(Math.random() * 100);
series.addPoint([x, y]);
}, 1000);
}
}
},
rangeSelector: {
buttons: [{
count: 1,
type: 'minute',
text: '1M'
}, {
count: 5,
type: 'minute',
text: '5M'
}, {
type: 'all',
text: 'All'
}],
inputEnabled: false,
selected: 0
},
title : {
text: null
},
exporting: {
enabled: false
},
// Disable navigator
navigator : {
enabled : false
},
series : [{
name : '',
data : (function () {
// generate an array of random data
var data = [],
time = (new Date()).getTime(), i;
for (i = -999; i <= 0; i = i + 1) {
data.push([
time + i * 1000,
Math.round(Math.random() * 100)
]);
}
return data;
}())
}]
}
/* ============ CHARTS OPTIONS END ============ */
/* ============ DRAW CHARTS BEGIN ============ */
function renderCharts(){
$('div.chart-container').each(function(){
var chartId = $(this).attr('id');
var chartIdParts = chartId.split('-');
var chartIdentifier = chartIdParts[1];
//Set chart options dinamically
var chartId = "chart" + chartIdentifier;
var chart = $('#' + chartId);
var renderTo = "chartcontainer-" + chartIdentifier;
//Render Charts for each aech container
options.chart.renderTo = renderTo;
options.chart.type = 'line';
var chart = new Highcharts.StockChart(options);
});
}
function setChatType(){
// Show types list (piker)
$('.current-type').on('click', function(){
$(this).parents('div.chart-options').find('ul.type ul').addClass('clicked');
});
$('.chart-options ul ul li a').on('click', function(){
//Get piked chart type
var type = $(this).parent('li').attr('data-chart-type');
// For text and Title Capitalization
var textAndTitle = type.replace(/^[a-z]/, function(m){ return m.toUpperCase() });
// Show piked type in picker
var currSetClass = 'current-type ' + type;
$(this).parents('.chart-options').find('.current-type')
.text(textAndTitle)
.attr({
class : currSetClass,
title: textAndTitle
});
// Then Hide the types list
$('.chart-options ul ul').removeClass('clicked');
//Identify current chart container by ID
var chartCtnId= $(this).parents('div.chart').find('.chart-container').attr('id');
// Render chart again with new type
options.chart.renderTo = chartCtnId;
options.chart.type = type;
var chart = new Highcharts.StockChart(options);
});
}
/* ============ DRAW CHARTS END ============ */
$(document).ready(function(){
$("article.grid:even").addClass('left')
$("article.grid:odd").addClass('right');
// Draw charts
renderCharts();
// Set/change chart type
setChatType();
});
The solution, suggested by Pawel:
instead of
var chart = new Highcharts.StockChart(options);
use
var chart = new Highcharts.StockChart( $.extend(true, {}, options) );

AngularJS element directive with ng-init runs before view renders

I am attempting to loop through an array and create multiple instances of a custom directive that creates different graphs based on some variables on the rootScope. Everything works fine except when I try to place those in a view and call ng-init to a method on the scope and pass it arguments.
What I am finding is that ng-init seems to run before anything (and I think ng-init is the wrong approach), which causes errors because the variables being set in the method aren't set yet when the ng-init runs in the view.
When I first load the index view, then go into this view, all is well, but when I try to load this view first or reload it, I am getting the errors. The ng-init is trying to call the chart() method before anything else runs.
On the index view, I have this chart in a modal that gets called onclick, so ng-init is not needed, therefore it works great.
I am a little stuck and what I need is advice on the "right" or better way to accomplish this.
On the detail view, I need to loop across that array to get four charts based on four different objects of data.
The data is a static file for now, as this is a prototype.
My code is essentially this:
View:
<div id="chart_list">
<div class="chart" ng-repeat="val in ['abc', 'def', 'ghi', 'jkl']" ng-init="chart('line', val, itemId, val)">
<h3>{{val | uppercase}}</h3>
<chart/>
</div>
</div>
AppController method:
// get data set up for chart consumption
$scope.chart = function(chart, kpi, socId, chartId) {
$rootScope.visualize = {};
$rootScope.visualize.chart = chart;
$rootScope.visualize.chartId = chartId;
$rootScope.visualize.val = val;
$rootScope.visualize.item = $rootScope.itemList[itemId];
$rootScope.visualize.valName = $rootScope.visualize.item[val].name;
};
DetailView controller:
app.controller('ItemDetailController', function($scope, $rootScope, $routeParams, ItemList) {
var itemId = $scope.itemId = $routeParams.itemId;
ItemList.get({}, function(res) {
$rootScope.itemList = res.data;
$scope.item = $rootScope.itemList[itemId];
});
});
Service:
app.factory('ItemList', function($resource){
return $resource("/api/item-list.json");
});
Directive:
app.directive('chart', function() {
return {
restrict: 'E',
link: function(scope, element, attrs){
if ($(window).width() <= 1200){
var width = 300;
} else {
var width = 450;
}
var visualize = scope.visualize;
var data = visualize.soc[visualize.val].data;
var numTicks = Object.keys(data).length;
element.append('<div class="chart_container"><div id="y_axis' + visualize.chartId +'" class="y_axis"></div><div id="chart' + visualize.chartId + '" class="chart"></div><div id="x_axis' + visualize.chartId + '" class="x_axis"></div></div>');
element.append('<div id="legend_container' + visualize.chartId +'" class="legend_container"><div id="smoother' + visualize.chartId +'" title="Smoothing"></div><div id="legend' + visualize.chartId +'"></div></div>');
var valSeries = [];
var valSeries2 = [];
var valSeries3 = [];
var valMap = {};
var i = 0;
Object.keys(data).forEach(function(propertyName) {
var value = data[propertyName];
var val2 = (Math.random() * (102 - 87) + 86) / 100;
var val3 = (Math.random() * (95 - 70) + 69) / 100;
valSeries.push({x: i, y: data[propertyName].amount});
valSeries2.push({x: i, y: data[propertyName].amount * val2});
valSeries3.push({x: i, y: data[propertyName].amount * val3});
valMap[i] = data[propertyName].name;
i++;
});
var graph = new Rickshaw.Graph({
element: document.querySelector('#chart' + visualize.chartId),
width: width,
height: 150,
renderer: visualize.chart,
stroke: true,
series: [
{
data: valSeries3,
color: '#F0AD4E',
name: 'Three years ago',
},
{
data: valSeries2,
color: '#5BC0DE',
name: 'Two years ago',
},
{
data: valSeries,
color: '#5CB85C',
name: 'Past year'
}
]
});
var format = function(n) {
var map = valMap;
return map[n];
}
var x_ticks = new Rickshaw.Graph.Axis.X({
graph: graph,
width: width,
orientation: 'bottom',
element: document.getElementById('x_axis' + visualize.chartId),
pixelsPerTick: width/numTicks,
tickFormat: format
});
var y_axis = new Rickshaw.Graph.Axis.Y({
graph: graph,
orientation: 'left',
tickFormat: Rickshaw.Fixtures.Number.formatKMBT,
element: document.getElementById('y_axis' + visualize.chartId),
});
graph.render();
var hoverDetail = new Rickshaw.Graph.HoverDetail({
graph: graph,
formatter: function(series, x, y) {
var content = app.lib[visualize.dataFormat](parseInt(y)) + "<br>";
return content;
}
});
var legend = new Rickshaw.Graph.Legend( {
graph: graph,
element: document.getElementById('legend' + visualize.chartId)
} );
var shelving = new Rickshaw.Graph.Behavior.Series.Toggle( {
graph: graph,
legend: legend
} );
}
};
});
Edit:
I fixed this by removing the chart method altogether and replacing ng-init with attributes. Something like this:
<chart data-attrone="somedata" data-attrtwo="some other data" />
Then the attrs are available in the directive with attrs.attrone, etc.
Attribute names must be lower-case.
Hope this helps someone in the future.
I fixed this by removing the chart method altogether and replacing ng-init with attributes. Something like this:
<chart data-attrone="somedata" data-attrtwo="some other data" />
Then the attrs are available in the directive with attrs.attrone, etc.
Attribute names must be lower-case.
Hope this helps someone in the future.

How to fuse these two javascript files?

I have a javascript file that is loading up the google charts API and drawing a graph, and another javascript file that handles an html form on the page. I'd like to fuse these two together, as the form will be providing the graph with data. However, when I try to put there google charts js file (graph.js), it refuses to load the graph. I've tried putting it in several locations, but it only loads if the graph.js is a separate js file that is linked within the html document. Can someone tell me how I can properly combine these two files:
CostComparer.js (the form handler):
$(document).ready(function(){
//variable setup
var wifi;
var firewall;
var backup;
var vpn;
var install;
var result;
$('#submit').click(function(){
$("#chart_div").show('slow');
$("#table_div").show('slow');
wifi = $('input[name=wifiPrice]').val();
firewall = $('input[name=firewallPrice]').val();
backup = $('input[name=backupPrice]').val();
vpn = $('input[name=vpnPrice]').val();
install = $('input[name=installPrice]').val();
result = parseInt(wifi) + parseInt(firewall) + parseInt(backup) + parseInt(vpn) + parseInt(install);
var resultbox = $('#result');
var cccontainer = $('#cccontainer');
if(resultbox.height() < 10){
cccontainer.hide('slow').delay(500);
cccontainer.show('slow');
setTimeout(function() {
resultbox.append('<h1>You Paid: <br />$' + result + '</h1>')
}, 500);
} else {
resultbox.empty()
cccontainer.hide('slow').delay(500);
cccontainer.show('slow');
setTimeout(function() {
resultbox.append('<h1>You Paid: <br />$' + result + '</h1>')
}, 500);
}
});
});
and graph.js:
google.load("visualization", "1", {packages: ["corechart"]});
google.setOnLoadCallback(drawChart);
var competitorCost = function(time){
return 3000 + (time * 300)
};
var ourCost = function(time){
return 1000 + (time * 50);
};
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Months', 'Entreda', 'Competitors'],
['0', ourCost(0), competitorCost(0)],
['6', ourCost(6), competitorCost(6)],
['12', ourCost(12), competitorCost(12)],
['18', ourCost(18), competitorCost(18)],
['24', ourCost(24), competitorCost(24)]
]);
var options = {
title: 'Entreda vs Competitor Costs',
width: 445,
height: 250,
pointSize: 5
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}
There was a problem with my compiler it seems. It worked after appending graph.js to the bottom outside of $document.ready():
$(document).ready(function(){
//variable setup
var wifi;
var firewall;
var backup;
var vpn;
var install;
var result;
$('#submit').click(function(){
$("#chart_div").show('slow');
$("#table_div").show('slow');
wifi = $('input[name=wifiPrice]').val();
firewall = $('input[name=firewallPrice]').val();
backup = $('input[name=backupPrice]').val();
vpn = $('input[name=vpnPrice]').val();
install = $('input[name=installPrice]').val();
result = parseInt(wifi) + parseInt(firewall) + parseInt(backup) + parseInt(vpn) + parseInt(install);
var resultbox = $('#result');
var cccontainer = $('#cccontainer');
if(resultbox.height() < 10){
cccontainer.hide('slow').delay(500);
cccontainer.show('slow');
setTimeout(function() {
resultbox.append('<h1>You Paid: <br />$' + result + '</h1>')
}, 500);
} else {
resultbox.empty()
cccontainer.hide('slow').delay(500);
cccontainer.show('slow');
setTimeout(function() {
resultbox.append('<h1>You Paid: <br />$' + result + '</h1>')
}, 500);
}
});
});
google.load("visualization", "1", {packages: ["corechart"]});
google.setOnLoadCallback(drawChart);
var competitorCost = function(time){
return 3000 + (time * 300)
};
var ourCost = function(time){
return 1000 + (time * 50);
};
function drawChart() {
var data = google.visualization.arrayToDataTable([
['Months', 'Entreda', 'Competitors'],
['0', ourCost(0), competitorCost(0)],
['6', ourCost(6), competitorCost(6)],
['12', ourCost(12), competitorCost(12)],
['18', ourCost(18), competitorCost(18)],
['24', ourCost(24), competitorCost(24)]
]);
var options = {
title: 'Entreda vs Competitor Costs Over Time',
width: 480,
height: 270,
pointSize: 5
};
var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
chart.draw(data, options);
}

Categories

Resources