昨天建立好 Vue 專案的基本架構,今天終於要開始製作第一個跟演算法視覺化有關的功能:把 Array 畫成長條圖。
假設有一組資料:
const arr = ref<number[]>([5, 3, 8, 1])
平常看到的只是四個數字,但之後 Bubble Sort 開始交換位置時,我希望可以直接從畫面看到資料的變化。
Vue 可以透過 v-for 把 Array 中的資料一個一個渲染出來:
<div
v-for="(value, index) in arr"
:key="index"
class="bar-chart__bar"
>
<span>{{ value }}</span>
<span>[{{ index }}]</span>
</div>
但這時候還不算長條圖,只是單純把每一個數字都渲染出來而已。
一開始想到長條圖,我以為需要先建立 X、Y 軸,再根據 Y 軸的刻度計算每個數字應該出現在哪個高度。
但後來發現,我現在做的並不是需要精確刻度的統計圖表,而是演算法視覺化。我的目的只是讓使用者可以直觀看出數值彼此的大小,以及之後排序時資料位置的變化,因此不一定需要建立完整的 X、Y 軸。
所以我用了更簡單的方式:把 Array 中最大的數字當成畫面高度的 100%,其他數字再按照比例縮放。
長條高度 = 目前數值 ÷ 最大值 × 100%
例如 [5, 3, 8, 1] 最大值是 8,那 8 就是 100%,5 則是 62.5%。
const maxValue = computed(() =>
arr.value.length ? Math.max(...arr.value) : 0
)
function getBarHeight(value: number) {
if (maxValue.value === 0) return '0%'
return `${(value / maxValue.value) * 100}%`
}
再透過 Vue 的動態 :style:
<div
v-for="(value, index) in arr"
:key="index"
:style="{ height: getBarHeight(value) }"
>
{{ value }}
</div>
這樣不需要額外建立 Y 軸刻度,也可以把 Array 中數值的大小轉換成不同高度的長條圖。
接著我不希望每次都固定使用 [5, 3, 8, 1],所以加入隨機產生資料的功能:
const randomArray = (length: number, min: number, max: number) => {
return Array.from(
{ length },
() => Math.floor(Math.random() * (max - min + 1)) + min
)
}
這裡我原本最不理解的是:
Math.floor(Math.random() * (max - min + 1)) + min
假設我要產生 5~10,總共有:
5、6、7、8、9、10
也就是 6 種可能。
所以:
max - min + 1
// 10 - 5 + 1 = 6
Math.floor(Math.random() * 6) 會得到:
0、1、2、3、4、5
但我要的是 5~10,因此最後再 + min:
0 + 5 = 5
1 + 5 = 6
...
5 + 5 = 10
所以我把它理解成:
max - min + 1決定有幾種可能,+ min則是把數字移動到指定的起始範圍。
至於 Array.from({ length }) 中的 { length },其實就是 { length: length } 的縮寫,用來決定這次要產生幾個元素。
今天終於把原本只是程式裡的 Array,轉換成畫面上看得見的長條圖,也加入了隨機產生資料的功能。
這次實作讓我更具體感受到:
演算法負責改變資料,而 Vue 負責把資料的變化呈現在畫面上。



下一章就是讓 Bubble Sort 可以開始有動畫排序囉。