iT邦幫忙

2026 iThome 鐵人賽

DAY 27
0
佛心分享-SideProject30

看得到的演算法:用 Vue 3 打造演算法互動視覺化平台系列 第 27 篇

【Day 27】Vue 實作 — 播放器:我該怎麼開始播放我的演算法動畫?

  • 分享至 

  • xImage
  •  

前面不管是 Bubble Sort、Quick Sort 還是 Dijkstra,我都已經把演算法執行過程記錄成一張張「快照」。

但快照做好之後,現在又遇到新的問題:

我要怎麼讓這些快照自己一張一張播放?按下暫停後,又要怎麼真的停下來?

今天就來幫演算法視覺化加上最基本的播放器功能:Play、Pause、Reset。


怎麼取得每一步的畫面?

以 Bubble Sort 為例,目前 steps 裡已經記錄了每個時間點需要的資料:

steps[0] = {
  arr: [18, 66, 79, 84, 4, 29, 27, 83],
  barStates: ['default', 'default', ...],
  phase: 'start',
  summary: '共 8 筆資料,準備開始氣泡排序。'
}

steps[1] = {
  arr: [18, 66, 79, 84, 4, 29, 27, 83],
  barStates: ['active', 'comparing', ...],
  phase: 'compare',
  summary: '比較 [0] 18 與 [1] 66'
}

所以其實我不是要讓 Bubble Sort 重新執行一次。

真正需要做的事情只是:

steps[0]
   ↓
steps[1]
   ↓
steps[2]
   ↓
steps[3]
   ↓
...

也就是讓目前顯示的步驟 currentStep 自動增加。


問題一:怎麼讓 currentStep 自己增加?

如果只是手動下一步,其實很簡單:

currentStep.value++

畫面原本就是根據:

steps[currentStep.value]

取得目前要顯示的快照,因此 currentStep 從 0 變成 1,畫面自然就會換成 steps[1]。

但我現在想要的是:

不用一直按「下一步」,每隔一段時間自動前進。

我想到可以試試看用 for 迴圈慢慢吐資料……

for 迴圈可以一筆一筆「處理」資料,但不代表瀏覽器會一筆一筆「畫」給你看。

假設這樣寫:

for (let i = 0; i < steps.length; i++) {
  currentStep.value = i
}

我原本想像的是:

currentStep = 0 → 畫面顯示第 0 步
currentStep = 1 → 畫面顯示第 1 步
currentStep = 2 → 畫面顯示第 2 步
currentStep = 3 → 畫面顯示第 3 步

但實際上 for 迴圈跑得非常快,而且這些程式會在同一次同步任務裡完成。

所以比較接近:

for 開始
↓
currentStep = 0
currentStep = 1
currentStep = 2
currentStep = 3
...
currentStep = 最後一步
↓
for 結束
↓
Vue / 瀏覽器更新畫面

結果看到的很可能就是:

啪!直接變成最後一張。

所以最後真正需要解決的不是「怎麼一筆一筆取得快照」,而是:

怎麼讓每一張快照之間有等待時間?

這時就可以使用 setTimeout:

function scheduleNext() {
  timer = setTimeout(() => {
    currentStep.value++

    if (!isLastStep.value) {
      scheduleNext()
    }
  }, 700)
}

第一次 setTimeout 時間到了,currentStep 加 1。

如果還沒到最後一步,再執行一次 scheduleNext()。

這樣就會變成:

等待 700ms
→ currentStep + 1
→ 等待 700ms
→ currentStep + 1
→ ...

讓 currentStep 不要一次跑到底,而是每隔一段時間才前進一步,快照也就真的「播放」起來了。


問題二:按下暫停,要怎麼讓它停下來?

既然播放是靠 Timer 控制,那暫停其實就是:

把還在等待執行的 Timer 清掉。

所以我另外記錄:

const isPlaying = ref(false)
let timer: ReturnType<typeof setTimeout> | null = null

播放時:

function play() {
  isPlaying.value = true
  scheduleNext()
}

暫停時:

function pause() {
  isPlaying.value = false

  if (timer) {
    clearTimeout(timer)
    timer = null
  }
}

clearTimeout() 之後,原本排好的下一次 currentStep++ 就不會發生。

而且我沒有修改 currentStep,所以畫面會直接停留在目前這張快照。

再次按下 Play 時,再從現在的 currentStep 繼續往下播放。


Reset 反而最簡單

Reset 就沒有播放和暫停那麼複雜了。

先停止目前的 Timer,再把:

currentStep.value = 0

設回第 0 步即可:

function reset() {
  pause()
  currentStep.value = 0
}

因為第 0 張快照本來就是演算法還沒開始執行前的狀態,所以畫面自然也跟著回到最開始。

下一篇,我還想再加入 上一步、下一步以及播放倍速,讓這個播放器不只能自己跑,也可以自己控制演算法執行的節奏。


上一篇
【Day 26】Vue 實作 — Dijkstra 都算出最短路徑了,為什麼畫面還不能直接用?
系列文
看得到的演算法:用 Vue 3 打造演算法互動視覺化平台 共 27 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言