feat(Chart): add AppendData parameter (#4047)

* chore: bump version 8.1.7

* chore: 更新依赖

* Feat(Chart): use custom ChartDataSource (#4041)

Co-authored-by: Argo Zhang <argo@live.ca>

* chore: bump version 8.1.8

* refactor: 重构代码

* feat: 增加 AppendData 扩展数据

* feat: 增加 AppendData 参数

* refactor: 增加 deepMerge 方法

* doc: 增加 AppendData 示例

* chore: 更新项目依赖

* refactor: 更新命名空间

---------

Co-authored-by: AiZhen <53560110+AiYuZhen@users.noreply.github.com>
This commit is contained in:
Argo Zhang 2024-08-13 17:01:38 +08:00 committed by GitHub
parent 4792fe6ebc
commit f85b22791c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 104 additions and 32 deletions

View File

@ -35,6 +35,7 @@
<PackageReference Include="BootstrapBlazor.Bluetooth" Version="8.0.2" />
<PackageReference Include="BootstrapBlazor.BootstrapIcon" Version="8.0.3" />
<PackageReference Include="BootstrapBlazor.BootstrapIcon.Extensions" Version="8.0.6" />
<PackageReference Include="BootstrapBlazor.Chart" Version="8.1.8" />
<PackageReference Include="BootstrapBlazor.CherryMarkdown" Version="8.0.0" />
<PackageReference Include="BootstrapBlazor.CodeEditor" Version="8.0.2" />
<PackageReference Include="BootstrapBlazor.Dock" Version="8.1.7" />

View File

@ -63,14 +63,8 @@
<Pre ShowToolbar="true">@_code</Pre>
</DemoBlock>
<DemoBlock Title="添加未封装属性"
Introduction="通过继承<code>ChartDataset</code>类型,添加未封装的属性"
Name="BarAddProperty">
<Row ItemsPerRow="ItemsPerRow.Six" RowType="RowType.Inline">
<BootstrapInputGroup>
<BootstrapInputGroupLabel DisplayText="是否通过继承添加属性"/>
<Switch @bind-Value=IsChartDataset2 OnValueChanged="@(v=>BarAdd!.Reload())" ShowLabel="false" />
</BootstrapInputGroup>
</Row>
<Chart @ref=BarAdd ChartType="ChartType.Line" OnInitAsync="() => OnInitAddProperty(true)" Title="BarColorSeparately Demo" Height="500px" Width="500px" />
<DemoBlock Title="@Localizer["AppendDataTitle"]"
Introduction="@Localizer["AppendDataIntro"]"
Name="AppendData">
<Chart OnInitAsync="GetData" AppendData="GetAppendData()" />
</DemoBlock>

View File

@ -295,6 +295,38 @@ public partial class Line : IDisposable
}
}
private Task<ChartDataSource> GetData()
{
var BarDataCount = 6;
var BarDatasetCount = 3;
var Randomer = new Random();
var ds = new ChartDataSource();
ds.Options.Title = "Bar Histogram";
ds.Options.X.Title = "Days";
ds.Options.Y.Title = "Numerical value";
ds.Labels = Enumerable.Range(1, BarDataCount).Select(i => i.ToString());
for (var index = 0; index < BarDatasetCount; index++)
{
ds.Data.Add(new ChartDataset()
{
Label = $"Set {index}",
Data = Enumerable.Range(1, BarDataCount).Select(i => Randomer.Next(20, 37)).Cast<object>()
});
}
return Task.FromResult(ds);
}
private static object GetAppendData()
{
var steps = new List<object>();
for (var index = 0; index < 3; index++)
{
// 添加 ChartDataset 未提供的 Stepped 参数
steps.Add(new { Stepped = true });
}
return new { Data = steps };
}
/// <summary>
/// <inheritdoc/>
/// </summary>

View File

