Chart.js是一款open source的图表制作library,支援多种图表,包括Pie chart、Bar chart、line chart...等等,也有动画效果,可以制作出精美的报表。
今天我们要建立一个Blazor WebAssembly专案,这个专案会串接一个新冠肺炎的Api,并使用Chart.js呈现近60天的确诊人数折线图,那我们就开始吧!
接下来主要分3部分进行:
Api部份,我们可以用https://covid19api.com/ 这个网站的Api来取得资料,一般资料是free的,如果有更多资料的需求再订阅付费,我们可以到他的文件看一下有哪些Api可用。
首先建立Blazor WebAssembly专案,取消勾选Asp.net core hosted
建立完专案後,新增Service和Model资料夹,Model中加入json要对应的类别,Service资料夹加入COVID19Service。
COVID19Service有两个方法:
GetCountriesAsync:取得index.razor的国家下拉选单资料
GetCountrySummaryAsync:传入CountryCode,取得某国的确诊、死亡等等人数
public class COVID19Service : ICOVID19Service
{
private readonly HttpClient httpClient;
private string baseurl { get; set; } = "https://api.covid19api.com";
public COVID19Service(HttpClient httpClient)
{
this.httpClient = httpClient;
}
/// <summary>
/// 取得国家清单
/// </summary>
/// <returns></returns>
public async Task<List<CountryModel>> GetCountriesAsync()
{
List<CountryModel> countries = new List<CountryModel>();
var response = await httpClient.GetAsync($"{baseurl}/countries");
if (response.IsSuccessStatusCode)
{
var contentString = await response.Content.ReadAsStringAsync();
countries = JsonConvert.DeserializeObject<List<CountryModel>>(contentString);
}
return countries;
}
/// <summary>
/// 取得确诊、死亡等等人数资料
/// </summary>
/// <param name="countryCode"></param>
/// <returns></returns>
public async Task<List<CountrySummary>> GetCountrySummaryAsync(string countryCode)
{
List<CountrySummary> countrySummary = new List<CountrySummary>();
var respones = await httpClient.GetAsync($"{baseurl}/country/{countryCode}");
if (respones.IsSuccessStatusCode)
{
var contentString = await respones.Content.ReadAsStringAsync();
countrySummary = JsonConvert.DeserializeObject<List<CountrySummary>>(contentString);
}
return countrySummary.TakeLast(60).ToList();
}
}
在Program.cs注册COVID19Service
builder.Services.AddScoped<ICOVID19Service, COVID19Service>();
使用cdn引入chart.js。可从https://cdnjs.com/libraries/Chart.js 取得cdn连结
再来把cdn script拉进wwwroot/index.html
<!DOCTYPE html>
<html>
//略....
<body>
<app>Loading...</app>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">?</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js"></script>
<script src="script/MyChart.js"></script>
</body>
</html>
另外还拉了一个MyChart.js进去,这是我们自己建立的js档,待会会在里面写产生图表的程序码
接下来到index.razor,这边增加一个canvas标签,产生的图表会放到这个canvas内
<canvas id="myChart" width="800" height="300"></canvas>
在MyChart.js建立图表资料
function DrawLineChart(summaryListlist) {
//建立图表资料
var datachart = {
labels: [],
datasets: [{
label: '确诊人数',
data: [],
borderColor: '#FF5376',
fill: false
}]
};
//将日期与人数push到labels和data阵列中
for (var i = 0; i < summaryListlist.length; i++) {
datachart.labels.push(summaryListlist[i].shortDate);
datachart.datasets[0].data.push(summaryListlist[i].confirmed);
}
//绘制图表
var ctx = document.getElementById("myChart").getContext("2d");
var chart = new Chart(ctx, {
type: 'line', //图表类型
data: datachart,
})
}
chart.js的官方文件还有许多设定可以套用,让我们的图表可以更美观更友善
在画面上会准备一个国家的下拉选单给user选取要看哪一国的资料,所以下拉选单部分会透过上述建立的COVID19Service取的国家资料後在塞到Select标签中
@page "/"
@inject ICOVID19Service COVID19Service
<h2>COVID19 Chart</h2>
<hr />
@if (countries != null)
{
<div class="form-group">
<label for="countrySelect" class="font-weight-bold">国家</label>
<select @onchange="ChangeCountryAsync" class="form-control" id="countrySelect">
<option>--请选择--</option>
@foreach (var item in countries)
{
<option value="@item.Slug" selected="@(item.Slug == DefaultCountry)">@item.Country</option>
}
</select>
</div>
//显示chart的canvas标签
<canvas id="myChart" width="800" height="300"></canvas>
}
else
{
//还在读取资料时,显示loading gif
<img src="https://media.giphy.com/media/3oEjI6SIIHBdRxXI40/giphy.gif" />
}
@code{
public string DefaultCountry { get; set; } = "taiwan";
public List<CountryModel> countries;
protected override async Task OnInitializedAsync()
{
countries = await COVID19Service.GetCountriesAsync();
}
}
在一进入index.razor,我希望显示的是台湾的确诊资料,因此在OnInitializedAsync方法取得下拉选单然後用一个预设为taiwan的DefaultCountry属性,让下拉选单预设选到taiwan
传入countryCode取确诊资料并透过IJSRuntime物件绘制图表
@inject IJSRuntime js
@code{
private async Task BuildChartAsync(string selectedValue)
{
summaryList = await COVID19Service.GetCountrySummaryAsync(selectedValue);
summaryList.ForEach(x => x.ShortDate = $"{x.Date.Month}/{x.Date.Day}");
await js.InvokeVoidAsync("DrawLineChart", summaryList);
}
}
在OnInitializedAsync也加入BuildChartAsync
protected override async Task OnInitializedAsync()
{
countries = await COVID19Service.GetCountriesAsync();
BuildChartAsync(DefaultCountry);
}
选取国家时,处理onchange事件的ChangeCountryAsync方法中,使用ChangeEventArgs参数取得选择的value,在传入刚刚建立的BuildChartAsync方法
public async Task ChangeCountryAsync(ChangeEventArgs e)
{
if (e.Value != null)
{
await BuildChartAsync(e.Value.ToString());
}
}
最後完成的结果
程序码可参考:https://github.com/CircleLin/COVID19_Chart
Git Git 是一个开源的分布式版本控制系统, 允许我们跟踪档案异动, 最初目的是为更好地管理 L...
基於讯息传递的一致性协定,只能保证资料的「最终一致性」,都无法处理「拜占庭将军问题(Byzantin...
在这边先声明,这篇是是WWDC大会的部分翻译,我找到的也是别人翻译以及笔记的 文章,只是我觉得很适合...
第七天 各位点进来的朋友,你们好阿 小的不才只能做这个系列的文章,但还是希望分享给点进来的朋友,知道...
子曰:『工欲善其事,必先利其器。 前言 昨天提到依照 Ground truth 改变的速度会让不同...