
Chart 图表
通过给定数据,绘画各种图表的组件
本组件依赖于 BootstrapBlazor.Chart
,使用本组件时需要引用其组件包
Nuget 包安装
使用 nuget.org 进行 BootstrapBlazor.Chart
组件的安装
.NET CLI
dotnet add package BootstrapBlazor.Chart --version 5.0.7
PackageReference
<PackageReference Include="BootstrapBlazor.Chart" Version="5.0.7" />
Package Manager
Install-Package BootstrapBlazor.Chart -Version 5.0.7
CSS 文件
<link rel="stylesheet" href="_content/BootstrapBlazor.Chart/css/bootstrap.blazor.chart.bundle.min.css" />
JS 文件
<script src="_content/BootstrapBlazor.Chart/js/bootstrap.blazor.chart.bundle.min.js"></script>
组件数据在 OnInit
回调委托中进行设置即可
Line 图
使用 OnInit
回调委托方法,对初始化数据进行赋值后,即可进行绘图操作
Demo
Loading ...
Bar 图
通过设置 ChartType
更改图表为 bar
图
Demo
Loading ...
Pie 图
通过设置 ChartType
更改图表为 pie
图
Demo
Loading ...
Doughnut 图
通过设置 ChartType
更改图表为 doughnut
图
Demo
Loading ...
Bubble 图
通过设置 ChartType
更改图表为 bubble
图
Demo
Loading ...
Attributes
Loading...
事件 Events
Loading...
@page "/charts"
@using Microsoft.Extensions.DependencyInjection
@implements IDisposable
@inherits ComponentBase
@inject NugetVersionService VersionManager
<h3>Chart 图表</h3>
<h4>通过给定数据,绘画各种图表的组件</h4>
<p>本组件依赖于 <a href="https://www.nuget.org/packages?q=BootstrapBlazor.Chart" target="_blank"><code>BootstrapBlazor.Chart</code></a>,使用本组件时需要引用其组件包</p>
<p><b>Nuget 包安装</b></p>
<p>使用 <a href="https://www.nuget.org/packages?q=BootstrapBlazor.Chart" target="_blank">nuget.org</a> 进行 <code>BootstrapBlazor.Chart</code> 组件的安装</p>
<div class="code-label">.NET CLI</div>
<Pre class="no-highlight">dotnet add package BootstrapBlazor.Chart --version @Version</Pre>
<div class="code-label">PackageReference</div>
<Pre class="no-highlight"><PackageReference Include="BootstrapBlazor.Chart" Version="@Version" /></Pre>
<div class="code-label">Package Manager</div>
<Pre class="no-highlight">Install-Package BootstrapBlazor.Chart -Version @Version</Pre>
<h4>CSS 文件</h4>
<Pre><link rel="stylesheet" href="_content/BootstrapBlazor.Chart/css/bootstrap.blazor.chart.bundle.min.css" /></Pre>
<h4>JS 文件</h4>
<Pre><script src="_content/BootstrapBlazor.Chart/js/bootstrap.blazor.chart.bundle.min.js"></script></Pre>
<p>组件数据在 <code>OnInit</code> 回调委托中进行设置即可</p>
<Block Title="Line 图" Introduction="使用 <code>OnInit</code> 回调委托方法,对初始化数据进行赋值后,即可进行绘图操作">
<Chart OnInit="@(() => OnInit(LineDatasetCount, LineDataCount))" @ref="LineChart" />
<div class="text-center mt-2 chart">
<div class="btn-group">
<button class="btn btn-primary" @onclick="e => RandomData(LineChart)"><i class="fa fa-line-chart"></i><span>随机数据</span></button>
<button class="btn btn-primary" @onclick="e => AddDataSet(LineChart, ref LineDatasetCount)"><i class="fa fa-plus-circle"></i><span>添加数据集</span></button>
<button class="btn btn-primary" @onclick="e => RemoveDataSet(LineChart, ref LineDatasetCount)"><i class="fa fa-minus-circle"></i><span>移除数据集</span></button>
<button class="btn btn-primary" @onclick="e => AddData(LineChart, ref LineDataCount)"><i class="fa fa-plus"></i><span>添加数据</span></button>
<button class="btn btn-primary" @onclick="e => RemoveData(LineChart, ref LineDataCount)"><i class="fa fa-minus"></i><span>移除数据</span></button>
</div>
</div>
</Block>
<Block Title="Bar 图" Introduction="通过设置 <code>ChartType</code> 更改图表为 <code>bar</code> 图">
<Chart ChartType="ChartType.Bar" OnInit="@(() => OnInit(BarDatasetCount, BarDataCount))" @ref="BarChart" />
<div class="text-center mt-2 chart">
<div class="btn-group">
<button class="btn btn-info" data-method="play" @onclick="@OnPlayChart">
<i class="fa fa-play-circle"></i>
<span>开启动画</span>
</button>
<button class="btn btn-info" data-method="stop" @onclick="@OnStopChart">
<i class="fa fa-stop-circle"></i>
<span>关闭动画</span>
</button>
</div>
</div>
<div class="text-center mt-2 chart">
<div class="btn-group">
<button class="btn btn-primary" @onclick="e => RandomData(BarChart)"><i class="fa fa-bar-chart"></i><span>随机数据</span></button>
<button class="btn btn-primary" @onclick="e => AddDataSet(BarChart, ref BarDatasetCount)"><i class="fa fa-plus-circle"></i><span>添加数据集</span></button>
<button class="btn btn-primary" @onclick="e => RemoveDataSet(BarChart, ref BarDatasetCount)"><i class="fa fa-minus-circle"></i><span>移除数据集</span></button>
<button class="btn btn-primary" @onclick="e => AddData(BarChart, ref BarDataCount)"><i class="fa fa-plus"></i><span>添加数据</span></button>
<button class="btn btn-primary" @onclick="e => RemoveData(BarChart, ref BarDataCount)"><i class="fa fa-minus"></i><span>移除数据</span></button>
</div>
</div>
</Block>
<Block Title="Pie 图" Introduction="通过设置 <code>ChartType</code> 更改图表为 <code>pie</code> 图">
<Chart ChartType="ChartType.Pie" OnInit="@(() => OnPieInit(PieDatasetCount, PieDataCount))" @ref="PieChart" />
<div class="text-center mt-2 chart">
<div class="btn-group">
<button class="btn btn-primary" @onclick="e => RandomData(PieChart)"><i class="fa fa-pie-chart"></i><span>随机数据</span></button>
<button class="btn btn-primary" @onclick="e => AddDataSet(PieChart, ref PieDatasetCount)"><i class="fa fa-plus-circle"></i><span>添加数据集</span></button>
<button class="btn btn-primary" @onclick="e => RemoveDataSet(PieChart, ref PieDatasetCount)"><i class="fa fa-minus-circle"></i><span>移除数据集</span></button>
<button class="btn btn-primary" @onclick="e => AddData(PieChart, ref PieDataCount)"><i class="fa fa-plus"></i><span>添加数据</span></button>
<button class="btn btn-primary" @onclick="e => RemoveData(PieChart, ref PieDataCount)"><i class="fa fa-minus"></i><span>移除数据</span></button>
</div>
</div>
</Block>
<Block Title="Doughnut 图" Introduction="通过设置 <code>ChartType</code> 更改图表为 <code>doughnut</code> 图">
<Chart ChartType="ChartType.Doughnut" OnInit="@(() => OnPieInit(DoughnutDatasetCount, DoughnutDataCount))" @ref="DoughnutChart" />
<div class="text-center mt-2 chart">
<div class="btn-group">
<button class="btn btn-primary" @onclick="e => RandomData(DoughnutChart)"><i class="fa fa-slack"></i><span>随机数据</span></button>
<button class="btn btn-primary" @onclick="e => AddDataSet(DoughnutChart, ref DoughnutDatasetCount)"><i class="fa fa-plus-circle"></i><span>添加数据集</span></button>
<button class="btn btn-primary" @onclick="e => RemoveDataSet(DoughnutChart, ref DoughnutDatasetCount)"><i class="fa fa-minus-circle"></i><span>移除数据集</span></button>
<button class="btn btn-primary" @onclick="e => AddData(DoughnutChart, ref DoughnutDataCount)"><i class="fa fa-plus"></i><span>添加数据</span></button>
<button class="btn btn-primary" @onclick="e => RemoveData(DoughnutChart, ref DoughnutDataCount)"><i class="fa fa-minus"></i><span>移除数据</span></button>
<button class="btn btn-primary" @onclick="@ToggleCircle"><i class="fa fa-circle-o-notch"></i><span>半圆/全圆</span></button>
</div>
</div>
</Block>
<Block Title="Bubble 图" Introduction="通过设置 <code>ChartType</code> 更改图表为 <code>bubble</code> 图">
<Chart ChartType="ChartType.Bubble" OnInit="@(() => OnBubbleInit(BubbleDatasetCount, BubbleDataCount))" @ref="BubbleChart" />
<div class="text-center mt-2 chart">
<div class="btn-group">
<button class="btn btn-primary" @onclick="e => RandomData(BubbleChart)"><i class="fa fa-snowflake-o"></i><span>随机数据</span></button>
<button class="btn btn-primary" @onclick="e => AddDataSet(BubbleChart, ref BubbleDatasetCount)"><i class="fa fa-plus-circle"></i><span>添加数据集</span></button>
<button class="btn btn-primary" @onclick="e => RemoveDataSet(BubbleChart, ref BubbleDatasetCount)"><i class="fa fa-minus-circle"></i><span>移除数据集</span></button>
<button class="btn btn-primary" @onclick="e => AddData(BubbleChart, ref BubbleDataCount)"><i class="fa fa-plus"></i><span>添加数据</span></button>
<button class="btn btn-primary" @onclick="e => RemoveData(BubbleChart, ref BubbleDataCount)"><i class="fa fa-minus"></i><span>移除数据</span></button>
</div>
</div>
</Block>
<AttributeTable Items="@GetAttributes()" />
<EventTable Items="@GetEvents()" />
@code {
private int LineDatasetCount = 2;
private int BarDatasetCount = 2;
private int PieDatasetCount = 1;
private int DoughnutDatasetCount = 1;
private int BubbleDatasetCount = 2;
private int LineDataCount = 7;
private int BarDataCount = 7;
private int PieDataCount = 5;
private int DoughnutDataCount = 5;
private int BubbleDataCount = 7;
/// <summary>
/// 获得/设置 版本号字符串
/// </summary>
private string Version { get; set; } = "fetching";
/// <summary>
/// OnInitializedAsync 方法
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
Version = await VersionManager.GetVersionAsync("bootstrapblazor.chart");
}
}
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
// Website: https://www.blazor.zone or https://argozhang.github.io/
using BootstrapBlazor.Components;
using BootstrapBlazor.Shared.Common;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace BootstrapBlazor.Shared.Pages
{
/// <summary>
///
/// </summary>
public sealed partial class Charts
{
/// <summary>
///
/// </summary>
[Inject]
private ToastService? ToastService { get; set; }
[Inject]
private IJSRuntime? JSRuntime { get; set; }
private static Random Randomer { get; set; } = new Random();
private JSInterop<Charts>? Interope { get; set; }
private Chart? LineChart { get; set; }
private Chart? BarChart { get; set; }
private Chart? PieChart { get; set; }
private Chart? DoughnutChart { get; set; }
private Chart? BubbleChart { get; set; }
private bool IsCricle { get; set; }
private IEnumerable<string> Colors { get; set; } = new List<string>() { "Red", "Blue", "Green", "Orange", "Yellow", "Tomato", "Pink", "Violet" };
/// <summary>
///
/// </summary>
/// <param name="firstRender"></param>
protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);
if (firstRender && JSRuntime != null)
{
if (Interope == null) Interope = new JSInterop<Charts>(JSRuntime);
await Interope.Invoke(this, "", "_initChart", nameof(ShowToast));
}
}
private Task<ChartDataSource> OnInit(int dsCount, int daCount)
{
var ds = new ChartDataSource();
ds.Options.XAxes.Add(new ChartAxes() { LabelString = "天数" });
ds.Options.YAxes.Add(new ChartAxes() { LabelString = "数值" });
ds.Labels = Enumerable.Range(1, daCount).Select(i => i.ToString());
for (var index = 0; index < dsCount; index++)
{
ds.Data.Add(new ChartDataset()
{
Label = $"数据集 {index}",
Data = Enumerable.Range(1, daCount).Select(i => Randomer.Next(20, 37)).Cast<object>()
});
}
return Task.FromResult(ds);
}
private CancellationTokenSource _chartCancellationTokenSource = new CancellationTokenSource();
private Task OnPlayChart()
{
_chartCancellationTokenSource = new CancellationTokenSource();
return Task.Run(async () =>
{
while (!_chartCancellationTokenSource.IsCancellationRequested)
{
await Task.Delay(800, _chartCancellationTokenSource.Token);
if (!_chartCancellationTokenSource.IsCancellationRequested) RandomData(BarChart);
}
});
}
private void OnStopChart()
{
_chartCancellationTokenSource.Cancel();
}
private Task<ChartDataSource> OnPieInit(int dsCount, int daCount)
{
var ds = new ChartDataSource();
ds.Options.XAxes.Add(new ChartAxes() { LabelString = "天数" });
ds.Options.ShowXAxesLine = false;
ds.Options.YAxes.Add(new ChartAxes() { LabelString = "数值" });
ds.Options.ShowYAxesLine = false;
ds.Labels = Colors.Take(daCount);
for (var index = 0; index < dsCount; index++)
{
ds.Data.Add(new ChartDataset()
{
Label = $"数据集 {index}",
Data = Enumerable.Range(1, daCount).Select(i => Randomer.Next(20, 37)).Cast<object>()
});
}
return Task.FromResult(ds);
}
private Task<ChartDataSource> OnBubbleInit(int dsCount, int daCount)
{
var ds = new ChartDataSource
{
Labels = Enumerable.Range(1, daCount).Select(i => i.ToString())
};
for (var index = 0; index < dsCount; index++)
{
ds.Data.Add(new ChartDataset()
{
Label = $"数据集 {index}",
Data = Enumerable.Range(1, daCount).Select(i => new
{
x = Randomer.Next(10, 40),
y = Randomer.Next(10, 40),
r = Randomer.Next(1, 20)
})
});
}
return Task.FromResult(ds);
}
private void RandomData(Chart? chart)
{
chart?.Update();
}
private void AddDataSet(Chart? chart, ref int dsCount)
{
if (dsCount < Colors.Count())
{
dsCount++;
chart?.Update("addDataset");
}
}
private void RemoveDataSet(Chart? chart, ref int dsCount)
{
if (dsCount > 1)
{
dsCount--;
chart?.Update("removeDataset");
}
}
private void AddData(Chart? chart, ref int daCount)
{
var limit = (chart?.ChartType ?? ChartType.Line) switch
{
ChartType.Line => 14,
ChartType.Bar => 14,
ChartType.Bubble => 14,
_ => Colors.Count()
};
if (daCount < limit)
{
daCount++;
chart?.Update("addData");
}
}
private void RemoveData(Chart? chart, ref int daCount)
{
var limit = (chart?.ChartType ?? ChartType.Line) switch
{
ChartType.Line => 7,
ChartType.Bar => 7,
ChartType.Bubble => 4,
_ => 2
};
if (daCount > limit)
{
daCount--;
chart?.Update("removeData");
}
}
private void ToggleCircle()
{
IsCricle = !IsCricle;
DoughnutChart?.SetAngle(IsCricle ? 360 : 0);
DoughnutChart?.Update("setAngle");
}
/// <summary>
///
/// </summary>
[JSInvokable]
public void ShowToast()
{
ToastService?.Show(new ToastOption() { Title = "友情提示", Content = "屏幕宽度过小,如果是手机请横屏观看" });
}
/// <summary>
///
/// </summary>
/// <param name="disposing"></param>
private void Dispose(bool disposing)
{
if (disposing) Interope?.Dispose();
}
/// <summary>
///
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// 获得事件方法
/// </summary>
/// <returns></returns>
private IEnumerable<EventItem> GetEvents() => new EventItem[]
{
new EventItem()
{
Name = "OnInit",
Description="组件数据初始化委托方法",
Type ="Func<Task<ChartDataSource>>"
},
new EventItem()
{
Name = "OnAfterInit",
Description="客户端绘制图表完毕后回调此委托方法",
Type ="Action"
},
};
/// <summary>
/// 获得属性方法
/// </summary>
/// <returns></returns>
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]
{
// TODO: 移动到数据库中
new AttributeItem() {
Name = "Angle",
Description = "Bubble 模式下显示角度 180 为 半圆 360 为正圆",
Type = "int",
ValueList = " — ",
DefaultValue = " — ",
},
new AttributeItem() {
Name = "Width",
Description = "组件宽度支持单位 如: 100px 75%",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new AttributeItem() {
Name = "ChartType",
Description = "设置图表类型",
Type = "ChartType",
ValueList = "Line|Bar|Pie|Doughnut|Bubble",
DefaultValue = "Line"
},
};
}
}