Обновлено: Окончательное решение было добавлено в качестве ответа, но я отметил ответ Танаике как решение, поскольку он указал мне в правильном направлении.
Я настраиваю Google AppScript для автоматизации некоторых отчетов. Я получаю некоторые данные, а затем хочу создать слайды по мере необходимости для отчета по всем данным.
Презентация, которую я использую в качестве шаблона, имеет разные макеты из трех столбцов с заполнителями подзаголовков для заголовков столбцов и заполнителями тела для текста столбца.
Предположим, макеты слайдов аналогичны рисунку ниже.
Используя замещающий текст для этих полей, я смог в некоторой степени понять расположение слайдов.
function getPlaceholders(layout) {
layout.getPlaceholders().forEach((e, i) => {
Logger.log("[%s] %s %s", i, e.getPageElementType(), p.getDescription());
});
}
Напечатает что-то вроде [0.0] SHAPE Header 1
, где Column 1 header
— это альтернативный текст, который я установил для этого заполнителя.
Но я столкнулся с 2 проблемами:
Сценарий ниже добавит только 2 слайда. На первом слайде поля будут заполнены.
Второй слайд не содержит текста в полях, поскольку сценарии, похоже, не могут их обнаружить.
function test(g) {
let styles = [
"CUSTOM_1",
"CUSTOM_1_2",
"CUSTOM_1_2_1",
"CUSTOM_1_2_1_1"
]
styles.forEach((style, index) => {
let newslide = g.addSlide(g.getLayout(style))
Logger.log("[%s] %s", index, style);
newslide.getPlaceholders().forEach((p, i) => {
// Won't print alt text as those aren't carried from template layouts to actual slides
Logger.log(" [%s] %s %s %s", i, p.getPageElementType(), p.getTitle(), p.getDescription());
});
for (let i = 0; i < 3; i++) {
newslide.getPlaceholder(SlidesApp.PlaceholderType.SUBTITLE, i).asShape().getText().setText(`Header ${index}-${i}`);
newslide.getPlaceholder(SlidesApp.PlaceholderType.BODY, i).asShape().getText().setText(`Body ${index}-${i}`);
}
});
}
Это сообщит, например.
10:04:39 AM Info [0.0] CUSTOM_1
10:04:39 AM Info [0.0] SHAPE
10:04:39 AM Info [1.0] SHAPE
10:04:39 AM Info [2.0] SHAPE
10:04:39 AM Info [3.0] SHAPE
10:04:39 AM Info [4.0] SHAPE
10:04:39 AM Info [5.0] SHAPE
10:04:39 AM Info [6.0] SHAPE
10:04:40 AM Info [1.0] CUSTOM_1_2
10:04:40 AM Info [0.0] SHAPE
10:04:40 AM Info [1.0] SHAPE
10:04:40 AM Info [2.0] SHAPE
10:04:40 AM Info [3.0] SHAPE
10:04:40 AM Info [4.0] SHAPE
10:04:40 AM Info [5.0] SHAPE
10:04:40 AM Info [6.0] SHAPE
10:04:40 AM Error
TypeError: Cannot read properties of null (reading 'asShape')
(anonymous) @ App.gs:115
test @ App.gs:106
main @ App.gs:132
Похоже, заполнители на втором слайде не распознаются как типы SlidesApp.PlaceholderType.SUBTITLE
.
Поэтому я изменил цикл for следующим образом:
for (let i = 0; i < 3; i++) {
newslide.getPlaceholders()[2*i].asShape().getText().setText(`Header ${index}-${i}`);
newslide.getPlaceholders()[2*i+1].asShape().getText().setText(`Body ${index}-${i}`);
}
Однако это по-прежнему не дает хороших слайдов, поскольку порядок элементов по-прежнему нелогичен.
Слайд 1
Слайд 2
Слайд 3
Слайд 4
Чего я хочу добиться, так это иметь возможность программно заполнять эти слайды в логическом порядке. Т.е. (в псевдокоде)
let index = 0;
let slide;
report.forEach((r) => {
if (index == 0) { slide = addSlide(layout_x) };
slide.placeholder(type=subhead)[index].setText(r.title);
slide.placeholder(type=body)[index].setText(r.content);
index = (index + 1) % 3;
});
ТЛ;ДР;
Как настроить шаблон презентации так, чтобы получить последовательный и логичный порядок элементов-заполнителей?
@Tanaike Четыре таблицы представляют собой четыре слайда, созданные сценарием. Я отредактировал свое сообщение, добавив рисунок, который поможет вам визуализировать то, что представляют собой таблицы. Я ищу способ программно сказать: объект 1 из отчета, поместить заголовок в подзаголовок вверху слева и текст в теле вверху справа, в то время как объект 2 находится посередине, а объект 3 справа. Для obj4 создается новый слайд, содержимое помещается в левый столбец и т. д.
Спасибо за ответ. Судя по вашему ответу и обновленному вопросу, я подумал о подходе к решению вашей проблемы. В вашей ситуации как насчет управления ими с помощью названия и/или описания каждой фигуры в макете? Например, установите заголовок «Подзаголовок1» в левом верхнем углу «Макет слайда 1 (CUSTOM_1)». При этом вы можете выполнить поиск по форме «subhead1» с помощью скрипта. В моем случае я использую заголовок и описание для управления изображениями в Google Slides. Если это не было включено в ожидаемое вами направление, прошу прощения.
Я пробовал это, используя текстовое описание Alt в макете (редакторе шаблонов), но они не копируются на слайд после создания слайда на основе этого слайда. Могу ли я использовать другое свойство?
Спасибо за ответ. Что касается I have tried this using the Alt text description in the Layout (Template Editor), but those aren't copied to the slide once a slide is created based on that slide.
, можете ли вы предоставить образцы слайдов для правильного воспроизведения?
@Tanaike Я добавил несколько скриншотов. Там вы можете увидеть заполнитель субтитров и альтернативный текст. Они определены в макете слайда («Слайд» > «Редактировать тему»). Альтернативный текст можно получить через Presentation.getLayouts()[i].getPlaceholders()[i].getDescription();
Developers.google.com/apps-script/reference/slides/… / Developers.google.com/apps-script/reference/slides/… / Developers. google.com/apps-script/reference/slides/…
Спасибо за ответ. На основе вашего ответа я хотел бы подготовить образец слайда Google с вашей ситуацией и протестировать его.
В качестве другого подхода вместо заголовка и описания я предложил использовать в качестве ответа идентификатор объекта. Пожалуйста, подтвердите это. Если вы не ожидали такого подхода, я еще раз прошу прощения.
В качестве другого подхода вместо заголовка и описания хотелось бы предложить использовать ID объектов в макете. Если для макета задан слайд, идентификатор объекта макета можно увидеть как значение родительского объектаId. Когда объекты (например, их форма) извлекаются из макета, можно получить идентификатор объекта, заголовок и описание. Используя их, можно получить каждый идентификатор объекта, соответствующий каждому заголовку. Таким образом, даже если макет установлен на слайд, происхождение вставленных объектов можно узнать с помощью родительского идентификатора объекта. Если это отразить в простом примере сценария, это будет выглядеть следующим образом.
Пожалуйста, подготовьте следующий индивидуальный макет. И установите заголовок каждой фигуры как «subtitle1», «body1», «subtitle2», «body2».
Установите созданный пользовательский макет на первую страницу Google Slides. Это происходит следующим образом.
Чтобы правильно вставить текст в каждый заполнитель, используется следующий пример сценария. Пожалуйста, установите имя пользовательского макета на layoutName
. И, пожалуйста, установите заголовок и вставленный текст в качестве ключа и значения соответственно.
В этом примере тексты «образец заголовка 1», «образец тела 1», «образец заголовка 2», «образец тела 2» вставляются в заполнители «subtitle1», «body1», «subtitle2», «body2». ", соответственно.
function myFunction() {
// Please set your custom layout name.
const layoutName = "CUSTOM";
// Please set the title and the inserted text as the key and value, respectively.
const object = {
subtitle1: "sample title 1",
body1: "sample body 1",
subtitle2: "sample title 2",
body2: "sample body 2",
};
// Create an object including the parent object ID and the inserting text.
const s = SlidesApp.getActivePresentation();
const layout = s.getLayouts().find(e => e.getLayoutName() == layoutName);
const newObject = layout.getPageElements().reduce((o, e) => (o[e.getObjectId()] = object[e.getTitle()] || "", o), {});
// Insert the texts to each object of the placeholder.
const slide = s.getSlides()[0]; // As a sample, 1st page is used.
slide.getShapes().forEach(s => {
const parentObjectId = s.getParentPlaceholder().getObjectId();
if (newObject[parentObjectId]) {
s.getText().setText(newObject[parentObjectId]);
}
});
}
Когда этот сценарий запускается в описанной выше ситуации ввода, получается следующий результат.
Это простой пример сценария для объяснения моего подхода. Поэтому, пожалуйста, измените это в соответствии с вашей реальной ситуацией.
В этом примере, чтобы упростить управление, я использовал идентификатор объекта и заголовок заполнителя. Однако, если вы уже знаете идентификаторы объектов всех заполнителей, я думаю, вы можете напрямую создать object
в приведенном выше скрипте. В этом случае const newObject = ,,,
использовать не обязательно.
Спасибо за помощь! Я скоро попробую. Быстрый вопрос: где мне установить заголовок элемента. Это в разделе «Дополнительные параметры» в разделе «Альтернативный текст»?
@BlueCacti Спасибо за ответ. Насчет Quick question: where do I set the element's title. Is it under the Advanced Options under Alt text?
, да. Вы можете установить заголовок фигуры в «Дополнительных параметрах» в «Замещающий текст» в разделе «Параметры формата».
Потрясающий! Внес несколько изменений (также опубликую отредактированную версию в качестве ответа) и заставил ее работать 🎉
Это отредактированная копия функции, которую я в конечном итоге получил. Еще раз спасибо @Tanaike за то, что указал мне правильное направление.
Вероятно, я мог бы хранить ссылки на объекты TextRange вместо объектов Placeholder в функции reduce()
, чтобы избежать дублирования .asShape().getText()
.
/**
* Create the report slides
* @param {Google} google Google instance
* @param {Report} report Report instance
*/
function createReportSlides(google, report, project) {
let styles = [
"CUSTOM_1", // layout 0
"CUSTOM_1_2", // layout 1
"CUSTOM_1_2_1", // layout 2
"CUSTOM_1_2_1_1", // layout 3
]
let iCounter = 0; // Item counter
let curTitle = ""; // Current title
// Uses global variable for list of topics ('title': str, 'items': [])
TOPICS.forEach((t, i) => {
let title = t.title;
let slide;
if (title != curTitle) {
/**
* @todo Add topic overview slide. Copy/move the correct slide or add?
*/
curTitle = title;
iCounter = 0;
let objects = {};
}
t.items.forEach((item) => {
let summaries = report.getItemSummary(project, title, item);
if (summaries.length > 0) {
if (iCounter == 0) {
slide = google.addSlide(google.getLayout(styles[i]));
objects = slide.getPlaceholders().reduce((o, e) => (
// Store reference to placeholders based on Alt Title
// Alt Title is Header_x or Body_x or empty
o[e.asShape().getParentPlaceholder().getTitle() || "_"] = e, o), {}
);
}
objects[`Header_${lCounter}`].asShape().getText().setText(item);
objects[`Body_${lCounter}`].asShape().getText().setText(summaries.join("\v")); // \v = vertical tab (same as shift+return)
iCounter = (iCounter+1)%3;
}
});
});
}
Я должен извиниться за мое плохое знание английского языка. К сожалению, я не могу понять ваш вопрос. Показанные вами 4 таблицы, от «Слайд 1» до «Слайд 4», существуют на 1-4 страницах вашего слайда Google? И это входная ситуация? Если я правильно понимаю, могу ли я спросить вас о деталях
a consistent and logical order of placeholder elements
? Во-первых, мне хотелось бы правильно понять Ваш вопрос.