Skip to content

Commit

Permalink
Chart label rotation.
Browse files Browse the repository at this point in the history
  • Loading branch information
akorchev committed Oct 28, 2024
1 parent e964851 commit 643916f
Show file tree
Hide file tree
Showing 10 changed files with 231 additions and 14 deletions.
13 changes: 13 additions & 0 deletions Radzen.Blazor/AxisBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,26 @@ public abstract class AxisBase : RadzenChartComponentBase, IChartAxis
/// <value><c>true</c> if visible; otherwise, <c>false</c>.</value>
[Parameter]
public bool Visible { get; set; } = true;
/// <summary>
/// Specifies the label rotation angle in degrees. Set to <c>null</c> by default which means no rotation is applied. Has higher precedence than <see cref="LabelAutoRotation"/>.
/// </summary>
[Parameter]
public double? LabelRotation { get; set; } = null;

/// <summary>
/// Specifies the automatic label rotation angle in degrees. If set RadzenChart will automatically rotate the labels to fit the available space by the specified value. Has lower precedence than <see cref="LabelRotation"/>.
/// </summary>
[Parameter]
public double? LabelAutoRotation { get; set; } = null;

/// <inheritdoc />
protected override bool ShouldRefreshChart(ParameterView parameters)
{
return DidParameterChange(parameters, nameof(Min), Min) ||
DidParameterChange(parameters, nameof(Max), Max) ||
DidParameterChange(parameters, nameof(Visible), Visible) ||
DidParameterChange(parameters, nameof(LabelRotation), LabelRotation) ||
DidParameterChange(parameters, nameof(LabelAutoRotation), LabelAutoRotation) ||
DidParameterChange(parameters, nameof(Step), Step);
}

Expand Down
4 changes: 2 additions & 2 deletions Radzen.Blazor/RadzenChart.razor
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
{
<CascadingValue Value="@this">
<Legend />
<svg style="width: 100%; height: 100%">
<svg style="width: 100%; height: 100%; overflow: visible;">
<g transform="@($"translate({MarginLeft.ToInvariantString()}, {MarginTop.ToInvariantString()})")">
<ClipPath />
@if(ShouldRenderAxes())
Expand All @@ -38,7 +38,7 @@
@donut.RenderTitle(MarginLeft, MarginTop)
}
}

</CascadingValue>
}
</div>
Expand Down
31 changes: 29 additions & 2 deletions Radzen.Blazor/Rendering/CategoryAxis.razor
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
<CategoryAxisTick X="@x" Y="@y1" Text="@text" Stroke="@(XAxis.Ticks.Stroke ?? XAxis.Stroke)" StrokeWidth="@XAxis.Ticks.StrokeWidth" LineType="@XAxis.Ticks.LineType">
@XAxis.Ticks.Template(context)
</CategoryAxisTick>
}
}
else if (!String.IsNullOrEmpty(text))
{
<CategoryAxisTick X="@x" Y="@y1" Text="@text" Stroke="@(XAxis.Ticks.Stroke ?? XAxis.Stroke)" StrokeWidth="@XAxis.Ticks.StrokeWidth" LineType="@XAxis.Ticks.LineType"/>
<CategoryAxisTick Rotate=@rotate X="@x" Y="@y1" Text="@text" Stroke="@(XAxis.Ticks.Stroke ?? XAxis.Stroke)" StrokeWidth="@XAxis.Ticks.StrokeWidth" LineType="@XAxis.Ticks.LineType"/>
}

if (XAxis.GridLines.Visible && idx > start)
Expand All @@ -47,6 +47,8 @@
private AxisBase XAxis { get; set; }
private AxisBase YAxis { get; set; }

private double? rotate;

protected override void OnParametersSet()
{
XAxis = Chart.CategoryAxis;
Expand All @@ -69,5 +71,30 @@
var valueTicks = Chart.ValueScale.Ticks(YAxis.TickDistance);
y1 = Chart.ValueScale.Scale(valueTicks.Start);
y2 = Chart.ValueScale.Scale(valueTicks.End);

if (XAxis.LabelRotation != null)
{
rotate = XAxis.LabelRotation;
}
else if (XAxis.LabelAutoRotation != null)
{
rotate = null;

var tickWidth = (x2 - x1) / ((double)end - (double)start);

for (var idx = start; idx <= end; idx += step)
{
var value = Chart.CategoryScale.Value((double)idx);
var text = XAxis.Format(Chart.CategoryScale, value);

var textWidth = TextMeasurer.TextWidth(text) - 8;

if (textWidth > tickWidth)
{
rotate = XAxis.LabelAutoRotation;
break;
}
}
}
}
}
34 changes: 30 additions & 4 deletions Radzen.Blazor/Rendering/CategoryAxisTick.razor
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,38 @@
<Line class="rz-tick-line" Stroke="@Stroke" StrokeWidth="@StrokeWidth" LineType="@LineType" X1="@X" Y1="@Y" X2="@X" Y2="@(Y+6)" />
@if (ChildContent == null)
{
<g>
<text class="rz-tick-text" x="@X.ToInvariantString()" dy="1em" y="@((Y + 6).ToInvariantString())">@Text</text>
</g>
@if (Rotate != null)
{
<text>
<text class="rz-tick-text" x="@x" text-anchor=@textAnchor dy="1em" y="@y" transform="rotate(@angle, @x, @y)">@Text</text>
</text>
}
else
{
<text>
<text class="rz-tick-text" text-anchor=@textAnchor x="@x" dy="1em" y="@y">@Text</text>
</text>
}
}
else
{
@ChildContent
}
</g>
</g>

