Google Apps Script to set shape color - google-apps-script

I was looking through the Google Apps Script reference here and noticed there is a method for setSolidFill(color).
I was wondering if it was possible to write a Google Apps Script to set shape colors based on values/ lookup reference in a Google Sheet? Essentially set the colour of Shape #001 in Google Slides to the HEX code in A2 of a Google Sheet?

I am wondering if it is possible to set shape colours based on colour codes found in a Google Sheet.
I think that your goal can be achieved. So in order to help to understand about the method for achieving your goal, I proposed the following 2 patterns.
Pattern 1:
In this pattern, the color of shape is changed using the object ID of the shape in 1st slide on Google Slides. In this sample, the hex color is retrieved from the cell "A1" of the Spreadsheet. Please set the Spreadsheet ID, sheet name and the presentation ID.
Sample script:
function myFunction() {
const objectId = "###"; // Please set the object ID.
const hexColor = SpreadsheetApp.openById("spreadsheetId").getSheetByName("sheetName").getRange("A1").getValue();
const slide = SlidesApp.openById("presentationId").getSlides()[0];
var obj = slide.getShapes().filter(s => s.getObjectId() == objectId);
if (obj.length > 0) obj[0].getFill().setSolidFill(hexColor);
}
Pattern 2:
In this pattern, the color of shape is changed using the shape type of the shape in 1st slide on Google Slides. In this sample, the hex color is retrieved from the cell "A1" of the Spreadsheet, and the color of "RECTANGLE" shapes are changed. Please set the Spreadsheet ID, sheet name and the presentation ID. Please select the shape type from Enum ShapeType.
Sample script:
function myFunction() {
const shapeType = "RECTANGLE"; // Please set the shape type.
const hexColor = SpreadsheetApp.openById("spreadsheetId").getSheetByName("sheetName").getRange("A1").getValue();
const slide = SlidesApp.openById("presentationId").getSlides()[0];
var objs = slide.getShapes().filter(s => s.getShapeType() == SlidesApp.ShapeType[shapeType]);
if (objs.length > 0) {
objs.forEach(obj => obj.getFill().setSolidFill(hexColor));
}
}
Note:
These are the simple sample scripts. So when you use the script, please modify it for your actual situation.
References:
setSolidFill(hexString)
getObjectId()
getShapeType()
Enum ShapeType
Added 1:
When you want to retrieve the object IDs of all shaped in a slide, you can use the following script.
Sample script:
const slide = SlidesApp.openById(presentationId).getSlides()[0];
const objectIds = slide.getShapes().map(s => s.getObjectId());
console.log(objectIds)
In this case, the object IDs of all shapes in 1st slide are put in an array.
Added 2:
For example, when the colors of all shapes in the 1st slide in Google Slides are changed to the red color, the following script can be used. When you want to select one of shapes using the object ID, at first, please retrieve the object IDs using the script of "Added 1", and use the script of "Pattern 1".
Sample script:
function myFunction() {
const hexColor = "#ff0000"; // This is a red color.
const slide = SlidesApp.openById(presentationId).getSlides()[0];
const shapes = slide.getShapes();
if (shapes.length > 0) {
shapes.forEach(obj => obj.getFill().setSolidFill(hexColor));
}
}
Added 3:
About can the pattern 1 script use an array (I need to change colours of several shapes, not just one), from your additional request of can you please show me how to adjust the pattern 1 script to work with an array?, I added one more sample script as follows.
In this sample, at first, please set the object IDs and hex colors in objectIds. By this, the colors of shapes of 1st slide can be changed.
Sample script:
function myFunction() {
const objectIds = [
{objectId: "###", hexColor: "###"},
{objectId: "###", hexColor: "###"},
,
,
,
];
const slide = SlidesApp.openById("presentationId").getSlides()[0];
const shapeObjects = slide.getShapes().reduce((o, s) => Object.assign(o, {[s.getObjectId()]: s}), {});
objectIds.forEach(({objectId, hexColor}) => {
if (shapeObjects[objectId]) shapeObjects[objectId].getFill().setSolidFill(hexColor);
});
}
Note:
This is a simple sample script. So please modify it for your actual situation.

Related

How to output a hyperlink from Apps Script function into Google Sheet