@ -560,7 +560,9 @@
"LineBarAspectRatioTitle": "Chart ratio",
"LineBarAspectRatioIntro": "Setting the height and width will automatically disable the constraint chart ratio, and the chart will fill the container",
"LineChartJSTitle": "Generate Chart through JS",
"LineChartJSIntro": "Due to the underlying reference of<code>BootstrapBlazor.Chart</code>to<code>Chart.JS</code>, we can call and generate charts through JS."
"LineChartJSIntro": "Due to the underlying reference of<code>BootstrapBlazor.Chart</code>to<code>Chart.JS</code>, we can call and generate charts through JS.",
"AppendDataTitle": "Append Data",
"AppendDataIntro": "Since <code>ChartDataSource</code> does not fully encapsulate all parameters in <code>Chart.JS</code>, when we need to set some unprovided parameters, we can use <code>AppendData</code> to complete it."
},
"BootstrapBlazor.Server.Components.Samples.Charts.Bar": {
"BarTypeTitle": "Bar graph",

View File

@ -560,7 +560,9 @@
"LineBarAspectRatioTitle": "图表比例",
"LineBarAspectRatioIntro": "设置了高度和宽度,会自动禁用约束图表比例, 图表充满容器",
"LineChartJSTitle": "通过JS生成Chart",
"LineChartJSIntro": "由于 <code>BootstrapBlazor.Chart</code> 底层引用了 <code>Chart.JS</code> 所以我们可以通过JS方式来调用并生成图表。"
"LineChartJSIntro": "由于 <code>BootstrapBlazor.Chart</code> 底层引用了 <code>Chart.JS</code> 所以我们可以通过JS方式来调用并生成图表。",
"AppendDataTitle": "数据参数扩展",
"AppendDataIntro": "由于 <code>ChartDataSource</code> 没有完全封装 <code>Chart.JS</code> 中所有参数,当我们需要设置一些未提供的参数时,可以通过 <code>AppendData</code> 来完成"
},
"BootstrapBlazor.Server.Components.Samples.Charts.Bar": {
"BarTypeTitle": "Bar 图",

View File

@ -775,6 +775,20 @@ export function switchTheme(theme, x = 0, y = 0, sync = true) {
}
}
const deepMerge = (obj1, obj2) => {
for (let key in obj2) {
if (obj2.hasOwnProperty(key)) {
if (obj2[key] instanceof Object && obj1[key] instanceof Object) {
obj1[key] = deepMerge(obj1[key], obj2[key]);
}
else {
obj1[key] = obj2[key];
}
}
}
return obj1;
}
export {
autoAdd,
autoRemove,
@ -785,10 +799,11 @@ export {
addLink,
addScript,
copy,
getTextFromClipboard,
getAllClipboardContents,
deepMerge,
debounce,
drag,
getTextFromClipboard,
getAllClipboardContents,
insertBefore,
insertAfter,
isDisabled,

View File

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">
<PropertyGroup>
<Version>8.1.6</Version>
<Version>8.1.8</Version>
<PackageTags>Bootstrap Blazor WebAssembly wasm UI Components Chart</PackageTags>
<Description>Bootstrap UI components extensions of Chart.js</Description>
</PropertyGroup>

View File

@ -101,13 +101,16 @@ public partial class Chart
[Parameter]
public bool IsAnimation { get; set; } = true;
/// <summary>
/// 获得/设置 扩展数据 默认为空 序列化到浏览器与数据集合 <see cref="ChartDataSource "/> 合并,方便把组件未提供的参数传递到浏览器
/// </summary>
[Parameter]
public object? AppendData { get; set; }
/// <summary>
/// 获得/设置 组件数据初始化委托方法
/// </summary>
[Parameter]
#if NET6_0_OR_GREATER
[EditorRequired]
#endif
public Func<Task<ChartDataSource>>? OnInitAsync { get; set; }
/// <summary>
@ -154,21 +157,25 @@ public partial class Chart
if (firstRender)
{
if (OnInitAsync == null)
if (OnInitAsync == null && AppendData == null)
{
throw new InvalidOperationException("OnInit parameter must be set");
throw new InvalidOperationException($"{nameof(OnInitAsync)} parameter or {nameof(AppendData)} must one be set. {nameof(OnInitAsync)} 回调方法或者 {nameof(AppendData)} 参数必须设置一个");
}
var ds = await OnInitAsync();
UpdateOptions(ds);
if (Height != null && Width != null)
ChartDataSource? ds = null;
if (OnInitAsync != null)
{
//设置了高度和宽度,会自动禁用约束图表比例,图表充满容器
ds.Options.MaintainAspectRatio = false;
ds = await OnInitAsync();
UpdateOptions(ds);
if (Height != null && Width != null)
{
//设置了高度和宽度,会自动禁用约束图表比例,图表充满容器
ds.Options.MaintainAspectRatio = false;
}
}
await InvokeVoidAsync("init", Id, Interop, nameof(Completed), ds);
await InvokeVoidAsync("init", Id, Interop, nameof(Completed), ds, AppendData);
}
}
@ -176,9 +183,12 @@ public partial class Chart
/// 图表绘制完成后回调此方法
/// </summary>
[JSInvokable]
public void Completed()
public async Task Completed()
{
OnAfterInitAsync?.Invoke();
if (OnAfterInitAsync != null)
{
await OnAfterInitAsync();
}
}
/// <summary>

View File

@ -70,7 +70,23 @@ const genericOptions = {
radius: 0
}
const getChartOption = function (option) {
const deepMerge = (obj1, obj2) => {
for (let key in obj2) {
if (obj2.hasOwnProperty(key)) {
if (obj2[key] instanceof Object && obj1[key] instanceof Object) {
obj1[key] = deepMerge(obj1[key], obj2[key]);
}
else {
obj1[key] = obj2[key];
}
}
}
return obj1;
}
const getChartOption = function (option, appendData) {
option = deepMerge(option, appendData);
const colors = []
const chartColors = option.options.colors
for (const name in option.options.colors) colors.push(name)
@ -409,8 +425,8 @@ const updateChart = function (config, option) {
}
}
export function init(id, invoke, method, option) {
const op = getChartOption(option);
export function init(id, invoke, method, option, appendData) {
const op = getChartOption(option, appendData);
op.options.onClick = (event, elements, chart) => {
if (elements.length > 0) {
if (option.options.onClickDataMethod) {