@code {
[Parameter]
public double? Rotate { get; set; }

string x => X.ToInvariantString();
string y => (Y + 6).ToInvariantString();

string angle => Rotate?.ToInvariantString();

string textAnchor => Rotate switch
{
> 0 => "start",
< 0 => "end",
_ => "middle"
};
}
6 changes: 1 addition & 5 deletions Radzen.Blazor/themes/components/blazor/_chart.scss
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,6 @@ $chart-color-schemes: (
}
}

.rz-category-axis .rz-tick-text {
text-anchor: middle;
}

.rz-axis .rz-axis-title {
stroke: none;
text-anchor: middle;
Expand Down Expand Up @@ -330,7 +326,7 @@ $chart-color-schemes: (
gap: 1rem;
padding: 0.125rem 0.5rem;
border-radius: var(--rz-chart-tooltip-item-border-radius);

&:hover {
background-color: var(--rz-chart-tooltip-item-hover-background-color);
}
Expand Down
2 changes: 1 addition & 1 deletion RadzenBlazorDemos/Pages/AreaChartConfig.razor
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<RadzenAreaSeries Smooth="@smooth" Data="@revenue2024" CategoryProperty="Date" Title="2024" LineType="LineType.Dashed" ValueProperty="Revenue">
<RadzenSeriesDataLabels Visible="@showDataLabels" />
</RadzenAreaSeries>
<RadzenCategoryAxis Padding="20" />
<RadzenCategoryAxis Padding="20" LabelAutoRotation="-45" />
<RadzenValueAxis Formatter="@FormatAsUSD">
<RadzenGridLines Visible="true" />
<RadzenAxisTitle Text="Revenue in USD" />
Expand Down
61 changes: 61 additions & 0 deletions RadzenBlazorDemos/Pages/ChartLabelAutoRotation.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@using System.Globalization

<RadzenStack class="rz-p-0 rz-p-md-6 rz-p-lg-12">
<RadzenCard Variant="Variant.Outlined">
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Wrap="FlexWrap.Wrap">
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.5rem">
<RadzenLabel Text="Rotation" Component="rotation" />
<RadzenSlider @bind-Value="@rotation" Name="rotation" Min="-90" Max="90" />
<RadzenText>@(rotation)<sup>&deg;</sup></RadzenText>
</RadzenStack>
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.5rem">
<RadzenLabel Text="Width" Component="width" />
<RadzenSlider @bind-Value="@width" Name="width" Min="600" Max="1200" />
<RadzenText>@(width)px</RadzenText>
</RadzenStack>
</RadzenStack>
</RadzenCard>

<RadzenChart style="@($"width: {width}px")">
<RadzenAreaSeries Smooth="true" Data="@revenue2024" CategoryProperty="Date" Title="2024" ValueProperty="Revenue">
<RadzenSeriesDataLabels Visible="@showDataLabels" />
</RadzenAreaSeries>
<RadzenCategoryAxis Padding="20" LabelAutoRotation="@rotation" />
<RadzenValueAxis Formatter="@FormatAsUSD">
<RadzenGridLines Visible="true" />
<RadzenAxisTitle Text="Revenue in USD" />
</RadzenValueAxis>
</RadzenChart>
</RadzenStack>

@code {
double rotation = -45;
bool showDataLabels = false;
double width = 600;

class DataItem
{
public string Date { get; set; }
public double Revenue { get; set; }
}

string FormatAsUSD(object value)
{
return ((double)value).ToString("C0", CultureInfo.CreateSpecificCulture("en-US"));
}

DataItem[] revenue2024 = new DataItem[] {
new DataItem { Date = "January", Revenue = 234000 },
new DataItem { Date = "February", Revenue = 269000 },
new DataItem { Date = "March", Revenue = 233000 },
new DataItem { Date = "April", Revenue = 244000 },
new DataItem { Date = "May", Revenue = 214000 },
new DataItem { Date = "June", Revenue = 253000 },
new DataItem { Date = "July", Revenue = 274000 },
new DataItem { Date = "August", Revenue = 284000 },
new DataItem { Date = "September", Revenue = 273000 },
new DataItem { Date = "October", Revenue = 282000 },
new DataItem { Date = "November", Revenue = 289000 },
new DataItem { Date = "December", Revenue = 294000 }
};
}
55 changes: 55 additions & 0 deletions RadzenBlazorDemos/Pages/ChartLabelRotation.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
@using System.Globalization

<RadzenStack class="rz-p-0 rz-p-md-6 rz-p-lg-12">
<RadzenCard Variant="Variant.Outlined">
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Wrap="FlexWrap.Wrap">
<RadzenStack Orientation="Orientation.Horizontal" AlignItems="AlignItems.Center" Gap="0.5rem">
<RadzenLabel Text="Rotation" Component="rotation" />
<RadzenSlider @bind-Value="@rotation" Name="rotation" Min="-90" Max="90" />
<RadzenText>@(rotation)<sup>&deg;</sup></RadzenText>
</RadzenStack>
</RadzenStack>
</RadzenCard>

<RadzenChart>
<RadzenAreaSeries Smooth="true" Data="@revenue2024" CategoryProperty="Date" Title="2024" ValueProperty="Revenue">
<RadzenSeriesDataLabels Visible="@showDataLabels" />
</RadzenAreaSeries>
<RadzenCategoryAxis Padding="20" LabelRotation="@rotation" />
<RadzenValueAxis Formatter="@FormatAsUSD">
<RadzenGridLines Visible="true" />
<RadzenAxisTitle Text="Revenue in USD" />
</RadzenValueAxis>
</RadzenChart>
</RadzenStack>

@code {
double rotation = -45;
bool showDataLabels = false;

class DataItem
{
public string Date { get; set; }
public double Revenue { get; set; }
}

string FormatAsUSD(object value)
{
return ((double)value).ToString("C0", CultureInfo.CreateSpecificCulture("en-US"));
}

DataItem[] revenue2024 = new DataItem[] {
new DataItem { Date = "January", Revenue = 234000 },
new DataItem { Date = "February", Revenue = 269000 },
new DataItem { Date = "March", Revenue = 233000 },
new DataItem { Date = "April", Revenue = 244000 },
new DataItem { Date = "May", Revenue = 214000 },
new DataItem { Date = "June", Revenue = 253000 },
new DataItem { Date = "July", Revenue = 274000 },
new DataItem { Date = "August", Revenue = 284000 },
new DataItem { Date = "September", Revenue = 273000 },
new DataItem { Date = "October", Revenue = 282000 },
new DataItem { Date = "November", Revenue = 289000 },
new DataItem { Date = "December", Revenue = 294000 }
};
}
30 changes: 30 additions & 0 deletions RadzenBlazorDemos/Pages/ChartLabelRotationPage.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@page "/chart-label-rotation"

<RadzenText TextStyle="TextStyle.H2" TagName="TagName.H1" class="rz-pt-8">
Radzen Blazor Chart label rotation
</RadzenText>
<RadzenText Anchor="chart-label-rotation#auto-rotation" TextStyle="TextStyle.H5" TagName="TagName.H2" class="rz-pt-12">
Auto Rotation
</RadzenText>
<RadzenText TextStyle="TextStyle.Body1" class="rz-mb-8">
The Radzen Blazor Chart component can automatically rotate the labels of the category axis when they overlap.
To enable that set the <strong>LabelAutoRotation</strong> property: <code>LabelAutoRotation="-45"</code>.
</RadzenText>
<RadzenText TextStyle="TextStyle.Body1" class="rz-mb-8">
Try changing the angle and the width of the chart to see the effect.
</RadzenText>
<RadzenExample ComponentName="Chart" Example="ChartLabelAutoRotation" DocumentationLink="https://blazor.radzen.com/docs/guides/components/chart.html">
<ChartLabelAutoRotation />
</RadzenExample>
<RadzenText Anchor="chart-label-rotation#rotation" TextStyle="TextStyle.H5" TagName="TagName.H2" class="rz-pt-12">
Predefined Rotation
</RadzenText>
<RadzenText TextStyle="TextStyle.Body1" class="rz-mb-8">
To always rotate the labels of the category axis set the <strong>LabelRotation</strong> property: <code>LabelRotation="-45"</code>.
</RadzenText>
<RadzenText TextStyle="TextStyle.Body1" class="rz-mb-8">
Try changing the angle and the width of the chart to see the effect.
</RadzenText>
<RadzenExample ComponentName="Chart" Example="ChartLabelAutoRotation" DocumentationLink="https://blazor.radzen.com/docs/guides/components/chart.html">
<ChartLabelRotation />
</RadzenExample>
9 changes: 9 additions & 0 deletions RadzenBlazorDemos/Services/ExampleService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,15 @@ public class ExampleService
Tags = new [] { "chart", "graph", "legend" }
},
new Example
{
Name = "Label Rotation",
Path = "chart-label-rotation",
Title = "Blazor Chart Component - Label Rotation | Free UI Components by Radzen",
Description = "The Radzen Blazor Chart can rotate the labels of the horizontal axis.",
New = true,
Tags = new [] { "chart", "label", "rotate", "rotation" }
},
new Example
{
Name = "Trends",
Path = "chart-trends",
Expand Down

0 comments on commit 643916f

Please sign in to comment.