| Bots de conversa | Exemples | Dades pràctiques | Recursos CITCEA | |
| Google Apps Script | Projectes | Interacció | Inici |
En aquest exemple agafarem unes dades que tenim en un full de càlcul i generarem una imatge vectorial en forma de diagrama de barres amb els valors del full de càlcul. En un exemple anterior hem suposat que el nostre full de càlcul sempre té el mateix nombre de dades i aquestes es mouen dins un rang definir. En l'exemple actual el nombre de dades pot ser qualsevol (superior a 1, per descomptat) i aquestes poden prendre qualsevol valor positiu.
La següent imatge mostra el contingut del full de càlcul en un moment donat:

El resultat que obtindrem serà el gràfic següent:

En el nostre cas podrem obtenir el gràfic de dues maneres. Una d'elles serà a l'executar l'script des del navegador (funció doGet) i obtindrem una pàgina web que contindrà el gràfic. L'altra serà accedint des de Telegram (funció doPost) i, en cas de fer servir la comanda /grafic obtindrem una imatge del gràfic i un enllaç per descarregar-lo en format PDF.
El programa és el següent:
var token = "^^34328844:AAFIpk-e7j3UZtYQYQaTduf4hEhnDqIcNXI"; // API Token de Telegram
var telegramUrl = "https://api.telegram.org/bot" + token; // URL que comunica el bot de conversa amb Telegram
var ssId = "^^ThsoSjkeMSfwEKy4mn_4QEYH96sxv3VURqE3WHCTswDA"; // Identificador del full de càlcul
var id_carpeta = "^^Hlod5Y4qEsLF9HrIsE6oYQa32f6NHeo"; // Carpeta on guardarem el fitxer
// Definim els colors que surten al gràfic
var negre = "#000000";
var blau = "#0000FF";
var gris = "#CCCCCC";
var transparent = "null";
function doGet(e){
var resp = grafic(); // Creem el gràfic
var nomFitxer = "grafic"; // Nom del fitxer
// Creem el fitxer
var fitxerNou = DriveApp.getFolderById(IdCarpeta).createFile(nomFitxer + ".svg",resp);
var idFitxer = fitxerNou.getId(); // Identificador del fitxer
var urlDescFitxer = fitxerNou.getDownloadUrl(); // Adreça per descarregar el fitxer
var urlFitxer = "https://drive.google.com/uc?export=view&id=" + idFitxer; // Adreça per veure el fitxer
// Codi HTML de la pàgina web
var pagina = "<!DOCTYPE HTML>" + "\n";
pagina = pagina + "<html>" + "\n";
pagina = pagina + "<head>" + "\n";
pagina = pagina + "<meta charset='UTF-8'>" + "\n";
pagina = pagina + "</head>" + "\n";
pagina = pagina + "<body>" + "\n";
pagina = pagina + "<h1>Valors de la setmana passada</h1>" + "\n";
pagina = pagina + resp + "\n";
pagina = pagina + "</body>" + "\n";
pagina = pagina + "</html>" + "\n";
return HtmlService.createHtmlOutput(pagina); // Retorna la pàgina web
}
function doPost(e){
var data = JSON.parse(e.postData.contents); // Llegeix les dades rebudes per JSON i les guarda
var text = data.message.text; // Comanda enviada
var id = data.message.chat.id; // Identificador de la finestra d'on prové el missatge
var id_usuari = data.message.from.id; // Identificador de l'usuari
var id_missatge = data.message.message_id; // Identificador del missatge
var lang = data.message.from.language_code ; // Idioma de l'usuari
var nom_usr = data.message.from.first_name ; // Nom de l'usuari
var location = data.message.location; // Localització de l'usuari (si es sap)
var realitzat = false;
if(text == '/grafic'){
var resposta = "Estem preparant el gràfic. Espera un moment."; // Missatge que s'envia
sendText(id,resposta); // mentre es prepara el gràfic, perquè triga una mica
var resp = grafic(); // Genera el gràfic
var nomFitxer = "grafic"; // Nom del fitxer
var fitxerNou = DriveApp.getFolderById(IdCarpeta).createFile(nomFitxer + ".svg",resp); // Crea el fitxer
var idFitxer = fitxerNou.getId(); // Identificador del fitxer
var urlDescFitxer = fitxerNou.getDownloadUrl(); // Enllaç per descarregar el fitxer
// Enllaç per veure el fitxer al navegador
var urlFitxer = "https://drive.google.com/uc?export=view&id=" + idFitxer;
var blob = UrlFetchApp.fetch(urlFitxer).getBlob(); // Agafa el gràfic en format binari
var b64 = blob.getContentType() + ';base64,'+ Utilities.base64Encode(blob.getBytes());
// Creem una pàgina web de mínims que serà la base del PDF
var htmlEst = '<style type="text/css" media="print">@page {size: landscape;} </style>';
var htmlInst = htmlEst + '<img src="data:' + b64 + '" width=900 alt="Gràfic">';
var html = HtmlService.createHtmlOutput(htmlInst); // Crea la pàgina web
// Crea el PDF
var pdf = DriveApp.createFile(html.getAs("application/pdf").setName(nomFitxer + ".pdf"));
var urlDescPDF = pdf.getDownloadUrl(); // Enllaç per descarregar el fitxer
var pdfId = pdf.getId(); // Identificador del fitxer
var repetir = true;
// Hem d'esperar que estigui llesta la miniatura
var cnt = 0; // Comptador de dècimes de segon
while(repetir){ // Mentre no estigui
var thumb = DriveApp.getFileById(pdfId).getThumbnail(); // Mirem si ja s'ha creat la miniatura
Utilities.sleep(100); // Esperem una dècima de segon
cnt++;
if((cnt > 100) || (thumb)){ // Si ja està o han passat deu segons
repetir = false; // Sortim del bucle
}
}
// El títol conté l'enllaç
var descrip = "Pots descarregar el PDF aquí: " + urlDescPDF;
sendBlobFile(id,thumb,descrip); // Enviem la imatge
realitzat = true;
}
if (!realitzat){
var resposta = "Comanda desconeguda";
sendText(id,resposta);
}
}
function grafic(){
var resp = "";
var sh = SpreadsheetApp.openById(ssId).getSheetByName("linia"); // Agafem el full
var dades = sh.getDataRange().getValues(); // Llegim les dades
// Guardem els valors en un vector i ens quedem amb el màxim
var valors = new Array();
var maxY = 0; // El màxim, de moment, és zero
for (var i in dades){ // Mirem totes les dades
if (i > 0){ // Ignorem la línia dels títols
var row = dades[i]; // Llegeix una filera
valors.push(row[0]); // Guardem els valors
if (row[0] > maxY){ // Busquem el màxim
maxY = row[0]; // Guardem el valor més alt
}
}
}
var numVal = valors.length; // Nombre de punts
// Decidim quantes marques tindrà cada eix i amb quines separacions
maxY = arrod(maxY, 2);
var divY = maxY / 10; // Arrodoneix, per excés, a dues xifres
// Creem la capçalera
var grafic = cap(640, 480, "Capa 1")+ '\n';
// Fem els eixos
var zeroX = 50;
var zeroY = 435;
var fiX = 620;
var fiY = 25;
grafic = grafic + linia(zeroX-5, zeroY, fiX, zeroY, 3, negre, "eixX") + '\n';
grafic = grafic + linia(zeroX, fiY, zeroX, 440, 3, negre, "eixY") + '\n';
// Posem les divisions de l'eix Y
for (var i = 0; i <= 10; i++){ // Sempre són 10 divisions
var ym = zeroY - ((zeroY - fiY) / 10) * i;
var valor = divY * i;
var noml = 'm' + i;
var nomt = 'tm' + i;
var nomq = 'q' + i;
grafic = grafic + linia(zeroX-5, ym, zeroX, ym, 2, negre, noml) + '\n';
grafic = grafic + text(zeroX-10, ym+5, valor, 16, negre, "d", 0, 0, nomt) + '\n';
}
// Posem les divisions de l'eix X
var xm;
var val;
for(var i = 0; i < 5; i++){
val = Math.ceil(i * numVal / 4);
if (i == 0){
val = 1;
}
xm = zeroX + ((fiX - zeroX) / (numVal - 1)) * (val - 1);
var nomlh = 'mx' + i;
var nomth = 'tx' + i;
var nomqh = 'qx' + i;
grafic = grafic + linia(xm, zeroY+5, xm, zeroY, 2, negre, nomlh) + '\n';
grafic = grafic + text(xm, zeroY + 25, val, 16, negre, "c", 0, 0, nomth) + '\n';
}
// Dibuixem la línia del gràfic
for (var i = 1; i < numVal; i++){
var nomlg = 'L' + i;
var xp = zeroX + ((fiX - zeroX) / (numVal - 1)) * (i - 1);
var xm = zeroX + ((fiX - zeroX) / (numVal - 1)) * i;
var yp = zeroY - ((zeroY - fiY) / maxY) * valors[i-1];
var ym = zeroY - ((zeroY - fiY) / maxY) * valors[i];
grafic = grafic + linia(xp, yp, xm, ym, 4, blau, nomlg) + '\n';
}
// Posem el final del fitxer svg
grafic = grafic + peu();
return grafic;
}
function linia(xi, yi, xf, yf, gruix, color, ident){
var resp = '<line id="' + ident + '" x1="' + xi + '" y1="' + yi + '" x2="' + xf + '" y2="' + yf;
resp = resp + '" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null" stroke-width="';
resp = resp + gruix + '" stroke="' + color + '" fill="none"/>';
return resp;
}
function text(x, y, txt, mida, color, alin, negreta, cursiva, ident){
if (alin == "e"){ // Esquerra
var aln = "start";
}
if (alin == "c"){ // Centre
var aln = "middle";
}
if (alin == "d"){ // Dreta
var aln = "end";
}
var resp = '<text id="' + ident + '" xml:space="preserve" text-anchor="' + aln;
resp = resp + '" font-family="serif" font-size="' + mida + '" x="' + x + '" y="' + y +'"';
if (negreta == 1){
resp = resp + ' font-weight="bold"';
}
if (cursiva == 1){
resp = resp + ' font-style="italic"';
}
resp = resp + ' stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null"';
resp = resp + ' stroke-width="0" stroke="';
resp = resp + color + '" fill="' + color + '">' + txt + '</text>';
return resp;
}
function cap(ample, alt, titol){
var resp = '<svg width="' + ample + '" height="' + alt;
resp = resp + '" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg"';
resp = resp + ' xmlns:xlink="http://www.w3.org/1999/xlink">' + '\n';
resp = resp + '<g>' + '\n' + '<title>' + titol + '</title>';
return resp;
}
function peu(){
var resp = '</g>' + '\n' + '</svg>';
return resp;
}
function arrod(valor, numxifsig){
// Arrodoneix, per excés, a dues xifres significatives
var val = valor;
var iter = 0;
if(val!=0){
if(val > 10**numxifsig){
while(val > 10**numxifsig){
iter++;
val = val/10;
}
val = Math.ceil(val);
val = val * 10**iter;
} else {
while(val < 10**(numxifsig-1)){
iter++;
val = val*10;
}
val = Math.ceil(val);
val = val / 10**iter;
}
}
return val;
}
function sendText(chatId,text_env,keyBoard){ // Funció que envia un text o un teclat a Telegram
keyBoard = keyBoard || 0;
if(keyBoard.inline_keyboard || keyBoard.keyboard){
var data = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(chatId),
text: text_env,
parse_mode: "HTML",
reply_markup: JSON.stringify(keyBoard)
}
}
} else {
var data = {
method: "post",
payload: {
method: "sendMessage",
chat_id: String(chatId),
text: text_env,
parse_mode: "HTML"
}
}
}
UrlFetchApp.fetch( telegramUrl + '/', data);
}
function sendBlobFile(chatId,blob_data,caption){
var payload = {
method: "sendPhoto",
chat_id: String(chatId),
photo: blob_data,
caption: caption,
parse_mode: "HTML"
};
var options = {
method: "POST",
payload: payload,
muteHttpExceptions: true
};
UrlFetchApp.fetch( telegramUrl + '/', options);
}
Fixem-nos que hem creat la funció arrod que ens arrodoneix un valor a dues xifres significatives. Això ens permetrà que si el valor màxim és, per exemple, 143 l'eix vagi de 0 a 150.
Ens pot interessar que ens dibuixi també una quadrícula, com a la imatge següent.

