Created
May 14, 2025 14:48
-
-
Save htlin222/9861e4747313657598535f76ef4cb09b to your computer and use it in GitHub Desktop.
Google Slides Custom Progress Bar Generator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function onOpen() { | |
const ui = SlidesApp.getUi(); | |
ui.createMenu('自定功能') | |
.addItem('⏳ Reload ProgressBars', 'updateProgressBars') | |
.addToUi(); | |
} | |
function updateProgressBars() { | |
const presentation = SlidesApp.getActivePresentation(); | |
const slides = presentation.getSlides(); | |
const totalSlides = slides.length; | |
const maxWidth = 720; | |
const yPosition = 402; | |
const height = 3; | |
for (let i = 1; i < totalSlides; i++) { // Start from 2nd slide | |
const slide = slides[i]; | |
// 1. Remove old progress bar if exists | |
const shapes = slide.getShapes(); | |
for (let shape of shapes) { | |
if (shape.getTitle && shape.getTitle() === 'PROGRESS') { | |
shape.remove(); | |
} | |
} | |
// 2. Calculate new width | |
const progressRatio = i / ( totalSlides - 1); | |
const barWidth = maxWidth * progressRatio; | |
// 3. Insert new progress bar | |
const bar = slide.insertShape(SlidesApp.ShapeType.RECTANGLE, 0, yPosition, barWidth, height); | |
bar.getFill().setSolidFill('#000000'); | |
bar.getBorder().setTransparent(); | |
// 4. Tag the shape for future identification | |
bar.setTitle('PROGRESS'); | |
} | |
} |
Brilliant work! This is a fantastic addition to the already excellent "NEJM模版2020新版" — thank you so much for sharing it.
I’ve put together a modified version that omits skipped slides in the progress bar and adds a slide number feature as well.
P.S. The Apps Script is almost entirely "vibe-coded," so the style might not be the cleanest 😄
function onOpen() {
const ui = SlidesApp.getUi();
ui.createMenu('自定功能')
.addItem('⏳ Reload ProgressBars', 'updateProgressBars')
.addItem('🔢 Update SlideNumbers', 'addSlideNumbersSkippingSkipped')
.addItem('✅ Update Both', 'updateAll')
.addToUi();
}
function updateProgressBars() {
const presentation = SlidesApp.getActivePresentation();
const slides = presentation.getSlides();
// Build list of non-skipped slide indexes (excluding 1st slide)
const nonSkippedIndexes = slides
.map((slide, index) => ({ slide, index }))
.filter(({ slide, index }) => index > 0 && !slide.isSkipped())
.map(({ index }) => index);
const totalNonSkipped = nonSkippedIndexes.length;
const maxWidth = 720;
const yPosition = 402;
const height = 3;
if (totalNonSkipped <= 1) return; // nothing to show progress for
for (let i = 1; i < slides.length; i++) { // Start from 2nd slide
const slide = slides[i];
// Remove old progress bar if exists
const shapes = slide.getShapes();
for (let shape of shapes) {
if (shape.getTitle && shape.getTitle() === 'PROGRESS') {
shape.remove();
}
}
// Skip if slide is marked as skipped
if (slide.isSkipped()) continue;
// Find progress position in the non-skipped slide sequence
const progressPosition = nonSkippedIndexes.indexOf(i) + 1; // progressPosition starts from 0
const progressRatio = progressPosition / (totalNonSkipped); // totalNonSkipped excluded 1st slide
const barWidth = maxWidth * progressRatio;
const bar = slide.insertShape(SlidesApp.ShapeType.RECTANGLE, 0, yPosition, barWidth, height);
bar.getFill().setSolidFill('#000000');
bar.getBorder().setTransparent();
bar.setTitle('PROGRESS');
}
}
function addSlideNumbersSkippingSkipped() {
const presentation = SlidesApp.getActivePresentation();
const slides = presentation.getSlides();
// Get indexes of non-skipped slides (excluding title slide)
const nonSkippedIndexes = slides
.map((slide, index) => ({ slide, index }))
.filter(({ slide, index }) => index > 0 && !slide.isSkipped())
.map(({ index }) => index);
const fontSize = 18;
const fontFamily = "Cambria";
const x = 670;
const y = 365;
// Clear existing slide numbers
slides.forEach(slide => {
slide.getShapes().forEach(shape => {
if (shape.getTitle?.() === 'SLIDE_NUMBER') {
shape.remove();
}
});
});
// Insert new slide numbers based on non-skipped order
nonSkippedIndexes.forEach((slideIndex, i) => {
const slide = slides[slideIndex];
const shape = slide.insertTextBox(`${i + 1}`, x, y, 40, 30);
shape.getText().getTextStyle().setFontSize(fontSize);
shape.getText().getTextStyle().setFontFamily(fontFamily);
shape.getText().getParagraphStyle().setParagraphAlignment(SlidesApp.ParagraphAlignment.END);
shape.setTitle('SLIDE_NUMBER');
});
}
function updateAll() {
updateProgressBars();
addSlideNumbersSkippingSkipped();
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This Google Apps Script adds a custom menu item titled “⏳ Reload ProgressBars” to Google Slides. When triggered, it updates visual progress bars across all slides (excluding the first slide), indicating slide progression. Each bar adjusts its width based on the current slide’s position in the presentation. Existing progress bars are removed and replaced to maintain accuracy.