【圖解鴻蒙】使用繪圖組件Canvas繪製心率曲線圖

一、運行效果

    在頁面中顯示頁面標題、心率曲線圖、心率最大值及其圖標、心率最小值及其圖標、心率在每分鐘內的平均次數。如下圖所示:

二、實現思路

    在頁面的生命週期事件函數onInit()中,隨機生成若干個指定範圍內的整數,以作爲所有的心率數據。根據隨機生成的整數統計所有心率的最大值、最小值和平均值,並通過動態綁定的方式將其顯示在頁面中。使用組件chart繪製心率曲線圖。通過動態綁定的方式指定組件chart中屬性options和datasets的值,以對圖形的參數進行設置。

三、代碼詳解

    打開文件index.hml。
    將組件text中顯示的頁面標題修改爲:心率曲線,並在其外層嵌套一個組件div,以便對其樣式進行設置。將該組件div的屬性class的值設置爲"title-container"。
    在頁面標題的下方添加一個組件div以顯示心率曲線圖,並將屬性class的值設置爲"chart"。
    在心率曲線圖的下方添加一個組件list,以顯示心率的最大值、最小值及其圖標,並將屬性class的值設置爲"list"。
    在組件list的內部嵌套一個組件list-item以顯示列表中的每個列表項,並將屬性class的值設置爲"list-item"。通過動態綁定的方式指定屬性for的值爲"{{maxmin}}",從而對index.js中data裏面的maxmin進行迭代。
    每個列表項都由一張圖片和一個文本組成,因此在組件list-item中添加一個組件image和一個組件text。
    在組件image中將屬性class的值設置爲"icon",並通過動態綁定的方式將屬性src的值設置爲"/common/{{$item.iconName}}.png"。這樣,report2.js中data裏面的maxmin可以是一個字典的數組,數組中的每個字典都包含一個key爲iconName的元素。
    在組件text中將屬性class的值設置爲"maxmin",並通過動態綁定的方式將顯示的文本設置爲"{{$item.mValue}}"。這樣,對於index.js中data裏面的數組maxmin,其中的每個字典都包含一個key爲mValue的元素。
    在列表的下方添加一個組件div以顯示心率在一分鐘內的平均次數,並將屬性class的值設置爲" average-container "。
    在組件div中嵌套定義三個組件text,其屬性class的值分別爲:"average"、"average-number"和"average",其顯示的文本分別爲:平均、{{average}}、次/分。
    上述講解請見如下代碼:









<div class="container" onswipe="toNextPage">
    <div class="title-container">
        <text class="title">
            心率曲線
        </text>
    </div>
    <div class="chart">

    </div>
    <list class="list">
        <list-item class="list-item" for="{{maxmin}}">
            <image class="icon" src="/common/{{$item.iconName}}.png"/>
            <text class="maxmin">
                {{$item.mValue}}
            </text>
        </list-item>
    </list>
    <div class="average-container">
        <text class="average">
            平均
        </text>
        <text class="average-number">
            {{average}}
        </text>
        <text class="average">
            次/分
        </text>
    </div>
