Align multiple images beside in Google Doc - google-apps-script

after several hours of searching and try & error, I have to give up.
I got a google doc wich I fill up with some data from a google sheet.
Also I create some pie charts with the data and would like to align 2 (or even more) little charts (>200x200 px) inline beside eachother.
But I am not able to do it. :(
One single image, or chart isn´t any problem, but 2 or more seems to be pretty hard.
Thats why I picked up this option and Your experience as my last option.
Thank you very much for every hint and have a nice Day.
Michael
"Short" Code Sample:
Step 1: Open Google Sheet
var reportDataStorage = SpreadsheetApp.openByUrl('https://docs.google.com/.../edit');
var sheet = reportDataStorage.getSheetByName(...);
Step 2: Create Table
var daten_besucher_nach_quelle = Charts.newDataTable()
...
daten_besucher_nach_quelle.addRow([sheet.getRange('O'+y).getValue(), sheet.getRange('P'+y).getValue(), sheet.getRange('Q'+y).getValue(); sheet.getRange('R'+y).getValue()]);
...
daten_besucher_nach_quelle.build();
Step 3: Create Chart from Table
var chart_besucher_nach_quelle = Charts.newPieChart()
.setDataTable(daten_besucher_nach_quelle)
.setDimensions(300, 300)
...
.build();
Step 4: Append Image
body.appendImage(chart_besucher_nach_quelle.getAs('image/png'));
Is this enough?

As you noticed, when you insert an image in a document, a new paragraph is automatically added to the document's body.
This paragraph container is accessible using image.getParent() method. As soon as we get this paragraph we can add another image in it, this image will be directly aligned side by side (as long as the total width is less than the maximum size between margins).
Try this small simple code and see the result in the scren capture below :
function importImageTest(){
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var image1 = DriveApp.getFileById("0B3qSFd3iikE3TUFFLWY0ZWJjNzM2LWFiNDYtNGU1OC1hMGNhLTViM2UxNTBlMTE3Nw");// some image in my drive
var image2 = DriveApp.getFileById("0B3qSFd3iikE3TUFFLWI3Y2JiOTU1LWM0OGYtNDVkMS05ZTRiLTkzNjQ5NDBlZGFkNA");
var firstImage = body.appendImage(image1).setWidth(150).setHeight(100);// an arbitrary size
var currentParagraph = firstImage.getParent();// the container of first image
currentParagraph.asParagraph().appendInlineImage(image2).setWidth(150).setHeight(100);// add the second image to this parent paragraph
doc.saveAndClose();
}

Related

Display image in HTML page served by Apps Script

Good afternoon all;
I have a google spreadsheet which is populated by a Qualtrics form, where the user can upload a photo.
Using Apps Script, I have created a CRUD database that is accessed via a google sites page (html form). All is working great, but I'd like to display the photo that the user uploaded in their record; the URL to the image is saved in a column on the spreadhsheet.
The thing is, I'm not a very worthy 'coder' and I can't figure out how to make this happen.
I'm accessing my data like this: Note that I have removed a good portion of the code to save space.
Code.gs
function getFormValues(formObject) {
if (formObject.responseID && checkID(formObject.responseID)) {
var values = [[formObject.responseID.toString(),
formObject.permitNumber,
formObject.dateOfIssue,
formObject.photoLink, <<<this is where the URL would be pulled in. Column Q in the spreadsheet.`
DataTable.html
function populateForm(records){
document.getElementById('responseID').value = records[0][0];
document.getElementById('permitNumber').value = records[0][1];
document.getElementById('photoLink').value = records[0][16];
...I just don't know what to do after this point...
I did some tests, and I have an option for you to use Google Apps Script and the formula IMAGE.
Since I didn't have much information on your setup, like where the files are uploaded, which is the format of the URL, etc. I made a test environment using Google Forms, the files uploaded to Google Drive, and Apps Script.
With the formula:
=IMAGE("URL", [mode], [height], [width])
For the test, I use mode 4, which allows you to specify the size of the image. You can use either of the modes:
1 resizes the image to fit inside the cell, maintaining the aspect ratio.
2 stretches or compresses the image to fit inside the cell, ignoring the aspect ratio.
3 leaves the image at its original size, which may cause cropping.
4 allows the specification of a custom size.
The height and width needs to be in pixels.
When you use a Google Form to upload an image, you get an URL with the following format:
https://drive.google.com/open?id=[ID_OF_THE_FILE]
There is a trick to display images from Google Drive into Google Sheets using the image formula. You need the URL with the format: (I got this idea from this post)
https://lh3.googleusercontent.com/d/[ID_OF_THE_FILE]
So the script that I created modifies the URL in the column of the image from:
https://drive.google.com/open?id=[ID_OF_THE_FILE]
To:
=IMAGE("https://lh3.googleusercontent.com/d/[ID_OF_THE_FILE]", 4, 60, 60)
And place it in the cell in the column. However, you can place it in the same column as the current URL too.
Here is the sample code:
function testImage() {
// Identifies the sheet link to the Google Sheet and the tab you will be working with
// you can also use const sheet = SpreadsheetApp.getActiveSpreadsheet()
// .getSheetId("[ID_OF_THE_SHEET]");
// if the Script is not bound to the sheet.
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Form Responses 1");
// Gets the range and the values where the URLs of the images are located.
// in my example there are in column B
let range_1 = sheet.getRange("B2:B").getValues().flat();
// Filters the rows without values or empty
range_1 = range_1.filter((element) => {return (element !== '')});
// Start of the loop to run on each row with URLs
for (let i=0; i< range_1.length ; i++){
let row = range_1[i];
// For this sample, I replace the URL with the word "Done" to prevent duplicates later on in the Script
// This can be skipped or replaced place, in a different location.
if (row != "Done"){
// Replace the URL from https://drive.google.com/open?id=[ID_OF_THE_FILE]
// to =IMAGE("https://lh3.googleusercontent.com/d/[ID_OF_THE_FILE]
let temp_imageURL = row.toString().replace('https://drive.google.com/open?id=',
'=IMAGE("https://lh3.googleusercontent.com/d/');
// However, the process is not complete yet, we need to complete the formula
// so we added the last part ",4,60,60) to the URL
// making it "https://lh3.googleusercontent.com/d/[ID_OF_THE_FILE]",4,60,60)
let imageURL = temp_imageURL+'",4,60,60)';
// place the complete formula in the current iteration, row 3 (which is row C)
sheet.getRange(i+2,3).setValue(imageURL);
// replace the current URL in Row 2 (which is row B) with the word "Done"
sheet.getRange(i+2,2).setValue("Done");
}
}
}
It looks like:
Reference:
IMAGE
Replace

How to copy and paste specific information in a same doc using Google App Script?

I'm very new using GAS what I'm trying to do is to copy some information that is already on the bottom of my doc to anywhere I want in my docs, this should work just by copying the information and paste it at the place I desire, but I want it to be done with Google App Script because it's a daily task and it's easier to do it with a function, instead of copying and pasting manually. Searching on how to do this, I found a lot of information about how to do it on Spreadsheets, but I needed it to be done on Google Docs. How can I do that?
If someone can guide me or send me a link to another similar question that would be very helpful, I don't know where to start.
This is what I have until now, I get all the data of the current doc and set it again to the page, the code gives me problems because it deletes my other information, also it selects all the doc's information. I want to select a piece of specific information and don't copy the content style.
function copyPasteInfo() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var notesText = body.getText();
body.appendPageBreak();
body.setText(notesText);
}
Link to the doc document
https://docs.google.com/document/d/1s2TCspXbjvHVurwhIWSdwJ_hMcZIoLTKj4FAB82nmhM/edit
Video example of how what i want to do
https://www.screencast.com/t/UmEon8Fm0lPe
Picture of the information i'm trying to copy and paste to the bottom of my doc
If I correctly understood your question, this code will help you to achieve your goal.
let body = DocumentApp.getActiveDocument().getBody();
function moveTable() {
// Get the last table and the previous table found in your Doc
const [previousTable, bottomTable] = getDesireTables();
// Make a copy of your last table
const bottomTableCopy = bottomTable.copy();
// Get the previous table's index
const previousTableIndex = body.getChildIndex(previousTable);
// Insert the last table's copy under the previous table in your Doc
body.insertTable(previousTableIndex + 1, bottomTableCopy);
// Remove the original last table
body.removeChild(bottomTable);
}
function getDesireTables(){
const tablesArr = body.getTables().slice(-3);
// Get the parent element type to check if it's a cell
const parentELementType = tablesArr[tablesArr.length - 1].getParent().getType();
if(parentELementType === DocumentApp.ElementType.TABLE_CELL){
// If there's a table inside a table, return this
return tablesArr.slice(0, 2);
}
else{
return tablesArr.slice(-2);
}
}
What I did was to get the last two tables in the Doc, then I made a copy of the last one and with the index of the previous one, I inserted it under the previous one.
Edit
I noticed you had a table inside a table. therefore I added the getDesireTables function. Which it will check if your bottom table has a table inside.
Docs
These are the docs I used to help you:
getTables().
copy().
insertTable(childIndex, table).

Is there a way to automatically have text move into certain sections in Google Docs depending on what color I highlight it?

So let's see if I can explain this correctly.
I use a Google Doc to track my to-do list at work. When I add something that needs immediate attention, I will highlight that bullet point and the description of the task with a bright yellow color. Lesser tasks, get a different color, etc. I break up my tasks into different lists under different headings depending on what type of project it's for (so I have a heading for "Website" then a bulleted list under it for all the tasks I need to do that pertain to updating the website, I have a "Videos" heading and a list beneath with all the tasks I need to do for videos, and so on). Within each section, I then highlight based on priority.
My list is long with many sections and I would love it if it were possible that when I highlight a task in a given section as "top priority" with the bright yellow color, that it would - automatically - be copied and moved to a section at the very top of my doc under a heading of "Priorities" that way I can see all in one place all the high priority tasks I want to accomplish across all my projects without having to scan through each section in my document and potentially missing something.
Is this possible to do? I've heard of Google Apps Script but I've never really dived into it. I have basic coding knowledge and can usually find my way around HTML, Javascript, and so on.
Is something like this possible? And how would I go about it?
Brenda.
You'll probably start with this:
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
var lists = body.getListItems();
var childIndex = 0;
for (var i = 0; i < doc.getNumChildren(); i++) {
var child = doc.getChild(i);
if (child.getType() == DocumentApp.ElementType.LIST_ITEM){
while(child.getType() == DocumentApp.ElementType.LIST_ITEM){
child = doc.getChild(i)
childIndex = body.getChildIndex(child);
Logger.log(childIndex)
i++
}
child = doc.getChild(i-2)
var listId = child.getListId();
Logger.log(childIndex)
// You'll want to do something like...
// if child.getBackgroundColor() == "Yellow"...
// Here you can add an element to your "Priorities" list as well:
// var newElement = child.getParent().insertListItem(childIndex, elementContent);
// newElement.setListId(child);
break;
}
}
Here's a good reference: https://stackoverflow.com/a/20729760/5415398
And another: https://stackoverflow.com/a/26419644/5415398
Here you are getting the document, its body, and any lists contained therein. You can either use the "lists" variable directly, or you can instead loop through all of the document's children and for any that are LIST_ITEMs, they can be processed as needed.
You'll try to capture the highlighting of the list item with the ".getBackgroundColor()" function, and if it meets your conditions, then add the item to your priorities list.
(Note: This answer can and should be improved to be complete.)

Google Script different aligment in same table row in Docs table

I'm trying to put three paragraphs (loaded from google spreadsheet) into docs via google app script.
One should be on its own row and the other two should be on same row but with different alignment.
Pic. 1 - What I want
The problem is, google allow only appending paragraphs into table cells. And paragraph contains new line so the second text is on the new line.
Pic. 2 - What I get
I've tried appending paragraph and then appending text.
But I don't know how to set up right-aligned tab and insert tab after first text.
Is it even possible to set up tabs using google script only ?
I welcome any help or suggestion how can I create text as showed in Pic. 1. Than you for any help.
There is actually an issue (3211) that prevents doing exactly what you want : the merge() method is causing the doc crash.
so the code below will result in something like this :
because we cannot merge the 2 cells in the first row from the script.
Doing it manually works well :
code :
function myFunction() {
var doc = DocumentApp.getActiveDocument();
var body = doc.getBody();
body.clear();
var table = body.appendTable([['',''],['','']]);
table.setBorderColor('#ffffff');
table.getCell(0,0).appendParagraph('Some important text important text important text important text ');
//table.getCell(0,1).merge();// this is the issue...it crashes the doc
table.getCell(1,0).appendParagraph('left text').setAlignment(DocumentApp.HorizontalAlignment.LEFT);
table.getCell(1,1).appendParagraph('right text').setAlignment(DocumentApp.HorizontalAlignment.RIGHT);
doc.saveAndClose()
}

Add button on the fly

I read the tutorial regarding creating buttons, it was pretty simple & straightforward.
However, I want to create buttons on the fly. I have a status column. It has a drop down menu created from a range of cells on a hidden sheet. This is working code.
Here's the wish list. When “status X” is selected, I want the button to appear. The user can then push the button to increment a counter (which is displayed). Track needs to be kept of the date & time (also displayed – including the history) when the button is pressed. The previous button press date & time is always displayed.
Once the counter reaches some number – say 10, a warning message pops up which the user must acknowledge, and then the status automagically changes, button disappears and the entire row (with a color change) is moved to another page (or possibly another spreadsheet entirely).
Currently I have a function that simply changes the row color when the status changes, and also moves the row to another page. I imagine the button would get created around that point somehow. Other than what the tutorial says which I don't think really applies, I don't really know how to move forward. Any help?
Please note for the record I find using the “active page” a bad idea in my case, as I have several pages where this might execute from. So, I use “sourceSheet” and “targetSheet” for everything.
Thank you
//happyFunTime is installed as an edit trigger.
function happyFunTime() {
var s = SpreadsheetApp.getActiveSheet();
var r = s.getActiveCell();
// set row color as soon as we know the status
var i = r.getRow();
var targetSheetName=setRowColor(i);
// moveRow(targetSheetName);
}
function setRowColor(i)
{
var sName;
var outCome = [];
var color;
var range = SpreadsheetApp.getActiveSheet().getDataRange();
var statusColumnOffset = getStatusColumnOffset();
var rowRange = range.offset(i-1, 0, 1);
var status = rowRange.offset(0, statusColumnOffset).getValue();
outCome=checkStatus(status);
sName=outCome[0];
color=outCome[1];
rowRange.setBackgroundColor(color);
return sName;
}
Have you tried writing any code to achieve this programmatically? If you do, post it here, as its easier to gain a better understanding of your working code, and to build on it. Or do you just want someone to write te code for you?
All you have described is certainly possible to achieve programmatically, I suggest researching the onEdit trigger, as a means to an end.