Vue.js
ItIron2020
昨天我們完成了專案的基本建置並建立一個簡單的chart做為暖身練習,今天我們要接續chart的實作,從資料處理一直到呈現圖表,過程其實相當的簡單,甚至稱不上與vue有太大的關係XD 放輕鬆跟我來吧~! gogogo~!
從昨天的LineChart示範我們知道要建立圖表必須將資料以陣列的方式傳進去,每個圖表都需要
兩個陣列陣列幫忙,我們最終需要產出六個圖表,由於日期會是共用的,所以最終我們需要六個變數儲存六組陣列,分別是
arrPositive: [],
arrHoptialized: [],
arrInIcu: [],
arrOnVentilators: [],
arrRecovered: [],
arrDeaths: []
我們首先要做的就是迭代我們利用axios拿到的資料,將我們所需的資料推進對應的陣列中! 在App.vue中,請你先引入dayjs
import dayjs from 'dayjs'
接著將data的部分新增以下的屬性
data() {
return {
arrPositive: [],
arrHoptialized: [],
arrInIcu: [],
arrOnVentilators: [],
arrRecovered: [],
arrDeaths: [],
}
}
並修改created的部分
async created() {
// 利用解構的方式取出axios拿到的data
let { data } = await axios.get(
'https://api.covidtracking.com/v1/us/daily.json'
)
// 只取最近一個月的資料
data = data.slice(0, 30)
// 迭代陣列中的每個元素
data.forEach((item) => {
// 利用dayjs將原本的20201010改為2020/10/10
const date = dayjs(`${item.date}`).format('YYYY/MM/DD')
// 利用解構的方式取出data內我們需要的值
const {
positive,
hospitalizedCurrently,
inIcuCurrently,
recovered,
onVentilatorCurrently,
death,
} = item
// 將值推進對應的陣列,每一個值都需要對應一個日期,所以要以物件的方式傳入
this.arrPositive.push({ date, total: positive })
this.arrHoptialized.push({ date, total: hospitalizedCurrently })
this.arrDeaths.push({ date, total: death })
this.arrRecovered.push({ date, total: recovered })
this.arrOnVentilators.push({ date, total: onVentilatorCurrently })
this.arrInIcu.push({ date, total: inIcuCurrently })
})
},
打開我們的vue-devtool檢查一下取得的資料,很好! 一切都如同我們所想
現在我們已經有可用的資料了,馬上就先來打造確診人數的圖表吧! 我們需要在App.vue將我們整理好的資料傳入LineChart組件,因此我們要先回到LineChart組件做一些props的設定,我們要傳入的屬性有
請你將LineChart的內容改為以下
<script>
import { Line } from 'vue-chartjs'
export default {
extends: Line,
// 加入基本的資料驗證
props: {
label: {
type: String,
},
chartData: {
type: Array,
},
options: {
type: Object,
},
chartColorOptions: {
type: Object,
},
},
mounted() {
// 從傳入的資料中取出數字與日期,並將其反轉(因為我們拿到的是最新到最舊的資料)
const dates = this.chartData.map((d) => d.date).reverse()
const totals = this.chartData.map((d) => d.total).reverse()
this.renderChart(
{
labels: dates,
datasets: [
{
label: this.label,
data: totals,
...this.chartColorOptions
},
],
},
this.options
)
},
}
</script>
處理完後我們回到App.vue,我們先在data內加入圖表選項,我們希望圖表響應式、根據畫面變化大小,更多的設定你一樣可以在官方文件中找到!
data() {
return {
arrPositive: [],
arrHoptialized: [],
arrInIcu: [],
arrOnVentilators: [],
arrRecovered: [],
arrDeaths: [],
chartOptions: { // 新增這裡
responsive: true,
maintainAspectRatio: false,
},
}
},
接著我們改寫一下我們的template,主要有著以下的改動
有關於vuetify的組件使用,都可以在官方文件上找到對應的說明,我這邊就不贅述囉!
<template>
<v-app>
<v-main>
<v-container>
<v-card>
<v-container>
<h1>COVID-19 Tracking Dashboard</h1>
<v-row v-if="arrPositive.length">
<v-col cols="12">
<LineChart
label="Positive"
:chartData="arrPositive"
:options="chartOptions"
:chartColorOptions="{
borderColor: '#EF5350',
backgroundColor: 'rgba(255, 56, 96, 0.1)',
}"
/>
</v-col>
</v-row>
</v-container>
</v-card>
</v-container>
</v-main>
</v-app>
</template>
順利的話你就會看到以下的畫面,我們真的弄好第一個圖表囉!
其他的圖表你自然可以如法炮製,直接複製6組一模一樣的程式碼,再修改傳入的資料即可
<v-row v-if="arrPositive.length">
<v-col cols="12">
<h2>{{ chartData.label }}</h2>
<LineChart
:chartData="chartData.data"
:options="chartOptions"
:label="chartData.label"
:chartColorOptions="chartData.chartColorOptions"
/>
</v-col>
</v-row>
這樣的東西複製貼上六次也是可以的!
不過做為一個文明人,DRY(don't repeat yourself)是個我們崇尚的基本原則! 當然要想想更好的方式來處理! 我們需要將所有要印出的資料整理成一個陣列,這個陣列會包含
這樣最後我們只要透過一個v-for就能印出所有圖表囉!
請你在computed的部分增加一個renderData的屬性,並寫入以下的內容,對照著註解看我想會比較清楚我在幹什麼~!
computed: {
renderData() {
// 利用解構的方式從this中取出我們要用到的所有陣列
const {
arrPositive,
arrHoptialized,
arrInIcu,
arrOnVentilators,
arrRecovered,
arrDeaths,
} = this
// 建立所有的labels
const labels = [
'Positive',
'Hoptialized',
'InIcu',
'OnVentilators',
'Recovered',
'Deaths',
]
// 將所有要輸出的陣列整理為一個,做為最終迭代的對象
const displayedDataArr = [
arrPositive,
arrHoptialized,
arrInIcu,
arrOnVentilators,
arrRecovered,
arrDeaths,
]
// 設置每個圖表的背景與邊界顏色
const chartColorOptions = [
{
borderColor: '#EF5350',
backgroundColor: 'rgba(255, 56, 96, 0.1)',
},
{
borderColor: '#FFF176',
backgroundColor: 'rgba(191, 182, 63, 0.1)',
},
{
borderColor: '#FFB74D',
backgroundColor: 'rgba(239, 109, 9, 0.1)',
},
{
borderColor: '#B3E5FC',
backgroundColor: 'rgba(9, 140, 239, 0.1)',
},
{
borderColor: '#00E676',
backgroundColor: 'rgba(11, 227, 47, 0.1)',
},
{
borderColor: '#E30B86',
backgroundColor: 'rgba(239, 9, 140, 0.1)',
},
]
// 最終整理成一個陣列,每一個元素都包含標籤名稱、資料以及圖表顏色的設定
return displayedDataArr.map((data, index) => ({
label: labels[index],
data,
chartColorOptions: chartColorOptions[index],
}))
},
},
資料處理好後我們回到template的地方,做出以下的修改
<template>
<v-app>
<v-main>
<v-container>
<v-card>
<v-container>
<h1>COVID-19 Tracking Dashboard</h1>
<v-row v-if="arrPositive.length"> // 修改以下的部分
<v-col
cols="12"
v-for="chartData in renderData"
:key="chartData.id"
>
<LineChart
:label="chartData.label"
:chartData="chartData.data"
:options="chartOptions"
:chartColorOptions="chartData.chartColorOptions"
/>
</v-col>
</v-row>
</v-container>
</v-card>
</v-container>
</v-main>
</v-app>
</template>
很好! 畫面如我們預期的一樣,有著6個不同顏色、內容的圖表囉!
今天我們成功的整理了利用axios取得的資料,並透過props傳遞給子層的LineChart讓它能正確顯示我們要的資料,最後則藉由新建立一個computed屬性進行v-for迭代,避免我們做重複的複製貼上~! 內容稍微多了一點,其中有些邏輯要配合註解去觀看會比較好懂! 基本上我們的應用程式已經有著該有的功能,明天我們只要做最後的一點點優化就可以上架囉! 那就明天見吧!
此文章同步發布於個人部落格,有興趣的大大也可以來參觀一下:D