</div>

    打開文件index.css。
    在類選擇器container中刪除樣式display、left和top。將flex-direction的值設置爲column,以在豎直方向上排列容器內的所有組件。將justify-content的值修改爲flex-start,以讓容器內的所有組件在主軸上向上對齊。
    在類選擇器title中刪除樣式text-align、width和height。將font-size的值修改爲38px。將margin-top的值設置爲40px,以讓頁面標題與頁面的上邊緣保持一定的間距。
    添加一個名爲title-container的類選擇器,以設置頁面標題的樣式。將justify-content和align-items都設置爲center,以讓容器內的組件在水平方向和豎直方向都居中對齊。將寬度width和高度height的值分別設置爲300px和130px。
    添加一個名爲chart的類選擇器,以設置心率曲線圖的樣式。將寬度width和高度height的值分別設置爲400px和180px。
    添加一個名爲list的類選擇器,以設置列表的樣式。將flex-direction的值設置爲row,以在水平方向上排列所有列表項。將寬度width和高度height的值分別設置爲240px和45px。
    添加一個名爲list-item的類選擇器,以設置列表項的樣式。將justify-content和align-items都設置爲center,以讓列表項內的組件在水平方向和豎直方向都居中對齊。將寬度width和高度height的值分別設置爲120px和45px。
    添加一個名爲icon的類選擇器,以設置心率的最大值圖標和最小值圖標的樣式。將寬度width和高度height的值分別設置爲32px和32px。
    添加一個名爲maxmin的類選擇器,以設置心率的最大值文本和最小值文本的樣式。將font-size的值設置爲24px。將letter-spacing的值設置爲0px,以讓數字之間的間距更緊湊。
    添加一個名爲average-container的類選擇器,以設置心率平均值的相關文本的樣式。將justify-content的值設置爲space-between,以讓容器內的組件在水平方向上兩端對齊。將align-items的值設置爲center,以讓容器內的組件在豎直方向上居中對齊。將寬度width和高度height的值分別設置爲280px和55px。
    添加一個名爲average-number的類選擇器,以設置心率平均值的樣式。將font-size的值設置爲38px。將letter-spacing的值設置爲0px,以讓數字之間的間距更緊湊。
    添加一個名爲average的類選擇器,以設置心率平均值的兩邊文本的樣式。將font-size的值設置爲24px。將color的值設置爲gray,以將文本顯示爲灰色。










    上述講解請見如下代碼:

.container {
       display: flex;
	flex-direction: column;
	justify-content: flex-start;
	align-items: center;
	left: 0px;
	top: 0px;
	width: 454px;
	height: 454px;
}
.title-container {
	justify-content: center;
	align-items: center;
	width: 300px;
	height: 130px;
}
.title {
	margin-top: 40px;
	font-size: 38px;
	text-align: center;
	width: 454px;
	height: 100px;
}
.chart {
	width: 400px;
	height: 180px;
}
.list {
	flex-direction: row;
	width: 240px;
	height: 45px;
}
.list-item {
	justify-content: center;
	align-items: center;
	width: 120px;
	height: 45px;
}
.icon {
	width: 32px;
	height: 32px;
}
.maxmin {
	font-size: 24px;
	letter-spacing: 0px;
}
.average-container {
	justify-content: space-between;
	align-items: center;
	width: 280px;
	height: 55px;
}
.average {
	font-size: 24px;
	color: gray;
}
.average-number {
	font-size: 38px;
	letter-spacing: 0px;
}

    把心率最大值圖標max.png和心率最小值圖標min.png添加到目錄common中。
    打開文件index.js。
    在data中將佔位符maxmin初始化爲一個字典數組。該數組中包含兩個字典,分別表示心率最大值和心率最小值的相關信息。每個字典中都有兩個元素,對應的key都是iconName和mValue,分別表示心率最值的圖標名稱和心率最值。對於第一個字典,將心率最大值的圖標名稱iconName初始化爲'max',並將心率最大值初始化爲0。對於第二個字典,將心率最小值的圖標名稱iconName初始化爲'min',並將心率最小值初始化爲0。
    在data中將佔位符average初始化爲0。
    上述講解請見如下代碼:



import router from '@system.router'

export default {
	data: {
		maxmin: [{
			         iconName: 'max',
			         mValue: 0
		         },
		         {
			         iconName: 'min',
			         mValue: 0
		         }],
		average: 0
	}
}

    在index.js中自定義一個名爲getRandomInt的函數,該函數用於隨機生成一個介於min和max之間(包含min和max)的整數。
    在頁面的生命週期事件函數onInit()裏,首先創建一個空數組並賦值給局部作用域變量heartRates,然後通過for循環執行100次迭代。在每一次迭代中,調用自定義函數getRandomInt()隨機生成一個介於73和159之間的整數,並調用函數push()將隨機生成的整數添加到數組heartRates中。
    定義一個名爲countMaxMinAverage的函數,其形參爲heartRates,該函數用於計算heartRates中所有元素的最大值、最小值和平均值。
    在函數onInit()的最後,調用自定義函數countMaxMinAverage (),並將heartRates作爲實參傳遞給形參heartRates。
    上述講解請見如下代碼:



import router from '@system.router'

