1
votes

I am developing a google add-on using CardService. Is there any way to insert google Charts[1] inside google Card[2]? I couldn't be able to find any documentation for that.

Also thinking a way to covert chart to image and insert, is that possible?

[1] - https://developers.google.com/apps-script/reference/charts

[2] - https://developers.google.com/apps-script/reference/card-service

1
Hm, nice question, I researched it before - no way to do that directly, but inserting an image as an Image widget with a data URL (data:image/png;base64) is likely the way to go. The only downside is that we have no control over the image size, so you should craft the chart accordingly - Oleg Valter
Also, please be mindful with getAs() method if you wish to add a table chart. I haven't used charts in a while and decided to test on a TableChart which apparently has a bug (still not fixed) resulting in server error: stackoverflow.com/questions/57385584/… - Oleg Valter

1 Answers

2
votes

You'd have to convert the chart to an image, and add that image to your Card.

setImageUrl(url) accepts a publicly accessible URL and a base64 encoded image string.

The workflow would depend on whether the Chart will be built by the add-on or not.

  • In case the Chart is built by the add-on, you just have to retrieve the base 64 string:
function getChartImageUrl() {
  var chart = Charts.
              // Building chart methods
              .build();
  var imageData = Utilities.base64Encode(chart.getAs('image/png').getBytes());
  var imageUrl = "data:image/png;base64," + encodeURI(imageData);  
  return imageUrl;
}

And then add this to your Card:

function createChartCard() {
  var image = CardService.newImage().setAltText("An awesome chart").setImageUrl(getChartImageUrl());
  var section = CardService.newCardSection()
      .addWidget(image)
  var card = CardService.newCardBuilder()
      .addSection(section)
  return card.build();
}
  • In case the Chart is not built by the add-on, I'd suggest to store the image in Drive, make it publicly accessible and retrieve its ID:
function getChartImageId() {
  var chart = Charts.
              // Building chart methods
              .build();
  var imageBlob = chart.getAs('image/png');
  var file = DriveApp.createFile(imageBlob).setName("MY AWESOME CHART");
  file.setSharing(DriveApp.Access.ANYONE, DriveApp.Permission.VIEW);
  return file.getId();
}

And then, in the add-on, retrieve the File by its ID and get its base64 encoded string:

function createChartCard() {
  var imageId = "YOUR_IMAGE_ID"; // Returned by getChartImageId()
  var imageBytes = DriveApp.getFileById(imageID).getBlob().getBytes();
  var encodedImageURL = "data:image/jpeg;base64," + Utilities.base64Encode(imageBytes);
  var image = CardService.newImage().setAltText("An awesome chart").setImageUrl(encodedImageURL);
  var section = CardService.newCardSection()
      .addWidget(image)
  var card = CardService.newCardBuilder()
      .addSection(section)
  return card.build();
}

In this second method, you would have to add the scope https://www.googleapis.com/auth/drive.readonly to your manifest (see Setting explicit scopes).