My first attempt was raw html, but that clearly didn't work.
I found that I'm supposed to use rich text, so I tried:
function youtubeLink(yt_id, start_stamp, end_stamp) {
const start_secs = toSecs(start_stamp)
const end_secs = toSecs(end_stamp)
const href = `https://www.youtube.com/embed/${yt_id}?start=${start_secs}&end=${end_secs}`
return (
SpreadsheetApp.newRichTextValue()
.setText("Youtube Link")
.setLinkUrl(href)
.build()
)
}
I'm calling with:
=youtubeLink(A1,A2,A3)
But that didn't work at all. The field just stayed blank.
I tried with a range, but got a circular reference. It seems like this should be easy. Not sure what I'm missing.
This works, but it is auto-formated and the link text is the same as the link:
function youtubeLink(yt_id, start_stamp, end_stamp) {
const start_secs = toSecs(start_stamp)
const end_secs = toSecs(end_stamp)
return (`https://www.youtube.com/embed/${yt_id}?start=${start_secs}&end=${end_secs}`)
}
Unfortunately, the custom function cannot directly put the RichtextValue and the built-in function to the cell. In this case, that is put as a string value. So, in this case, it is required to use a workaround. In this answer, I would like to propose the following 2 patterns.
Pattern 1:
If you want to use the functions of Spreadsheet, how about the following sample formula?
=HYPERLINK("https://www.youtube.com/embed/"&A1&"?start="&toSecs(B1)&"&end="&toSecs(C1),"Youtube Link")
In this case, the cells "A1", "B1" and "C1" are yt_id, start_stamp, end_stamp, respectively.
The function of toSecs is used from Google Apps Script.
Pattern 2:
If you want to use Google Apps Script, how about the following sample script? In this case, this script supposes that the values of yt_id, start_stamp, end_stamp are put in the cells "A1", "B1", and "C1", respectively. Please be careful about this.
function sample() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Sheet1"); // Please set the sheet name.
const [yt_id, start_stamp, end_stamp] = sheet.getRange("A1:C1").getValues()[0];
const start_secs = toSecs(start_stamp);
const end_secs = toSecs(end_stamp);
const href = `https://www.youtube.com/embed/${yt_id}?start=${start_secs}&end=${end_secs}`
const richtextValue = SpreadsheetApp.newRichTextValue().setText("Youtube Link").setLinkUrl(href).build();
sheet.getRange("D1").setRichTextValue(richtextValue);
}
When this script is run, the values of yt_id, start_stamp, end_stamp are retrieved from the cells "A1", "B1" and "C1", and the text with the hyperlink is put to the cell "D1".
Reference:
setRichTextValue(value)

Save a range of Google Sheet as image in Google Drive [duplicate]

I am trying to copy a range of cells of a specific Google spreadsheet as an image onto a Google slide. But I could barely find useful code. This is what I came up with, but I still cannot transfer the cell range into an image/png.
Goal: Insert the image stored just in a variable to a specific slide!
Any help is very much appreciated. Thank you.
function add_WSA(){
//Opening the Spreadsheet
var ss = SpreadsheetApp.openById("insertSpreadsheetID");
var range = ss.getRange("example!A1:F20");//in A1 Notation
//Conversion into an png image
var image = range.getAs('image/png');
//Opening the specific Slide (Nr. 3)
var slide = SlidesApp.openById("mySlidesID").getSlides()[2];
//Insertion of image
slide.insertImage(image);
}
Error: TypeError: range.getAs is not a function
at add_WSA(report:5:21)
PS: I am farely new to the community and to JavaScript. Please be patient. Every other help on a leaner or more efficient solution to the problem is very much appreciated. Thank you.
How about this answer?
Issue and workaround:
Unfortunately, in the current stage, the range object cannot be directly converted to the PNG format. So in this case, it is required to use a workaround. In this answer, as the workaround, I would like to propose to use Charts Service. When Charts Service is used, the range of Spreadsheet can be converted to an image blob.
Sample script:
function add_WSA(){
//Opening the Spreadsheet
var ss = SpreadsheetApp.openById("insertSpreadsheetID");
var range = ss.getRange("example!A1:F20");//in A1 Notation
//Conversion into an png image
// I modified below script.
const [header, ...values] = range.getDisplayValues();
const table = Charts.newDataTable();
header.forEach(e => table.addColumn(Charts.ColumnType.STRING, e));
values.forEach(e => table.addRow(e));
const image = Charts.newTableChart().setDataTable(table.build()).setDimensions(500, 500).setOption('alternatingRowStyle', false).build().getBlob();
//Opening the specific Slide (Nr. 3)
var slide = SlidesApp.openById("mySlidesID").getSlides()[2];
//Insertion of image
slide.insertImage(image);
}
Result:
When above script is run, the following sample result can be obtained.
Note:
Please use this script with enabling V8.
In this case, for example, when you want to change the font color, please use HTML code in each cell value.
Reference:
Charts Service

