引言
程式除了可以做到自動化,
還可以幫助溝通與表達。
有時候某個概念用文字講起來繁複又抽象。
但我只要寫個程式示範給你看,你一看便懂了。
例如碎形。
這一篇我就要來示範,
如何用 Google Apps Script 做一個前端碎形動畫,
把你的想法展示給全世界看。
需求背景
當我在跟其它家長聊天的時候,
常常會感受到一種父母的焦慮。
那是一種憂心孩子能否立足這個世界的焦慮。
所以爸媽們無不費盡心思花錢栽培孩子,以緩解這種焦慮。
而且這種焦慮,無論家裡錢多錢少都還是有。
年收千萬的,有千萬的焦慮,
年收百萬的,有百萬的焦慮,
年收十萬的,有十萬的焦慮。
雖然各自的賽道不同,考量的事物各異,
但是那份焦慮的情緒倒是相當一致。
你以為多賺九倍的錢,人生從此能快樂幸福?
你以為少賺九成的錢,人生便落入愁雲慘霧?
哪有這種事。
就好像碎形一樣,
你放大九倍來看跟你縮小九倍來看,
看起來不是都差不多嗎?
講到這裡,
有些人可能不熟悉什麼是碎形。
而這個概念講起來有點抽象,
要解釋清楚不太容易。
所以我就用 Google Apps Script 寫了一個動畫。
當然,不是我自己寫的,
是請 ChatGPT 寫的。
請見這個網頁成果:碎形動畫展示
怎麼向 ChatGPT 提需求?
正如我們在 《零基礎快速入門:GenAI 搭配 Google Apps Script 的工作自動化寶典》Chapter 1-2 魔法是想像的世界 所學習過的概念,
在請 ChatGPT 寫程式之前,
我們必須要自己先有一個非常清楚的具體想像,
具體到你閉上眼就能看到那個畫面。
在這個碎形動畫的需求上,
我的想像是先有一個謝爾賓斯基地毯(Sierpinski carpet),
然後不斷地往某一個點深入挖掘。
所以我的多階段提問是這樣的:
https://chatgpt.com/share/6701db04-7a64-800e-b652-2afd6d9e124c
以 Google Apps Script 的功能,有辦法做出網頁動畫嗎?
例如一個不停反復放大縮小的正方形動畫?有辦法畫一個靜態的 謝爾賓斯基地毯 嗎?
有辦法加上一個動畫,
讓這個畫好的謝爾賓斯基地毯不斷放大嗎?可以幫我改成:放大時,固定最左上角的點不動,其餘部分往右往下放大嗎?
最終程式碼成果
<!DOCTYPE html>
<html>
<head>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
}
</style>
</head>
<body>
<canvas id="carpetCanvas" width="600" height="600"></canvas>
<script>
function drawSierpinskiCarpet(ctx, x, y, size, depth) {
if (depth === 0) {
ctx.fillRect(x, y, size, size);
} else {
var newSize = size / 3;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (i !== 1 || j !== 1) {
drawSierpinskiCarpet(ctx, x + i * newSize, y + j * newSize, newSize, depth - 1);
}
}
}
}
}
function animate() {
var canvas = document.getElementById('carpetCanvas');
var ctx = canvas.getContext('2d');
var scale = 1;
var depth = 6; // Adjust the depth here
var direction = 1;
var offscreenCanvas = document.createElement('canvas');
offscreenCanvas.width = canvas.width;
offscreenCanvas.height = canvas.height;
var offscreenCtx = offscreenCanvas.getContext('2d');
var previousTimestamp = null;
var interval = 1000 / 30; // 30 FPS (frames per second)
function drawSierpinskiCarpet(ctx, x, y, size, depth) {
if (depth === 0) {
ctx.fillRect(x, y, size, size);
} else {
var newSize = size / 3;
for (var i = 0; i < 3; i++) {
for (var j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
continue; // Center square
}
drawSierpinskiCarpet(ctx, x + i * newSize, y + j * newSize, newSize, depth - 1);
}
}
}
}
// Initial draw
drawSierpinskiCarpet(offscreenCtx, 0, 0, offscreenCanvas.width, depth);
function draw(timestamp) {
// var timestamp = performance.now();
// if (!previousTimestamp) {
// previousTimestamp = timestamp;
// }
// var intervalTime = timestamp - previousTimestamp;
// previousTimestamp = timestamp;
// console.log('Current Time:', new Date(timestamp).toLocaleTimeString(), 'Interval:', intervalTime.toFixed(2), 'ms');
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.scale(scale, scale);
ctx.fillStyle = 'black';
drawSierpinskiCarpet(ctx, 0, 0, canvas.width, depth);
ctx.restore();
scale += direction * 0.01;
if (scale >= 3) {
scale = 1; // Stop scaling when it reaches 3
}
setTimeout(draw, interval);
// requestAnimationFrame(draw);
}
draw();
}
window.onload = animate;
</script>
</body>
</html>
以上這個程式碼是前端程式,是要放在 index.html 裡的。
記得在 .gs
裡也要放一段 doGet()
function doGet() {
return HtmlService.createHtmlOutputFromFile('index.html')
.setTitle('Animated Square')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
}
關於 .html
的新增方式,
可參考前一篇的 Chapter 5-1 前端範例:偽陽性計算機 步驟教學。
如果你有仔細跟我附的對話紀錄比對的話,
你會發現這個程式碼跟 ChatGPT 給的不太一樣。
是的,
因為我想讓動畫效果更順暢,
就自己動手修了一下程式碼,
這個步驟當然也可以跟 ChatGPT 討論請他幫忙改,
但我之所以請 ChatGPT 寫程式本是為了偷懶。
而我自己改程式也是為了偷懶。
因為有些參數我自己調整起來更快,
就不用浪費時間力氣再跟 ChatGPT 來回問答了。
結語
其實昨天和今天的這兩個案例,
都是屬於純前端就可以做得到的功能。
意思是並不需要用到牛刀 Google Apps Script 。
但很多讀者都是真正完全零基礎零經驗的朋友,
從來也沒有寫過一個網頁程式。
希望這兩個範例可以讓你做出第一個「可以發佈在網路上給朋友觀看或使用」的網頁工具。
有任何問題,歡迎與我討論!