| 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 columnes (barres verticals) amb els valors del full de càlcul. Amb la idea de fer un exemple senzill, hem suposat que el nostre full de càlcul sempre té les dades corresponents a set dies i que en la primera columna hi ha el nom del dia i a la segona el valor que li correspon; aquest valor sempre estarà entre 0 i 100 per fer el programa més fàcil. En un proper exemple treballarem amb un nombre variable de dades que tenen menys restriccions en el rang de valors.
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, creada a partir de la miniatura del PDF, 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 sortiran al gràfic
var negre = "#000000";
var blau = "#0000FF";
var transparent = "null";
function doGet(e){
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(); // Adreça per baixar el fitxer
var urlFitxer = "https://drive.google.com/uc?export=view&id=" + idFitxer; // URL per veure el fitxer
// Generem el codi HTML de la pàgina
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); // Envia 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."; // Enviem un text
sendText(id,resposta); // mentre es prepara el gràfic, ja que el procés és lent
var resp = grafic(); // Crea 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="Histograma">';
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 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); // Enviem la imatge
realitzat = true;
}
if (!realitzat){
var resposta = "Comanda desconeguda";
sendText(id,resposta);
}
}
function grafic(){
var sh = SpreadsheetApp.openById(ssId).getSheetByName("dades"); // Agafem el full
var dades = sh.getDataRange().getValues(); // Agafem les dades
var noms = new Array(); // Vector per guardar els noms de les barres
var valors = new Array(); // Vector per guardar els valors de les barres
for (var i in dades){ // Recorrem totes les dades
if (i > 0){ // Ignorem la filera de títols
var row = dades[i]; // Agafem una filera
noms.push(row[0]); // Nom de la barra
valors.push(row[1]); // Valor de la barra
}
}
// Creem la capçalera
var grafic = cap(640, 480, "Capa 1")+ '\n';
// Fem els eixos
var zeroX = 50;
var zeroY = 435;
grafic = grafic + linia(zeroX-5, zeroY, 620, zeroY, 3, negre, "eixX") + '\n';
grafic = grafic + linia(zeroX, 25, zeroX, 440, 3, negre, "eixY") + '\n';
// Posem les divisions de l'eix Y
for (var i = 0; i <= 10; i++){
var ym = zeroY - 40 * i;
var valor = 10 * i;
var noml = 'm' + valor;
var nomt = 'tm' + valor;
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 els títols de l'eix X i les barres
for (var i = 0; i < 7; i++){
var xb = 95 + 80 * i;
var alt = 4 * valors[i];
var yb = zeroY - alt;
var nomb = 'b' + i;
var nomc = 'tc' + i;
var nomv = 'tv' + i;
grafic = grafic + rect(xb-25, yb, 50, alt, 0, blau, transparent, nomb) + '\n';
grafic = grafic + text(xb, 450, noms[i], 16, negre, "c", 0, 0, nomc) + '\n';
grafic = grafic + text(xb, yb-5, valors[i], 16, blau, "c", 1, 0, nomv) + '\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 rect(x, y, ample, alt, gruix, color, vora, ident){
var resp = '<rect id="' + ident + '" x="' + x + '" y="' + y + '" width="' + ample + '" height="' + alt;
resp = resp + '" stroke-width="' + gruix + '" stroke="' + vora + '" fill="' + color;
resp = resp + '" stroke-linecap="null" stroke-linejoin="null" stroke-dasharray="null"/>';
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.