Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ jobs:

shellui add chart pie-chart dashboard-02 data-table --force

grep -q 'Blazor-ApexCharts' SmokeApp.csproj || (echo "shellui add chart did not add Blazor-ApexCharts NuGet dep"; exit 1)
grep -q 'ShellCharts.Blazor' SmokeApp.csproj || (echo "shellui add chart did not add the ShellCharts.Blazor NuGet dep"; exit 1)
grep -q 'System.Linq.Dynamic.Core' SmokeApp.csproj || (echo "shellui add data-table did not add System.Linq.Dynamic.Core NuGet dep"; exit 1)

test -f Components/UI/Models/DataTableModels.cs || (echo "shellui add data-table did not install data-table-models"; exit 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<ItemGroup>
<PackageReference Include="QRCoder" Version="1.8.0" />
<PackageReference Include="System.Linq.Dynamic.Core" Version="1.6.9" />
<PackageReference Include="Blazor-ApexCharts" Version="6.0.2" />
<PackageReference Include="ShellCharts.Blazor" Version="0.1.0-alpha" />
</ItemGroup>

<Import Project="Build\ShellUI.targets" />
Expand Down
35 changes: 17 additions & 18 deletions NET10/BlazorInteractiveServer/Components/Demo/ChartsDemo.razor
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
@using BlazorInteractiveServer.Components.UI
@using BlazorInteractiveServer.Components.UI.Variants
@using ApexCharts

<section class="border border-border rounded-lg p-6 bg-card">
<h2 class="text-2xl font-semibold mb-4 text-card-foreground">Bar Chart</h2>
Expand Down Expand Up @@ -49,21 +48,19 @@

<section class="border border-border rounded-lg p-6 bg-card mt-6">
<h2 class="text-2xl font-semibold mb-4 text-card-foreground">Multi-Series Chart</h2>
<MultiSeriesChart TItem="SalesData"
<MultiSeriesChart TItem="MonthlyResult"
Data="Results"
XValue="e => e.Month"
Title="Revenue vs Profit"
Height="300px">
<ChartSeries TItem="SalesData"
Data="SalesData"
<ChartSeries TItem="MonthlyResult"
Name="Revenue"
SeriesType="SeriesType.Bar"
XValue="e => e.Month"
YValue="e => e.Amount" />
<ChartSeries TItem="SalesData"
Data="ProfitData"
YValue="e => e.Revenue" />
<ChartSeries TItem="MonthlyResult"
Name="Profit"
SeriesType="SeriesType.Line"
XValue="e => e.Month"
YValue="e => e.Amount" />
YValue="e => e.Profit" />
</MultiSeriesChart>
</section>

Expand Down Expand Up @@ -138,11 +135,12 @@

@code {
private List<SalesData> SalesData { get; set; } = new();
private List<SalesData> ProfitData { get; set; } = new();
private List<MonthlyResult> Results { get; set; } = new();
private List<CategoryData> CategoryData { get; set; } = new();
private List<SkillItem> Skills { get; set; } = new();
private List<ProgressItem> Progress { get; set; } = new();

public class MonthlyResult { public string Month { get; set; } = ""; public decimal Revenue { get; set; } public decimal Profit { get; set; } }
public class SkillItem { public string Skill { get; set; } = ""; public decimal Level { get; set; } }
public class ProgressItem { public string Label { get; set; } = ""; public decimal Value { get; set; } }

Expand All @@ -158,14 +156,15 @@
new SalesData { Month = "Jun", Amount = 220 }
};

ProfitData = new List<SalesData>
// Every series in a multi-series chart reads the same items, one per month.
Results = new List<MonthlyResult>
{
new SalesData { Month = "Jan", Amount = 40 },
new SalesData { Month = "Feb", Amount = 50 },
new SalesData { Month = "Mar", Amount = 60 },
new SalesData { Month = "Apr", Amount = 70 },
new SalesData { Month = "May", Amount = 55 },
new SalesData { Month = "Jun", Amount = 80 }
new MonthlyResult { Month = "Jan", Revenue = 120, Profit = 40 },
new MonthlyResult { Month = "Feb", Revenue = 150, Profit = 50 },
new MonthlyResult { Month = "Mar", Revenue = 180, Profit = 60 },
new MonthlyResult { Month = "Apr", Revenue = 200, Profit = 70 },
new MonthlyResult { Month = "May", Revenue = 170, Profit = 55 },
new MonthlyResult { Month = "Jun", Revenue = 220, Profit = 80 }
};

CategoryData = new List<CategoryData>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
@using BlazorInteractiveServer.Components.UI
@using BlazorInteractiveServer.Components.UI.Variants
@using BlazorInteractiveServer.Components.Models
@using ApexCharts

<PageTitle>Dashboard</PageTitle>

Expand Down
38 changes: 15 additions & 23 deletions NET10/BlazorInteractiveServer/Components/UI/AreaChart.razor
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
@namespace BlazorInteractiveServer.Components.UI
@using ApexCharts
@using ShellCharts
@inherits Chart<TItem>
@typeparam TItem where TItem : class
@typeparam TItem

<div class="@ComputedClass border border-border bg-card text-card-foreground overflow-hidden [border-radius:var(--radius)] [box-shadow:var(--shadow)]" data-chart-theme="@Theme.ToString().ToLower()">
<ApexChart TItem="TItem"
Title="@Title"
Options="@ChartOptions"
Height="@Height"
Width="@Width">
<ApexPointSeries TItem="TItem"
Items="Data"
Name="@Name"
SeriesType="SeriesType.Area"
XValue="@XValue"
YValue="@YValue" />
</ApexChart>
</div>

@code {
[Parameter] public IEnumerable<TItem>? Data { get; set; }
[Parameter] public string Name { get; set; } = "Data";
[Parameter] public Func<TItem, object>? XValue { get; set; }
[Parameter] public Func<TItem, decimal?>? YValue { get; set; }
}
<ChartFrame Title="@Title" Subtitle="@Subtitle" Class="@Class" Width="@Width" Theme="Theme">
<ChartContainer Data="Data" Height="PlotHeight" AriaLabel="@(Title ?? Name)">
<CartesianGrid />
<XAxis TItem="TItem" TKey="string" DataKey="Category" />
<YAxis />
<Area TItem="TItem" DataKey="Value" Name="@Name" Gradient />
<ChartTooltip />
@if (ShowLegend)
{
<ChartLegend />
}
</ChartContainer>
</ChartFrame>
38 changes: 15 additions & 23 deletions NET10/BlazorInteractiveServer/Components/UI/BarChart.razor
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
@namespace BlazorInteractiveServer.Components.UI
@using ApexCharts
@using ShellCharts
@inherits Chart<TItem>
@typeparam TItem where TItem : class
@typeparam TItem

<div class="@ComputedClass border border-border bg-card text-card-foreground overflow-hidden [border-radius:var(--radius)] [box-shadow:var(--shadow)]" data-chart-theme="@Theme.ToString().ToLower()">
<ApexChart TItem="TItem"
Title="@Title"
Options="@ChartOptions"
Height="@Height"
Width="@Width">
<ApexPointSeries TItem="TItem"
Items="Data"
Name="@Name"
SeriesType="SeriesType.Bar"
XValue="@XValue"
YValue="@YValue" />
</ApexChart>
</div>

@code {
[Parameter] public IEnumerable<TItem>? Data { get; set; }
[Parameter] public string Name { get; set; } = "Data";
[Parameter] public Func<TItem, object>? XValue { get; set; }
[Parameter] public Func<TItem, decimal?>? YValue { get; set; }
}
<ChartFrame Title="@Title" Subtitle="@Subtitle" Class="@Class" Width="@Width" Theme="Theme">
<ChartContainer Data="Data" Height="PlotHeight" AriaLabel="@(Title ?? Name)">
<CartesianGrid />
<XAxis TItem="TItem" TKey="string" DataKey="Category" />
<YAxis />
<Bar TItem="TItem" DataKey="Value" Name="@Name" />
<ChartTooltip />
@if (ShowLegend)
{
<ChartLegend />
}
</ChartContainer>
</ChartFrame>
81 changes: 32 additions & 49 deletions NET10/BlazorInteractiveServer/Components/UI/Chart.razor
Original file line number Diff line number Diff line change
@@ -1,59 +1,42 @@
@namespace BlazorInteractiveServer.Components.UI
@using ApexCharts
@using BlazorInteractiveServer.Components.UI.Variants
@typeparam TItem where TItem : class

<div class="@ComputedClass" data-chart-theme="@Theme.ToString().ToLower()">
<ApexChart TItem="TItem"
Title="@Title"
Options="@ChartOptions"
Height="@Height"
Width="@Width">
@ChildContent
</ApexChart>
</div>
@typeparam TItem

@* Parameters shared by the ready-made charts, which draw with ShellCharts.
For anything they don't cover, compose ShellCharts parts inside a ChartFrame. *@

@code {
[Parameter] public ChartTheme Theme { get; set; } = ChartTheme.Default;
[Parameter] public IEnumerable<TItem>? Data { get; set; }

/// <summary>The series name, for the legend and tooltip.</summary>
[Parameter] public string Name { get; set; } = "Data";

/// <summary>Each item's category: its label on the x axis, or the name of its slice, ring or spoke.</summary>
[Parameter] public Func<TItem, object>? XValue { get; set; }

[Parameter] public Func<TItem, decimal?>? YValue { get; set; }

[Parameter] public ChartTheme Theme { get; set; }

[Parameter] public string? Title { get; set; }

[Parameter] public string? Subtitle { get; set; }

[Parameter] public string? Class { get; set; }
[Parameter] public string? Height { get; set; } = "400px";

/// <summary>The plot's height, such as "300px".</summary>
[Parameter] public string? Height { get; set; } = "300px";

[Parameter] public string? Width { get; set; } = "100%";
[Parameter] public bool ShowToolbar { get; set; }

[Parameter] public bool ShowLegend { get; set; } = true;
[Parameter] public RenderFragment? ChildContent { get; set; }

private ApexCharts.ApexChartOptions<TItem>? _chartOptions;

protected ApexCharts.ApexChartOptions<TItem> ChartOptions
{
get
{
if (_chartOptions == null)
{
_chartOptions = ChartVariants.GetOptions<TItem>(Theme, ShowToolbar, ShowLegend);

if (!string.IsNullOrEmpty(Title))
{
_chartOptions.Title = _chartOptions.Title ?? new ApexCharts.Title();
_chartOptions.Title.Text = Title;
}

if (!string.IsNullOrEmpty(Subtitle))
{
_chartOptions.Subtitle = _chartOptions.Subtitle ?? new ApexCharts.Subtitle();
_chartOptions.Subtitle.Text = Subtitle;
}
}
return _chartOptions;
}
set => _chartOptions = value;
}

protected string ComputedClass => Shell.Cn(
"border border-border bg-card text-card-foreground overflow-hidden",
"[border-radius:var(--radius)] [box-shadow:var(--shadow)]",
Class
);

[Parameter, Obsolete("ShellCharts has no toolbar, so this does nothing.")]
public bool ShowToolbar { get; set; }

protected int? PlotHeight => int.TryParse(Height?.Replace("px", "").Trim(), out var px) ? px : null;

protected string Category(TItem item) => XValue?.Invoke(item)?.ToString() ?? "";

protected double? Value(TItem item) => (double?)YValue?.Invoke(item);
}
36 changes: 36 additions & 0 deletions NET10/BlazorInteractiveServer/Components/UI/ChartFrame.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
@namespace BlazorInteractiveServer.Components.UI
@using BlazorInteractiveServer.Components.UI.Variants

<div class="@Shell.Cn("border border-border bg-card text-card-foreground p-6 [border-radius:var(--radius)] [box-shadow:var(--shadow)]", Class)" style="@Style">
@if (Title is not null || Subtitle is not null)
{
<div class="mb-4 grid gap-1">
@if (Title is not null)
{
<h3 class="font-semibold leading-none">@Title</h3>
}
@if (Subtitle is not null)
{
<p class="text-sm text-muted-foreground">@Subtitle</p>
}
</div>
}
@ChildContent
</div>

@code {
[Parameter] public string? Title { get; set; }

[Parameter] public string? Subtitle { get; set; }

[Parameter] public string? Class { get; set; }

[Parameter] public string? Width { get; set; }

/// <summary>Colorful and Monochrome swap the theme's --chart-1 … --chart-5 for their own palette.</summary>
[Parameter] public ChartTheme Theme { get; set; }

[Parameter] public RenderFragment? ChildContent { get; set; }

private string Style => (Width is null ? "" : $"width:{Width};") + ChartVariants.Palette(Theme);
}
32 changes: 22 additions & 10 deletions NET10/BlazorInteractiveServer/Components/UI/ChartSeries.razor
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
@namespace BlazorInteractiveServer.Components.UI
@using ApexCharts
@typeparam TItem where TItem : class
@using BlazorInteractiveServer.Components.UI.Variants
@using ShellCharts
@typeparam TItem

<ApexPointSeries TItem="TItem"
Items="Data"
Name="@Name"
SeriesType="@SeriesType"
XValue="@XValue"
YValue="@YValue" />
@switch (SeriesType)
{
case SeriesType.Area:
<Area TItem="TItem" DataKey="Value" Name="@Name" Stack="@Stack" />
break;
case SeriesType.Bar:
<Bar TItem="TItem" DataKey="Value" Name="@Name" Stack="@Stack" />
break;
default:
<Line TItem="TItem" DataKey="Value" Name="@Name" Stack="@Stack" />
break;
}

@code {
[Parameter] public IEnumerable<TItem>? Data { get; set; }
[Parameter] public string Name { get; set; } = "Series";

[Parameter] public SeriesType SeriesType { get; set; } = SeriesType.Line;
[Parameter] public Func<TItem, object>? XValue { get; set; }

[Parameter] public Func<TItem, decimal?>? YValue { get; set; }

/// <summary>Series with the same stack key are drawn on top of each other.</summary>
[Parameter] public string? Stack { get; set; }

private double? Value(TItem item) => (double?)YValue?.Invoke(item);
}
36 changes: 13 additions & 23 deletions NET10/BlazorInteractiveServer/Components/UI/DonutChart.razor
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
@namespace BlazorInteractiveServer.Components.UI
@using ApexCharts
@using ShellCharts
@inherits Chart<TItem>
@typeparam TItem where TItem : class
@typeparam TItem

<div class="@ComputedClass border border-border bg-card text-card-foreground overflow-hidden [border-radius:var(--radius)] [box-shadow:var(--shadow)]" data-chart-theme="@Theme.ToString().ToLower()">
<ApexChart TItem="TItem"
Title="@Title"
Options="@ChartOptions"
Height="@Height"
Width="@Width">
<ApexPointSeries TItem="TItem"
Items="Data"
Name="@Name"
SeriesType="SeriesType.Donut"
XValue="@XValue"
YValue="@YValue" />
</ApexChart>
</div>

@code {
[Parameter] public IEnumerable<TItem>? Data { get; set; }
[Parameter] public string Name { get; set; } = "Data";
[Parameter] public Func<TItem, object>? XValue { get; set; }
[Parameter] public Func<TItem, decimal?>? YValue { get; set; }
}
<ChartFrame Title="@Title" Subtitle="@Subtitle" Class="@Class" Width="@Width" Theme="Theme">
<ChartContainer Data="Data" Height="PlotHeight" AriaLabel="@(Title ?? Name)">
<Donut TItem="TItem" DataKey="Value" NameKey="Category" Name="@Name" PaddingAngle="2" />
<CenterLabel Value="@ChartFormat.Number(Data?.Sum(d => Value(d) ?? 0) ?? 0)" Label="@Name" />
<ChartTooltip />
@if (ShowLegend)
{
<ChartLegend />
}
</ChartContainer>
</ChartFrame>
Loading
Loading