Add RTL-aware Start/End legend positions and default to End

This commit is contained in:
yordanov
2026-06-22 12:23:59 +03:00
parent 71fea296e7
commit 5cac28f5e8
5 changed files with 103 additions and 9 deletions

View File

@@ -35,6 +35,76 @@ namespace Radzen.Blazor.Tests
return double.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
}
private static RenderFragment LegendWithSeries(LegendPosition position) => builder =>
{
builder.OpenComponent<RadzenLegend>(0);
builder.AddAttribute(1, nameof(RadzenLegend.Position), position);
builder.CloseComponent();
builder.OpenComponent<RadzenLineSeries<DataItem>>(2);
builder.AddAttribute(3, nameof(RadzenLineSeries<DataItem>.CategoryProperty), nameof(DataItem.Category));
builder.AddAttribute(4, nameof(RadzenLineSeries<DataItem>.ValueProperty), nameof(DataItem.Value));
builder.AddAttribute(5, nameof(RadzenLineSeries<DataItem>.Title), "Series");
builder.AddAttribute(6, nameof(RadzenLineSeries<DataItem>.Data), (IEnumerable<DataItem>)SampleData);
builder.CloseComponent();
};
[Theory]
[InlineData(LegendPosition.Start, "rz-legend-left")]
[InlineData(LegendPosition.End, "rz-legend-right")]
public async Task StartEndLegend_InLtr_ResolvesToPhysicalSide(LegendPosition position, string expectedClass)
{
using var ctx = CreateChartContext();
var chart = ctx.RenderComponent<RadzenChart>(p => p.Add(c => c.ChildContent, LegendWithSeries(position)));
await chart.InvokeAsync(() => chart.Instance.Resize(400, 300));
Assert.Contains(expectedClass, chart.Markup);
}
[Theory]
[InlineData(LegendPosition.Start, "rz-legend-right")]
[InlineData(LegendPosition.End, "rz-legend-left")]
public async Task StartEndLegend_InRtl_FlipsToOppositeSide(LegendPosition position, string expectedClass)
{
using var ctx = CreateChartContext();
var chart = ctx.RenderComponent<RadzenChart>(p => p.Add(c => c.ChildContent, LegendWithSeries(position)));
await chart.InvokeAsync(() => chart.Instance.Resize(400, 300));
await chart.InvokeAsync(() => chart.Instance.SetRTL(true));
Assert.Contains(expectedClass, chart.Markup);
}
private static RenderFragment DefaultLegendWithSeries() => builder =>
{
builder.OpenComponent<RadzenLegend>(0);
builder.CloseComponent();
builder.OpenComponent<RadzenLineSeries<DataItem>>(1);
builder.AddAttribute(2, nameof(RadzenLineSeries<DataItem>.CategoryProperty), nameof(DataItem.Category));
builder.AddAttribute(3, nameof(RadzenLineSeries<DataItem>.ValueProperty), nameof(DataItem.Value));
builder.AddAttribute(4, nameof(RadzenLineSeries<DataItem>.Title), "Series");
builder.AddAttribute(5, nameof(RadzenLineSeries<DataItem>.Data), (IEnumerable<DataItem>)SampleData);
builder.CloseComponent();
};
[Fact]
public async Task DefaultLegend_RendersOnRightInLtr_AndFlipsToLeftInRtl()
{
using var ctx = CreateChartContext();
// No Position set -> defaults to LegendPosition.End.
var chart = ctx.RenderComponent<RadzenChart>(p => p.Add(c => c.ChildContent, DefaultLegendWithSeries()));
await chart.InvokeAsync(() => chart.Instance.Resize(400, 300));
Assert.Contains("rz-legend-right", chart.Markup);
await chart.InvokeAsync(() => chart.Instance.SetRTL(true));
Assert.Contains("rz-legend-left", chart.Markup);
}
[Fact]
public async Task TopLegend_WithManyWrappingSeries_ReservesMoreSpaceThanSingleRow()
{

View File

@@ -20,6 +20,14 @@ namespace Radzen.Blazor
/// <summary>
/// The legend is below the series.
/// </summary>
Bottom
Bottom,
/// <summary>
/// The legend is at the inline-start side of the series &#8212; left in left-to-right mode, right in right-to-left mode.
/// </summary>
Start,
/// <summary>
/// The legend is at the inline-end side of the series &#8212; right in left-to-right mode, left in right-to-left mode.
/// </summary>
End
}
}