Per aconseguir-ho, caldria canviar la funció grafic per la següent:
function grafic(){
var resp = "";
var sh = SpreadsheetApp.openById(ssId).getSheetByName("linia"); // Agafem el full
var dades = sh.getDataRange().getValues(); // Llegim els valors
// Guardem els valors en un vector i ens quedem amb el màxim
var valors = new Array();
var maxY = 0; // El màxim, de moment, és zero
for (var i in dades){ // Mirem totes les dades
if (i > 0){ // Ignorem la filera dels títols
var row = dades[i]; // Agafem una filera
valors.push(row[0]); // Guardem els valors
if (row[0] > maxY){ // Busquem el màxim
maxY = row[0]; // Guardem el valor més alt
}
}
}
var numVal = valors.length; // Nombre de valors
// Decidim quantes marques tindrà cada eix i amb quines separacions
maxY = arrod(maxY, 2);
var divY = maxY / 10; // Arrodoneix, per excés, a dues xifres
// Creem la capçalera
var grafic = cap(640, 480, "Capa 1")+ '\n';
// Fem els eixos
var zeroX = 50;
var zeroY = 435;
var fiX = 620;
var fiY = 25;
grafic = grafic + linia(zeroX-5, zeroY, fiX, zeroY, 3, negre, "eixX") + '\n';
grafic = grafic + linia(zeroX, fiY, zeroX, 440, 3, negre, "eixY") + '\n';
// Posem les divisions de l'eix Y
for (var i = 0; i <= 10; i++){ // Sempre són 10 divisions
var ym = zeroY - ((zeroY - fiY) / 10) * i;
var valor = divY * i;
var noml = 'm' + i;
var nomt = 'tm' + i;
var nomq = 'q' + i;
grafic = grafic + linia(zeroX-5, ym, zeroX, ym, 2, negre, noml) + '\n';
grafic = grafic + text(zeroX-10, ym+5, valor, 16, negre, "d", 0, 0, nomt) + '\n';
if(i > 0){
grafic = grafic + linia(zeroX+1, ym, fiX, ym, 1, gris, nomq) + '\n';
}
}
// Posem les divisions de l'eix X
var xm;
var val;
for(var i = 0; i < 5; i++){
val = Math.ceil(i * numVal / 4);
if (i == 0){
val = 1;
}
xm = zeroX + ((fiX - zeroX) / (numVal - 1)) * (val - 1);
var nomlh = 'mx' + i;
var nomth = 'tx' + i;
var nomqh = 'qx' + i;
grafic = grafic + linia(xm, zeroY+5, xm, zeroY, 2, negre, nomlh) + '\n';
grafic = grafic + text(xm, zeroY + 25, val, 16, negre, "c", 0, 0, nomth) + '\n';
if(i > 0){
grafic = grafic + linia(xm, zeroY-1, xm, fiY, 1, gris, nomqh) + '\n';
}
}
// Dibuixem la línia del gràfic
for (var i = 1; i < numVal; i++){
var nomlg = 'L' + i;
var xp = zeroX + ((fiX - zeroX) / (numVal - 1)) * (i - 1);
var xm = zeroX + ((fiX - zeroX) / (numVal - 1)) * i;
var yp = zeroY - ((zeroY - fiY) / maxY) * valors[i-1];
var ym = zeroY - ((zeroY - fiY) / maxY) * valors[i];
grafic = grafic + linia(xp, yp, xm, ym, 4, blau, nomlg) + '\n';
}
// Posem el final del fitxer svg
grafic = grafic + peu();
return grafic;
}

Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.