This question already has answers here:
Google Apps Script: Insert Data Table into Google Slide
(2 answers)
Closed 12 months ago.
I'm creating a tablechart in Google Script and I want to send this through e-mail.
This is my code
var data = Charts.newDataTable()
.addColumn(Charts.ColumnType.STRING, 'Month')
.addColumn(Charts.ColumnType.NUMBER, 'In Store')
.addColumn(Charts.ColumnType.NUMBER, 'Online')
.addRow(['January', 10, 1])
.addRow(['February', 12, 1])
.addRow(['March', 20, 2])
.addRow(['April', 25, 3])
.addRow(['May', 30, 4])
.build();
var chart = Charts.newTableChart()
.setDataTable(data)
.enableSorting(true)
.build();
MailApp.sendEmail({
to: "me#gmail.com",
subject: "Test",
htmlBody: "inline Google Logo<img src='cid:inImage'> images! <br>",
inlineImages:
{
inImage: chart.getBlob().setContentType('image/png'),
}
});
The code gives the following error message on chart.getBlob().setContentType('image/png'):
"We're sorry, a server error occurred. Please wait a bit and try again".
Anyone any idea what's wrong?
Thanks!
How about this modification?
From:
var chart = Charts.newTableChart()
.setDataTable(data)
.enableSorting(true)
.build();
To:
var chart = Charts.newTableChart()
.setDataTable(data)
.enableSorting(true)
.setDimensions(640, 480) // Added
.build();
It sets the size of chart using setDimensions().
Note:
Also you can use chart.getAs('image/png') instead of chart.getBlob().setContentType('image/png').
Reference:
setDimensions(width, height)
If this was not what you want, please tell me. I would like to modify it.
Related
So I have multiple google forms (around 20 forms), that I need to do 2 things to them:
1- These 20 forms are placed in a folder in my google drive. I need to add more like an "Access code" where users will have to insert in order to continue the solving the quiz.
The way I did that was to add a "short answer" question to "section 1" of the quiz asking "Enter your Access Code", add "response validation", "Regular expression" and "Pattern". Also making this a "required question". This should look something like the below picture
Example of google form
So is it possible to have a scriptto add this question to all 20 forms
2- The "access code" in these google forms will have to be updated frequently, so I don' want to be updating the "Pattern" manually for each form, is t possible to have a google script to edit the value of the pattern for each form
Thanks in advance guys :)
I managed to solve this issue that I was having, through looking for different codes and here are the codes that I used.
N.B. The codes might not be very clean as I was copying them from other parts/projects, but they have worked for me
1- Update the 20 forms with adding the access code question, I figured it was not possible to add a question at a certain position in the google form, however I can add a question at the end of the form and then move this item to the position I want:
function AddAccesscodeQ() {
var filess = DriveApp.getFolderById("Drive id>").getFiles();
while (filess.hasNext()) {
var file = filess.next();
var form = FormApp.openById(file.getId());
var sectionIndex= 0; // Please set the index you want to insert.
//I added a "sample item" to be moved and edited later
var newItemQ = form.addTextItem().setTitle("New sample item").getIndex(); // New sample item
// I added a Pagebreak that also should be moved after the questions "Enter Your Access Code"
var newItemPB = form.addPageBreakItem().getIndex();
var items = form.getItems(FormApp.ItemType.PAGE_BREAK);
var sections = [0];
for (var i = 0; i < items.length; i++) {
// I pushed the items in the google form twice downwards, to be able to move the "sample item" and "Page break" to the top of the form
sections.push(items[i].getIndex());
sections.push(items[i].getIndex());
}
var insertIndex = sections[sectionIndex + 1] || null;
if (insertIndex) {
// Here I moved the 2 new items to the desired positions
form.moveItem(newItemQ, 0);
form.moveItem(newItemPB, 1);
}
// Here I am going to edit the "Sample Question" to be as desired
var itemss = form.getItems();
var itemID = itemss[0].getId();
var itemse = form.getItemById(itemID).asTextItem()
.setTitle('Enter Your Access Code').setRequired(true);
//Create validation rule
var validation = FormApp.createTextValidation()
.setHelpText('Invalid Code')
.requireTextMatchesPattern("<Access Code>")
.build();
itemse.setValidation(validation);
}
}
2- The second problem was that I later might need to change this access code to a new one for the 20 forms
function UpdateAccessCode() {
var filesPhCH = DriveApp.getFolderById("<Drive ID>").getFiles();
while (filesPhCH.hasNext()) {
var file = filesPhCH.next();
var form = FormApp.openById(file.getId());
var items = form.getItems();
//Loop through the items and list them
for (var i = 0;i<items.length;i++){
var item = items[i];
var itemID = item.getId();
var itemtitle = item.getTitle();
var itemindex = item.getIndex();
// I found no need to continue the for loop since the items that need modification are at the top of the form
if (itemindex == 0){
break;
}
}
//Select the question you want to update
var itemse = form.getItemById(itemID).asTextItem()
.setTitle('Enter Your Access Code');
//Create validation rule
var validation = FormApp.createTextValidation()
//.setTitle('Enter Your Access Code');
.setHelpText('Invalid Code')
.requireTextMatchesPattern("<Enter the new Access Code>")
.build();
itemse.setValidation(validation);
}
}
I hope this might help someone as it has saved a lot of time for me ;)
Following the doc and the example provided by cno I tried making a Bar Chart but despite the tries and the tests I always fall on the same result. I am sure I either missed something or I made a mistake somewhere, maybe there is some parameter I didn't understand well like the scale
Current BarChart Code
public Form createBarChartForm()
{
XYMultipleSeriesRenderer rendererTwo
= new XYMultipleSeriesRenderer(300);
rendererTwo.setBarWidth(300);
// rendererTwo.addYTextLabel(1, "ok");
// rendererTwo.addXTextLabel(5, "Ouuhh");
rendererTwo.setXAxisMin(1, 50);
rendererTwo.setXAxisMax(5, 200);
rendererTwo.setGridColor(ColorUtil.GREEN, 10);
// rendererTwo.setDisplayValues(true);
// rendererTwo.setYAxisMin(5);
// rendererTwo.setYAxisMax(5, 10);
com.codename1.charts.models.XYMultipleSeriesDataset dataset
= new XYMultipleSeriesDataset();
XYSeries xYSeries = new XYSeries("Hi", 50);
XYSeries xYSeries2 = new XYSeries("Hello", 150);
XYSeries xYSeries3 = new XYSeries("Hola", 80);
dataset.addSeries(xYSeries);
dataset.addSeries(xYSeries2);
dataset.addSeries(xYSeries3);
com.codename1.charts.views.BarChart chart = new com.codename1.charts.views.BarChart(
dataset, rendererTwo, BarChart.Type.STACKED);
// Wrap the chart in a Component so we can add it to a form
ChartComponent c = new ChartComponent(chart);
// Create a form and show it.
Form f = new Form("Budget", new com.codename1.ui.layouts.BorderLayout());
f.add(com.codename1.ui.layouts.BorderLayout.CENTER, c);
return f;
}
Result (Always The same when no errors)
Result (Stack Overflow upload would show at the bottom right and not entierly)
I found a chart demo on cno's website and it was more than I asked for.
Link To Charts Demo
It contains demo for all charts and it's well made.
I download the git project and tested out the one I need (extracted some methods) and it works. I would say I was 50% in the way of getting there.
I apologize if this was useless as I didn't really think the website would contain demo and I just fell on the site randomly.
I know very little about code and am simply looking for help if someone knows how to do this. I have a google spreadsheet and for this example let's say
Column A is an email address
Column B is text
Column C is a dropdown list of items made using the Data Validation tool (pending, scheduled and complete).
I need a code that upon selecting "Complete" in column C, an email is sent to the recipient in column A with the body of the email containing the text from column B.
Any help is appreciated as I'm not a developer, I'm a pastor trying to help my church run more smooth.
and here's the link to the spreadsheet... https://docs.google.com/spreadsheets/d/1bA-gDvZ_jbJMyU6IqExBjHKclrKmqJSMHyuKHsr2CMA/edit?usp=sharing
and here's the script...
var sheetname = "FacilitiesWorkRequests";
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var range = sheet.getRange(1, 3, sheet.getLastRow(), 1);
var list = SpreadsheetApp.newDataValidation().requireValueInList(["pending", "scheduled", "complete"], true).build();
range.setDataValidation(list);
}
function onEdit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var ac = sheet.getActiveCell();
if (ac.getValue() == "complete") {
data = sheet.getRange(ac.getRowIndex(), 1, 1, 2).getValues();
Logger.log(data)
MailApp.sendEmail({
to: data[0][0],
subject: "sample mail",
body: data[0][1]
});
}
}
How about this sample?
var sheetname = "Here, please input your sheet name.";
function onOpen() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var range = sheet.getRange(1, 3, sheet.getLastRow(), 1);
var list = SpreadsheetApp.newDataValidation().requireValueInList(["pending", "scheduled", "complete"], true).build();
range.setDataValidation(list);
}
function onEdit() {
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetname);
var ac = sheet.getActiveCell();
if (ac.getValue() == "complete") {
data = sheet.getRange(ac.getRowIndex(), 1, 1, 2).getValues();
Logger.log(data)
MailApp.sendEmail({
to: data[0][0],
subject: "sample mail",
body: data[0][1]
});
}
}
Please copy and paste this script to the script editor on spreadsheet, and set a sheet name you use, and then install a trigger. How to install a trigger is as follows. You can see the detailed information of this at https://developers.google.com/apps-script/guides/triggers/installable#google_apps_triggers.
At the script editor, choose "Resources" - "Current project's triggers".
Click "here" and add a trigger.
Under Run, select the function of "onEdit()".
Event is "From spreadsheet" - "Change of value".
For this sample script, when you open spreadsheet with this script, the dropdown list is applied, while the existing dropdown list is not changed. Because if you had added new row, new dropdown list is added. When you run this script, if authentication screen appears, please authenticate it.
And when you choose "complete" from the dropdown list, an e-mail is sent using e-mail of same row you chose. E-mail body is column B of same row.
If this will be helpful, I'm glad.
I've been trying to get closed captions working with the SEF player, but haven't had any luck. My app uses playready streams and I've tried side loading the SAMI files, but I get errors. I would prefer to do side loading, but if I can get embedded closed captions to work that would be a first step. There seems to be limited and conflicting documentation and posts on the Samsung developer's forum so I'm hoping to find someone who has gotten this to work on 2012/2013 devices.
Here's what I have tried:
var SefPlugin = document.getElementById('pluginDL');
alert(" " + SefPlugin.Open("Download", "1.000", ""));
alert(SefPlugin.Execute('GetPluginInfo'));
var ret = SefPlugin.Execute('StartDownFile', 'http://testurl.com/test.smi', '$TEMP/subtitle.smi', 10, 10);
alert("SUBTITLE DOWNLOAD RETURNED: " + ret);
The output is:
JS ALERT: 1
JS ALERT: 1
JS ALERT: SUBTITLE DOWNLOAD RETURNED: 1
Then in the OnStreamInfoReady method I attempt to do this:
alert(" START SUBTITLE: " +Player.plugin.Execute("StartSubtitle", '$TEMP/subtitle.smi'));
alert("SET STREAM ID: " +Player.plugin.Execute("SetStreamID", 5, 0));
The output is:
JS ALERT: START SUBTITLE: -1
JS ALERT: SET STREAM ID: 1
The StartSubtitle returning -1 is an error and I'm not sure what the problem is with this scenario.
I also tried the AVPlay plugin by downloading the subtitle file the same way as above. Then, I tried to initiate a play action by calling:
var subtitleDataCallback = (function(syncTime, data) {
alert(syncTime + " : " + data);
})();
Main.AVPlayerObj.open('http://testurl.com/test.mp4',
{
subtitle: {
path: "subtitle.smi",
streamID : 0,
sync : 1000,
subtitleDataCallback: subtitleDataCallback
}
});
It plays the content if I leave out the subtitle object, but when I have the subtitle object there it gives me the following error:
JS ALERT: ======================================= ERROR2: TYPE_MISMATCH_ERR
I tried $TEMP/subtitle.smi for the path as well, but I receive the same mismatch error. Any guidance would be greatly appreciated.
I never actually got subtitle files to work with the player. I found a subtitle parser and ripped it out from (http://mediaelementjs.com/). It gives you each subtitle entry in an array that has the time when the subtitle should start showing and when it should stop showing.
I've been working in Titanium appaccelerator and now I'm trying to open a video in it.
I've used the following code:
movieWindow.js
function displayVideo()
{
var window = Ti.UI.createWindow({
width:200,
height:300,
});
var activeMovie = Titanium.Media.createVideoPlayer({
url:"respigrandsoupir.mp4",
width:300,
height:200,
top:50,
left:50,
backgroundColor:'#0f0'
});
window.add(activeMovie);
activeMovie.play();
return window;
}
My video respigrandsoupir.mp4 is under the Resource folder. The problem is that when trying to run this method I get the following error:
[WARN] Exception in event callback. { expressionBeginOffset = 159;
expressionCaretOffset = 173;
expressionEndOffset = 191;
line = 12;
message = "Result of expression 'Titanium.Media' [undefined] is not an object.";
name = TypeError;
sourceId = 238167336;
sourceURL = "file://localhost/Users/adrian/Documents/Titanium%20Studio%20Workspace/La%20Pause/Resources/movieWindow.js";
}
Can one tell me where am I going wrong?
Thank you for your valuable answers, but Project->Clean solved my issue!
When you use a new object like Titanium.Media that you never used before, a clean is often required because Titanium builds a custom light version in the target folder.
If you don't clean, it will search in vain the widget in this folder.