Google Visualization API clickable chart-items - google-visualization

I am using GV-API to publish a piechart with information on my website. De items published are not clickable by default, but I thought I found a way in their documentation (https://developers.google.com/chart/interactive/docs/reference#numberformatter)
Implementation as follows:
<div id="chart_{!! $id !!}"></div>
<script type="text/javascript">
google.charts.setOnLoadCallback(function() {
var data = google.visualization.arrayToDataTable({!!json_encode($data)!!});
var options = {!! json_encode($options) !!};
var formatter = new google.visualization.PatternFormat('{0}');
formatter.format(data, [0, 1]);
var material = new google.visualization.PieChart(document.getElementById('chart_{!! $id !!}'));
material.draw(data, options);
});
And indeed this enforces a kind of formatting, but unfortunately the information is shown as plain text, not as a clickable URL. It is a bit weird, since this is almost the same as the example in the documentation.
I searched the web for solutions, but most of them refer to deprecated API's.
Any help appreciated

Related

Wkhtmltopdf does not render Chart.JS 2.5.0 graph

Using:
WKpdftohml version 0.12.3.2
PHPwkhtmltopdf version 2.2.0
Chart.JS version 2.5.0
I'm trying to print a line graph using the above libraries. I can reproduce a pdf using the shell command: wkhtmltopdf --javascript-delay 5000 " http://netdna.webdesignerdepot.com/uploads7/easily-create-stunning-animated-charts-with-chart-js/chartjs-demo.html" test2.pdf
So there is no problem with WKhtmltopdf.
The problem is when I do it in my app, using the PHPwkhtmltopdf library. I get a blank page.
From my research these are the things I tried:
Added 'javascript-delay' => 500 to Chart.JS options;
Added animation:{onComplete: function () {window.JSREPORT_READY_TO_START =true} to Chart.JS options;
Added <div style="width:800px;height:200;font-size:10px;"> to the parent div of canvas html tag
Added ctx.canvas.width = 800;ctx.canvas.height = 200; to javascript initialization of the chart.
Well nothing worked. I love Chart.JS and WKhtmltopdf, but if I can't print I'll have to drop one of them. Is there any solution?
This is my php code for the PHPwkhtmltopdf:
public function imprimir ($request, $response)
{
// include_once 'config/constants.php';
// include_once 'resources/auxiliar/helpers.php';
$folha = $_POST['printit'];
$variaveis = explode(',', $folha);
$nomeFicheiro = $variaveis[0];
$printName = substr($nomeFicheiro, 5);
if (isset($variaveis[2])) {
$_SESSION['mesNumero'] = $variaveis[2];
$_SESSION['mes'] = $variaveis[1];
} else {
$mesNumero = 0;
$mes = '';
}
ob_start();
if ($nomeFicheiro == 'printPpiam') {
require ('C:/xampp/htdocs/.../'.$nomeFicheiro.'.php');
} else {
require ('C:/xampp/htdocs/.../'.$nomeFicheiro.'.php');
}
$content = ob_get_clean();
// You can pass a filename, a HTML string, an URL or an options array to the constructor
$pdf = new Pdf($content);
// On some systems you may have to set the path to the wkhtmltopdf executable
$pdf->binary = 'C:/Program Files/wkhtmltopdf/bin/wkhtmltopdf';
$pdf -> setOptions(['orientation' => 'Landscape',
'javascript-delay' => 500,
// 'enable-javascript' => true,
// 'no-stop-slow-scripts' => true]
]);
if (!$pdf->send($printName.'.pdf')) {
throw new Exception('Could not create PDF: '.$pdf->getError());
}
$pdf->send($printName.'.pdf');
}
# Update 1
Made a php file with the page output. Run it in the browser and the graph rendered. When I do it in the console it renders everything except the graph!
How can it be wkhtmltopdf renders the graphics in this page : http://netdna.webdesignerdepot.com/uploads7/easily-create-stunning-animated-charts-with-chart-js/chartjs-demo.html but not my own?!
# Update 2
After Quince's comment, I tried just turning the animations off, but I'm not sure on how to do that. I tried:
$pdf -> setOptions(['orientation' => 'Landscape',
'javascript-delay' => 500,
// 'window-status' => 'myrandomstring ',
'animation' => false,
'debug-javascript',
'no-stop-slow-scripts',
]);
But it fails.
Here's the code that works with wkhtmltopdf version 0.12.5:
chart.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<style>
.reportGraph {width:900px}
</style>
</head>
<body>
<div class="reportGraph"><canvas id="canvas"></canvas></div>
<script type="text/javascript">
// wkhtmltopdf 0.12.5 crash fix.
// https://github.com/wkhtmltopdf/wkhtmltopdf/issues/3242#issuecomment-518099192
'use strict';
(function(setLineDash) {
CanvasRenderingContext2D.prototype.setLineDash = function() {
if(!arguments[0].length){
arguments[0] = [1,0];
}
// Now, call the original method
return setLineDash.apply(this, arguments);
};
})(CanvasRenderingContext2D.prototype.setLineDash);
Function.prototype.bind = Function.prototype.bind || function (thisp) {
var fn = this;
return function () {
return fn.apply(thisp, arguments);
};
};
function drawGraphs() {
new Chart(
document.getElementById("canvas"), {
"responsive": false,
"type":"line",
"data":{"labels":["January","February","March","April","May","June","July"],"datasets":[{"label":"My First Dataset","data":[65,59,80,81,56,55,40],"fill":false,"borderColor":"rgb(75, 192, 192)","lineTension":0.1}]},
"options":{}
}
);
}
window.onload = function() {
drawGraphs();
};
</script>
</body>
</html>
Run:
$ wkhtmltopdf chart.html chart.pdf:
Loading pages (1/6)
Counting pages (2/6)
Resolving links (4/6)
Loading headers and footers (5/6)
Printing pages (6/6)
Done
Found the answer. After I created a separate file, outside the framework, i did some tests again. It rendered the graph in the browser so I tried to use the command tool WKhtmltopdf, and it did not worked, when it did with other examples (see Update #1). So there is something wrong with my php page.
Ran the same tests that I did in the framework, and got the answer for my problem. By introducing a parent div tag width dimensions in the canvas tag it made the graph render in the page.
<div style="width:800px;height:200;">
<canvas id="myChart" style="width:800px;height:200;"></canvas>
</div>
The proposition was found in this site: Github, so thanks laguiz.
Try adding this, as according to this github source
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.0.0/polyfill.min.js"></script>
Solved it by downgrading wkhtmltopdf: 0.12.4 > 0.12.2.1
chart.js version seemed to have no influence. I used 2.7.0.
Fixed width and height seem to be required as well.
Edit: Since wkhtmltopdf is dead, I switched to Puppeteer recently.
I was dealing with the same issue using rotativa to export my ASP.NET MVC page with Chart.JS to PDF with no luck.
After a couple of days I finally found a super-easy solution to achieve my goal. What I did is simply to use the .toBase64Image() method of Chart.JS to encode the chart to a base64 string variable in Javascript. Then I saved this string into a model and then on the PDF html page a used tag where i put the base64encoded string to a scr property and the result is great :-)
javascript:
//save Chart as Image
var url_base64 = document.getElementById('myChart').toDataURL('image/png');
//set the string as a value of a hidden element
document.getElementById('base64graph').value = url_base64;
PDF view:
<img style='display:block; width:900px;height:400px;position:relative;margin:auto;text-align:center;' id='base64image'
src='#Model.base64graph' />
I'm trying to improve on the answer by temuri, which is great, but a bit bloated. I ran into the OP's issues (even same WKpdftohml version) and this did the trick for me:
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js"></script>
<div style="width: 400px;"><canvas id="canvas"></canvas></div>
<script type="application/javascript">
// wkhtmltopdf 0.12.5 crash fix.
// https://github.com/wkhtmltopdf/wkhtmltopdf/issues/3242#issuecomment-518099192
Function.prototype.bind = Function.prototype.bind || function (thisp) {
const fn = this;
return function () {
return fn.apply(thisp, arguments);
};
};
new Chart(
document.getElementById("canvas"), {
"responsive": false,
"type":"line",
"data":{"labels":["January","February","March","April","May","June","July"],"datasets":[{"label":"My First Dataset","data":[65,59,80,81,56,55,40],"fill":false,"borderColor":"rgb(75, 192, 192)","lineTension":0.1}]},
"options":{}
}
);
</script>
I'm yet to figure out how to get the chart library via ordinary tools like npm, instead of getting it via ajax like here in the first line. Note that this can impact your chart resolution.
I was strugling with that too and you self-answer did not help my case. I am using symfony 3.3 and Chart.js 2 and whatever I did, did not work properly. So I have solved it in a different manner (maybe not a clean one) and I wanted to post it here for inspiration to others.
I needed to export a page, that I was presenting to the user in a browser. In browser, I used Javascript to get picture out of the rendered graph with
animation: {
onComplete: function(animation) {
console.log('done');
var url=document.getElementById("barChartByCountryWeight{{ part }}{{ subsetKey }}").toDataURL();
$.ajax({
url: 'saveChartImages',
type: 'POST',
data: { 'barChartByCountryWeight{{ part }}{{ subsetKey }}': url },
success: function(result) {
console.log(result);
console.log('the request was successfully sent to the server');
},
error: function (request, error) {
console.log(arguments[0]['responseText']);
console.log(" Can't do because: " + error);
}
});
}
}
And on server side I put it in session and in a controller for the PDF export, I have taken the image from session and put the image in the HTML, that is converted to PDF.
Hope that helps.
I have implemented the working code for this issue. You can check out the working code here.
NOTE: For generating pdf you must disable the Chart JS animation or add the option javascript-delay=>1000 to the wkhtmltopdf options.
I have solved this problem when I tried to use Chartjs 1 instead of a new chart js. The reason for this is because laravel snappy uses wkhtmltopdf, which doesn't support css animation, while new chartjs uses css animation.
This github issue shows that.
The solution i found is to use google chart instead. It also uses svg, so you can get high resolution charts.

Populating a Google Charts Dashboard with an external Google Sheet

I just got finished implementing the solution from this question on a similar topic, but the solution is not working for me.
I'm trying to create a dashboard that uses data from a google spreadsheet but I can't seem to get it to load correctly.
I routinely get the following error message whenever I load the web page:
One or more participants failed to draw()
Here's the code I'm using right now:
<html>
<head>
<script type="text/javascript">
// Load the Visualization API and the controls package.
google.charts.load('current', {'packages':['corechart', 'controls']});
// Set a callback to run when the Google Visualization API is loaded.
google.charts.setOnLoadCallback(initialize);
function initialize() {
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws/edit#gid=0');
query.send(drawDashboard)
}
// Callback that creates and populates a data table,
// instantiates a dashboard, a range slider and a pie chart,
// passes in the data and draws it.
function drawDashboard(response) {
// Create our data table.
var data = response.getDataTable();
// Create a dashboard.
var dashboard = new google.visualization.Dashboard(
document.getElementById('dashboard_div'));
// Create a range slider, passing some options
var donutRangeSlider = new google.visualization.ControlWrapper({
'controlType': 'NumberRangeFilter',
'containerId': 'filter_div',
'options': {
'filterColumnLabel': 'Donuts eaten'
}
});
// Create a pie chart, passing some options
var pieChart = new google.visualization.ChartWrapper({
'chartType': 'PieChart',
'containerId': 'chart_div',
'options': {
'width': 300,
'height': 300,
'pieSliceText': 'value',
'legend': 'right'
}
});
// Establish dependencies, declaring that 'filter' drives 'pieChart',
// so that the pie chart will only display entries that are let through
// given the chosen slider range.
dashboard.bind(donutRangeSlider, pieChart);
// Draw the dashboard.
dashboard.draw(data);
}
</script>
</head>
<body>
<div id="dashboard_div">
<!--Divs that will hold each control and chart-->
<div id="filter_div"></div>
<div id="chart_div"></div>
</div>
</body>
</html>
Link to the spreadsheet can be seen here: https://docs.google.com/spreadsheets/d/1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws/edit#gid=420659822
The dashboard I'm trying to draw is taken directly from the source documentation listed here: https://developers.google.com/chart/interactive/docs/gallery/controls
I'm trying to follow the example about loading external spreadsheets here: https://developers.google.com/chart/interactive/docs/spreadsheets
The link to the working file I'm using for this project can be seen here: https://s3-us-west-2.amazonaws.com/example-server/index.html
I've tried removing all header links and styling in the previous link to verify nothing else was interfering with the visualization API and this did not solve the problem either.
Also:
Privacy for the spreadsheet is set to 'Public on the web'
The link being used in the query is taken directly from the address bar, but I also used the 'sharing link' provided by google when you prompt for it.
I'm using data that's exactly the same as the examples in the google documentation to make implementation as easily as possible.
Edit
Due to an answerer's prompt, I experiemented with different modifications of my query URL, which so far have not worked.
Here's the URL in my address bar:
URL
It's a single sheet document.
In response to the first answer, I've tried the following query URL's, but without success.
First:
https://docs.google.com/spreadsheets/d/1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws/gviz/tq?sheet=Sheet1
Second:
https://docs.google.com/spreadsheets/d/1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws/gviz/tq?gid=0
Third:
https://docs.google.com/spreadsheets/d/1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws/gviz/tq?gid=1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws
The idea behind this last URL is that in the new google sheets the gid is the string after d/ and before /edit.
Your help is greatly appreciated.
Find your dataSourceURL at:
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws/edit#gid=0');
Replace:
edit#gid=0
with:
gviz/tq?sheet=Sheet1
If that doesn't work, then you'll need to use the gid which is a unique 9 to 10 digit number. (ex. gid=1104711743). Open your sheet and look at the address bar, you should see it at the end of the url.
Your line should look like this:
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1FnETUo8yrthFBdUYsQ8Ty9e8pK3ouWZntvDnXlhHKws/gviz/tq?gid=1234567890');

using a famo.us surface to link to another URL

Seems like this should be obvious but...How can you use a famo.us surface as a link to another webpage?
I've tried:
this.fooSurface.on("click", function(){
window.location.replace("www.foo.com");
});
but this doesn't replace the URL, it just puts the new URL on the end of the address currently in the URL bar. window.location.href = "www.foo.com" has the same result.
EDIT: window.location.assign("www.foo.com") and window.location = ("foo") also have the same result. I think this has something to do with this script in the boilerplate index.html:
<script type="text/javascript">
require.config({baseUrl: 'src/'});
require(['main']);
</script>
Use window.location.assign("http://www.foo.com"); instead.
I probably wouldn't use the replace() method personally, as replace() switches the current page's place in the document history with that of the one you provide to the method, which I can't say I've ever found beneficial as a user unless there's a blank intermediary login page or something very specific (and temporary).
Or you can even just use window.location = "http://www.foo.com";
https://developer.mozilla.org/en-US/docs/Web/API/Window.location
I was able to get things working just fine with the boilerplate generator-famous gives you.
The script tag has nothing to do with it. That's configuration for RequireJS to load in the famo.us library with AMD.
var logo = new ImageSurface({
size: [200, 200],
content: '/content/images/famous_logo.png',
classes: ['backfaceVisibility']
});
logo.on('click', function() {
window.location.href ='http://www.google.com';
});
This problem you're having is also not a famo.us problem. It's your Javascript...

Google geochart doesn't show continents

I'm using google geochart to display data.
My code:
<script type='text/javascript' src='https://www.google.com/jsapi'></script>
<script type='text/javascript'>
google.load('visualization', '1', { 'packages': ['geochart'] });
google.setOnLoadCallback(drawRegionsMap);
function drawRegionsMap() {
var geochart = new google.visualization.GeoChart(
document.getElementById('visualization'));
var options = {region: 'world', resolution: 'continents', width: 556, height: 347};
var data = google.visualization.arrayToDataTable([
['continents', 'Aircrafts'],
['Asia', 700]
]);
geochart.draw(data, options);
};
</script>
<div id="visualization" style="width: 800px; height: 400px;"></div>
In chart it doesn't show asia as data.
Although the 'continents' resolution option isn't in the official docs it does work. You need to change your data table to include a column of continent region codes, e.g.:
var data = google.visualization.arrayToDataTable([
['Region code', 'Continent', 'Aircraft'],
['142', 'Asia', 700]
]);
geochart.draw(data, options);
The region codes are required but don't get rendered in the tooltips. The codes matching each continent are explained here, beneath the options in the section called 'Continent Hierarchy and Codes'. It doesn't actually say you need to use them in your data table (that would be too easy...)
The only caveat is that I haven't yet found a way to get it to recognise the subregion codes that will allow separating 'Americas' into North & South. If you stick to using the continent codes then they should work - they do for me. Note that the codes need to be in the data table as strings.
See here for a working example : http://jsfiddle.net/6hrhj9qs/
You are using undocumented options described in this post
There it was also said that this bug would be fixed soon... and date was 5/25/11!
I didn't find other update.
Try using VectorWorkz' GeoChart, it supports Asia as a Continent and you have full control of the regions and add/modify the underlying maps to your needs. We can help create custom maps for you too.

Automatically Embed Youtube Videos From URI

How would you go about embedding youtube vidoes automatically from the URI.
Say for example you type in a textbox:
The quick brown fox jumped over this video http://www.youtube.com/watch?v=5qm8PH4xAss&feature=player_embedded and then fell into this http://www.youtube.com/watch?v=lSCSmpV8Nn8&feature=hp_SLN&list=SL
You press submit and the results are displayed back to you. In place of the youtube links you have the actual flash files.
(In php naturally, or any language).
I know you could use Regex (preg_replace .etc), however how would you remove the extra queries that youtube provides (i.e. &feature=blah), and turn everything into something like: http://www.youtube.com/v/5qm8PH4xAss, ready to be placed into an object to embed.
Sorry for the long question,.. I hope you understand it. :)
i think you are looking for something like this:
try it here : http://www.jsfiddle.net/feridcelik/qu6U6/2/
<script src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script src="http://jquery.lukelutman.com/plugins/flash/jquery.flash.js"></script>
<script type="text/javascript">
var yt="http://www.youtube.com/v/";
$("a[href^='http://www.youtube.com/watch?v=']").each(function(){
var key;
var href =$(this).attr("href");
var i=href.indexOf("v");
href=href.substring(i+2,href.length);
i=href.indexOf("&");
if(i>-1){
key=href.substring(0,i);
}
href=yt+key;
$(this).after("<a href='"+href+"' class='video'></a>");
});
$('.video').flash(
{ height: 200, width: 200},
{ version: 8 },
function(htmlOptions) {
$this = $(this);
htmlOptions.src = $this.attr('href');
$this.before($.fn.flash.transform(htmlOptions));
}
);
$('.video').remove();
</script>
based on the flash plugin from:
http://jquery.lukelutman.com/plugins/flash/