View File

@@ -242,6 +242,18 @@ namespace Radzen.Blazor
}
}
/// <summary>
/// Resolves the legend position to a concrete side, mapping the direction-aware
/// <see cref="LegendPosition.Start"/> / <see cref="LegendPosition.End"/> values to
/// <see cref="LegendPosition.Left"/> / <see cref="LegendPosition.Right"/> based on <see cref="IsRTL"/>.
/// </summary>
internal LegendPosition EffectiveLegendPosition => (Legend?.Position ?? LegendPosition.Right) switch
{
LegendPosition.Start => IsRTL ? LegendPosition.Right : LegendPosition.Left,
LegendPosition.End => IsRTL ? LegendPosition.Left : LegendPosition.Right,
var position => position
};
/// <summary>
/// Gets or sets the callback invoked when a user clicks on a data point or segment in a chart series.
/// Provides information about the clicked series, data item, and value in the event arguments.
@@ -717,9 +729,11 @@ namespace Radzen.Blazor
if (Legend.Visible)
{
if (Legend.Position == LegendPosition.Right || Legend.Position == LegendPosition.Left)
var legendPosition = EffectiveLegendPosition;
if (legendPosition == LegendPosition.Right || legendPosition == LegendPosition.Left)
{
if (Legend.Position == LegendPosition.Right)
if (legendPosition == LegendPosition.Right)
{
MarginRight = legendSize + 16 + (IsRTL ? valueAxisSize : additionalAxesWidth);
}
@@ -728,9 +742,9 @@ namespace Radzen.Blazor
MarginLeft = legendSize + 16 + (IsRTL ? additionalAxesWidth : valueAxisSize);
}
}
else if (Legend.Position == LegendPosition.Top || Legend.Position == LegendPosition.Bottom)
else if (legendPosition == LegendPosition.Top || legendPosition == LegendPosition.Bottom)
{
if (Legend.Position == LegendPosition.Top)
if (legendPosition == LegendPosition.Top)
{
MarginTop = legendSize + 16;
}

View File

@@ -11,9 +11,10 @@ namespace Radzen.Blazor
/// <summary>
/// Gets or sets the position.
/// </summary>
/// <value>The position.</value>
/// <value>The position. Default is <see cref="LegendPosition.End"/>, which renders on the right
/// in left-to-right mode and automatically flips to the left in right-to-left mode.</value>
[Parameter]
public LegendPosition Position { get; set; }
public LegendPosition Position { get; set; } = LegendPosition.End;
/// <summary>
/// Gets or sets a value indicating whether this <see cref="RadzenLegend"/> is visible.
@@ -33,7 +34,8 @@ namespace Radzen.Blazor
var size = 16 * 0.875;
if (Position == LegendPosition.Right || Position == LegendPosition.Left)
if (Position == LegendPosition.Right || Position == LegendPosition.Left
|| Position == LegendPosition.Start || Position == LegendPosition.End)
{
if (chart.Series.Any())
{

View File

@@ -21,6 +21,6 @@
public RadzenChart? Chart { get; set; }
string Class => ClassList.Create("rz-legend")
.Add($"rz-legend-{Chart?.Legend?.Position ?? LegendPosition.Right}".ToLowerInvariant())
.Add($"rz-legend-{Chart?.EffectiveLegendPosition ?? LegendPosition.Right}".ToLowerInvariant())
.ToString();
}