Is it possible to add formatting (shading) to rows being appended in Google Sheets (by Google Apps Script)

I've got a Google App Script which is copying rows from one sheet to another, performing various transformations. This logic ultimately gets rows onto the new sheet using sheet.appendRow(row detail). I would like these newly created rows to have a background colour (my intention is to hold a 'latestColour' so I can alternate the shading).
So, is there anyway to add shading within the appendRow method itself, or easily determine the range that the appendRow method processed, such that I can apply additional logic to add the shading.
You can use conditional formatting
=and(A1<>"",A2="")
Although I'm not sure whether I could correctly understand your situation, from your question, I thought that you might be using [Format] --> [Alternating colors] in Google Spreadsheet. And, when a new row is appended by putting the values, you might want to reflect "Alternating colors" in the appended row. If my guess is correct, how about the following sample script?
Sample script:
function myFunction() {
const addValues = ["sample1", "sample2", "sample3"]; // This is a sample appending value. Please replace this for your value.
const sheetName = "Sheet1"; // Please set the sheet name.
// Retrieve banding object from the data range.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName);
const b = sheet.getDataRange().getBandings();
if (b.length == 0) {
console.log("Bandings are not used.");
return;
}
// Append the value.
sheet.appendRow(addValues);
// Expand the range of banding.
b[0].setRange(sheet.getDataRange());
}
When this script is run, the current banding is retrieved. And, after the value was appended, the banding is updated by including the appended row. In this sample, even when the multiple rows are appended, this script can be used.
Note:
From your question, I guessed that there is one banding in the data range in your sheet. Please be careful this.
References:
getBandings()
setRange(range)
Unfortunately the method appendRow() does not receive formatting settings as input, only an array of values.
However, here is a suggestion if you want to implement your own logic:
Sample code:
function applyColorLastRow() {
var ss = SpreadsheetApp.getActive(); //get active sheets file
var range = ss.getDataRange(); //get populated range, you may want to set a range manually if needed.
var lastRowNum = range.getLastRow(); //getting the last row index of the range.
var lastRowRange = ss.getRange(`${lastRowNum}:${lastRowNum}`); //narrowing the range (using A1 notation) to the last row only to apply color
var lastRowColor = lastRowRange.getCell(1,1).getBackgroundObject().asRgbColor().asHexString();
//Your row coloring logic here...
if (lastRowColor === '#ffffff'){ //toggling white/grey color as an example...
lastRowRange.setBackground('#cccccc'); //apply grey color to all cells in the last row range
} else {
lastRowRange.setBackground('#ffffff'); //apply white color to all cells in the last row range
};
}

Google Slides Apps Script retrive a shape in a page

how to retrieve a particular shape base on the text of the shape.
example: I would like to retrieve a shape in which text starts with "Issue" and get the content of the text to input it in Google Sheets
thanks for helping!
I believe your goal as follows.
You want to retrieve the texts from the shapes in Google Slides.
When the top of text is Issue, you want to retrieve the text, and want to put the retrieved texts to Google Spreadsheet.
You want to achieve this using Google Apps Script.
In this case, how about the following sample script? Unfortunately, from your question, I cannot understand about the output situation you expect. So the following sample script puts the retrieved values to the 1st column.
Sample script:
Please copy and paste the following script to the script editor. And, please set the variables and run myFunction.
function myFunction() {
const presentationId = "###"; // Please set the presentation ID (Google Slides ID).
const spreadsheetId = "###"; // Please set the Spreadsheet ID.
const sheetName = "Sheet1"; // Please set the sheet name.
const searchText = "Issue";
// Check texts and retrieve texts from Google Slides.
const regex = new RegExp(`^${searchText}`);
const slides = SlidesApp.openById(presentationId).getSlides();
const values = slides.flatMap(slide => slide.getShapes().reduce((ar, shape) => {
const text = shape.getText().asString().trim();
if (regex.test(text)) ar.push([text]);
return ar;
}, []));
// Put the retrieved texts to Google Spreadsheet.
const sheet = SpreadsheetApp.openById(spreadsheetId).getSheetByName(sheetName);
sheet.getRange(1, 1, values.length, values[0].length).setValues(values);
}
Note:
Unfortunately, I'm not sure whether above sample script is what you need. So when above script is not useful for your situation, in order to correctly understand about your goal, can you provide the sample Slides and the sample result you expect? By this, I would like to modify the script.
References:
getShapes()
getText()
setValues(values)