export default {
	data: {
            ......
	},
	onInit() {
		let heartRates = [];
		for (let i = 0; i < 100; i++) {
			heartRates.push(this.getRandomInt(73, 159));
		}
		this.countMaxMinAverage(heartRates);
	},
	getRandomInt(min, max) {
		return Math.floor(Math.random() * (max - min + 1) ) + min;
	},
	countMaxMinAverage(heartRates) {

	}
}

    在自定義函數countMaxMinAverage ()的函數體中,分別調用Math.max.apply()和Math.min.apply()計算數組heartRates中的最大值和最小值,然後分別賦值給data中的maxmin[0].mValue和maxmin[1].mValue。通過for循環對數組heartRates中的所有心率數據進行遍歷,在遍歷的過程中將心率數據累加到局部作用域變量sum,以計算數組heartRates中所有心率數據的總和。求出總和之後,將其除以所有心率數據的個數就得到了所有心率數據的平均值。調用函數Math.round()返回與心率平均值最接近的整數,並將其賦值給data中的average。
    上述講解請見如下代碼:

import router from '@system.router'

export default {
        ......
	countMaxMinAverage(heartRates) {
		this.maxmin[0].mValue = Math.max.apply(null, heartRates);
		this.maxmin[1].mValue = Math.min.apply(null, heartRates);

		let sum = 0;
		for (let index = 0; index < heartRates.length; index++) {
			sum += heartRates[index];
		}
		this.average = Math.round(sum / heartRates.length);
	},
        ......
}

    保存所有代碼後打開模擬器,在頁面中顯示出了頁面標題、心率最大值及其圖標、心率最小值及其圖標、心率在每分鐘內的平均次數,運行效果如圖所示:

    打開文件index.hml。
    將組件list上方的組件div修改爲chart,以繪製一張心率曲線圖。在組件chart中,通過動態綁定的方式將屬性options和datasets的值分別設置爲"{{options}}"和"{{datasets}}"。
    上述講解請見如下代碼:

<div class="container" onswipe="toNextPage">
    <div class="title-container">
        <text class="title">
            心率曲線
        </text>
    </div>
    <chart class="chart" options="{{options}}" datasets="{{datasets}}"/>
    <list class="list">
        ......    
    </list>
    ......
</div>

     打開文件index.js。
    在data中將佔位符options的值初始化爲一個字典,字典中包含兩個元素,分別用於設置x軸和y軸的參數。第一個元素的key是xAxis,對應的value是一個空字典{},說明不需要對x軸的參數進行設置。第二個元素的key是yAxis,對應的value是一個由兩個元素組成的字典,分別用於設置y軸的最小值和最大值,其中,key分別是min和max,value分別是0和160。
    在data中將佔位符datasets的值初始化爲一個字典的數組,該數組中只包含一個字典,該字典中包含兩個元素。第一個元素的key是gradient,對應的value是true,用於表示折線向下填充顏色到x軸。第二個元素的key是data,對應的value是一個空數組[],用於指定心率圖中的數據。
    在頁面的生命週期事件函數onInit()中,在隨機生成100個整數之後將所有整數組成的數組賦值給data中的datasets[0].data。
    上述講解請見如下代碼:



import router from '@system.router'

export default {
	data: {
		......		
                average: 0,
		options: {
			xAxis: {},
			yAxis: {
				min: 0,
				max: 160
			}
		},
		datasets: [{
			           gradient: true,
			           data: []
		           }]
	},
	onInit() {
		let heartRates = [];
		for (let i = 0; i < 100; i++) {
			heartRates.push(this.getRandomInt(73, 159));
		}
		this.datasets[0].data = heartRates;
		this.countMaxMinAverage(heartRates);
	},
	......
}

    保存所有代碼後打開模擬器,運行效果如下圖所示:

項目源代碼,請見附件。

 

歡迎訂閱我的專欄【圖解鴻蒙】:

https://harmonyos.51cto.com/column/27


文章相關附件可以點擊下面的原文鏈接前往學習
原文鏈接:https://harmonyos.51cto.com/posts/2265#bkwz


想了解更多關於鴻蒙的內容,請訪問:

51CTO和華爲官方戰略合作共建的鴻蒙技術社區

https://harmonyos.51cto.com/#bkwz


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章