| 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 tipus pastís amb els valors del full de càlcul. En aquest cas hem suposat que hi ha entre dos i dotze valors (hem definit dotze possibles colors) i que aquests són valors enters positius.
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 farem servir al gràfic
var negre = "#000000";
var blau = "#0000FF";
var transparent = "none";
var colors = ["#FF0000","#008800","#0000FF","#666600",
"#FF00FF","#006666","#CC6600","#8000FF",
"#888888","#884400","#00FFFF","#444444"]
function doGet(e){
var resp = grafic(); // Crea 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
// Adreça per veure el fitxer
var urlFitxer = "https://drive.google.com/uc?export=view&id=" + idFitxer;
// 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>Dades de l'any passat</h1>" + "\n";
pagina = pagina + resp + "\n";
pagina = pagina + "</body>" + "\n";
pagina = pagina + "</html>" + "\n";
return HtmlService.createHtmlOutput(pagina);
}
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."; // Text que s'envia
sendText(id,resposta); // Mentre es prepara el gràfic, ja que triga un temps
var resp = grafic(); // Crea el gràfic
var nomFitxer = "grafic"; // Nom del fitxer
// Crea el fitxer
var fitxerNou = DriveApp.getFolderById(IdCarpeta).createFile(nomFitxer + ".svg",resp);
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(); // Crea el gràfic com a dades binàries
var b64 = blob.getContentType() + ';base64,'+ Utilities.base64Encode(blob.getBytes());
// Crea una pàgina web senzilla que conté el gràfic
var htmlEst = '<style type="text/css" media="print">@page {size: landscape;} </style>';
var htmlInst = htmlEst + '<img src="data:' + b64 + '" width=900 alt="Histograma">';
var html = HtmlService.createHtmlOutput(htmlInst);
// Crea el PDF a partir de la pàgina web
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 PDF
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); // Envia la imatge
realitzat = true;
}
if (!realitzat){
var resposta = "Comanda desconeguda";
sendText(id,resposta);
}
}
function grafic(){
var resp = "";
var sh = SpreadsheetApp.openById(ssId).getSheetByName("circ"); // Agafem el full
var dades = sh.getDataRange().getValues(); // Agafa els valors
// Vectors per guardar les dades
var etiquetes = new Array();
var valors = new Array();
var suma = 0;
for (var i in dades){ // Mira totes les dades
if(i > 0){ // Ignorem la filera dels títols
var row = dades[i]; // Agafa una filera
etiquetes.push(row[0]); // Guardem les etiquetes
valors.push(row[1]); // Guardem els valors
suma = suma + row[1]; // Suma els valors, per tenir el total
}
}
var grafic = cap(640, 480, "Capa 1")+ '\n'; // Inici del gràfic
var ang = 0; // Angle inicial
for (var i = 0; i < valors.length; i++){ // Per a tots els valors
// Crea el sector
var ident = "arc" + i;
var angle = ang + 360 * valors[i] / suma; // Angle final
grafic = grafic + sector(210, 240, 150, ang, angle, colors[i], 2, transparent, ident) + '\n';
ang = angle; // Nou angle inicial
// Posa la llegenda
var ytxt = 460 - (valors.length - i) * 25;
var ident = "circ" + i;
grafic = grafic + cercle(450, ytxt, 10, 0, colors[i], transparent, ident) + '\n';
var ident = "txt" + i;
var perc = 100 * valors[i] / suma;
var lleg = etiquetes[i] + " " + valors[i] + " (" + perc.toFixed(2) + " %)";
lleg = lleg.replace(".",",");
grafic = grafic + text(470, ytxt+6, lleg, 16, negre, "e", 0, 0, ident) + '\n';
}
// Posem el final del fitxer svg
grafic = grafic + peu();
return grafic;
}
function sector(xc, yc, r, ai, af, color, gruix, vora, ident){
var xi = xc + (r * Math.cos(ai * Math.PI / 180.0));
var yi = yc + (r * Math.sin(ai * Math.PI / 180.0));
var xf = xc + (r * Math.cos(af * Math.PI / 180.0));
var yf = yc + (r * Math.sin(af * Math.PI / 180.0));
var laf = 0;
var sf = 1;
if ((af - ai) > 180){
laf = 1;
}
var resp = '<path id="' + ident + '" d=" M' + xi + ',' + yi + ' A' + r;
resp = resp + ',' + r + ' ' + 0 + ' ' + laf + ' ' + sf + ' ' + xf + ',';
resp = resp + yf + ' L' + xc +',' + yc + ' Z';
resp = resp + '" fill="' + color + '" stroke="' + vora;
resp = resp + '" stroke-width="' + gruix + '" />';
return resp;
}
function cercle(xc, yc, r, gruix, color, vora, ident){
var resp = '<circle id="' + ident + '" cx="' + xc + '" cy="' + yc + '" r="' + r;
resp = resp + '" stroke-width="' + gruix + '" stroke="' + vora + '" fill="' + color + '"/>';
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" 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 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);
}

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