Bug in getBackgrounds() using custom theme colors

I've got a spreadsheet with colors from a custom theme.
When I read the colors using getBackgrounds() the colors returned are all #000000
If I read the colors cell-by-cell using getBackground() the colors are returned correctly.
If I use standard colors (ie not colors in my Theme) the colors are also returned correctly.
TEST SHEET
(available to view at https://docs.google.com/spreadsheets/d/1nCZeUbCjs_5p6_52v8ggqVgrgnJ-Pd6x-gzXUFfV8G0/edit?usp=sharing
Cells A1:D1 contain the names of the four Beatles, all with background color #b70906
TEST CODE
/** #OnlyCurrentDoc */
function getbackgroundstwoways(){
var fullrange= SpreadsheetApp.getActiveSpreadsheet().getRange("A1:D1");
// Read all cells using getBackgrounds
var arBack = fullrange.getBackgrounds();
var arValues=fullrange.getValues()
Logger.log("Full array " +arBack + arValues);
//Now do the cells individually with getBackground
for (var i=0; i<fullrange.getLastRow();i++){
for (var j=0; j<fullrange.getLastColumn();j++){
Logger.log("Single cell " + i + " " + j + " " + fullrange.offset(i,j).getBackground() + " " + fullrange.offset(i,j).getValue() ) ;
}}}
LOGGER OUTPUT
Full array #000000,#000000,#000000,#000000John,Paul,George,Ringo
Single cell 0 0 #b70906 John
Single cell 0 1 #b70906 Paul
Single cell 0 2 #b70906 George
Single cell 0 3 #b70906 Ringo
How about this answer?
Issue and solution:
When I saw your shared Spreadsheet, the background colors of cells "A1:D1" has the color type of "THEME". I think that this is the reason of your issue.
In the current stage, it seems that getBackground() can directly retrieve the background color from the color type of "THEME" as the hex string. But, it seems that getBackgrounds() cannot directly retrieve them. The retrieved values using it becomes #000000. I'm not sure whether this is the bug or the current specification. But in the current stage, the background colors of the color type of "THEME" can be retrieved by the methods in Spreadsheet service.
One of several solution is to use getBackground() as your script. This has already been achieved in your script.
In this answer, as another pattern, the colors are retrieved from the values retrieved by getThemeColors. The flow of this script is as follows.
Create an object for searching the colors from the theme color type.
Retrieve background objects.
Retrieve the background colors from backgroundObjects.
Sample script:
function getbackgroundstwoways() {
const ss = SpreadsheetApp.getActiveSpreadsheet();
const fullrange = ss.getActiveSheet().getRange("A1:D1"); // Range from your script.
// 1. Create an object for searching the colors from the theme color type.
const theme = ss.getSpreadsheetTheme();
const themeColorObj = theme.getThemeColors().reduce((o, e) => Object.assign(o, {[e]: theme.getConcreteColor(SpreadsheetApp.ThemeColorType[e]).asRgbColor().asHexString()}), {});
// const fullrange = SpreadsheetApp.getActiveSpreadsheet().getDataRange();
// 2. Retrieve background objects.
const backgroundObjects = fullrange.getBackgroundObjects();
// 3. Retrieve the background colors from backgroundObjects.
const backgroundColors = backgroundObjects.map(r => {
return r.map(c => {
if (c.getColorType() == SpreadsheetApp.ColorType.RGB) {
return c.asRgbColor().asHexString();
} else if (c.getColorType() == SpreadsheetApp.ColorType.THEME) {
return themeColorObj[c.asThemeColor().getThemeColorType()];
} else {
return null;
}
});
});
console.log(backgroundColors);
}
This script can be used for the color types of both "RGB" and "THEME". When this script is run at your shared Spreadsheet, [ [ '#b70906', '#b70906', '#b70906', '#b70906' ] ] can be seen at the log.
Even when the RGB types and the THEME types are mixed, this script can retrieve the background colors as the hex string.
Note:
In this case, the background colors are retrieved from the theme colors. But when you overcoat the background colors as the RGB type of #b70906, you can retrieve them using getBackgrounds().
When I searched about this that getBackgrounds() cannot be used for the THEME color type at the issue tracker, I couldn't find this. So how about reporting this? Ref
Please use this script with V8.
References:
getSpreadsheetTheme()
This method is added at December 18, 2019.
Class SpreadsheetTheme
getBackgroundObjects()