Enterprise-level component library based on Bootstrap and Blazor

star nuget master download license repo commit

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">&lt;PackageReference Include="BootstrapBlazor.Chart" Version="@Version" /&gt;</Pre>

<div class="code-label">Package Manager</div>
<Pre class="no-highlight">Install-Package BootstrapBlazor.Chart -Version @Version</Pre>

<h4>CSS 文件</h4>

<Pre>&lt;link rel="stylesheet" href="_content/BootstrapBlazor.Chart/css/bootstrap.blazor.chart.bundle.min.css" /&gt;</Pre>

<h4>JS 文件</h4>

<Pre>&lt;script src="_content/BootstrapBlazor.Chart/js/bootstrap.blazor.chart.bundle.min.js"&gt;&lt;/script&gt;</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"
            },
        };
    }
}

B 站相关视频链接

暂无

交流群

QQ群: BootstrapAdmin & Blazor(795206915)欢迎加群讨论
An error has occurred. This application may no longer respond until reloaded. Reload