diff --git a/src/Components/Charts/Chart/Annotations/ChartAnnotations.cs b/src/Components/Charts/Chart/Annotations/ChartAnnotations.cs
index 3a53ae1..4edb408 100644
--- a/src/Components/Charts/Chart/Annotations/ChartAnnotations.cs
+++ b/src/Components/Charts/Chart/Annotations/ChartAnnotations.cs
@@ -1,5 +1,6 @@
using System.ComponentModel;
using Microsoft.AspNetCore.Components;
+using Syncfusion.Blazor.Toolkit.Charts.Internal;
namespace Syncfusion.Blazor.Toolkit.Charts
{
@@ -38,9 +39,23 @@ public class ChartAnnotations : ChartSubComponent, ISubcomponentTracker
///
///
/// Use this property to provide an accessibility role for the .
+ /// The value, if non-empty, must be a valid WAI-ARIA role (for example
+ /// "region", "status", "group"). Invalid values are
+ /// rejected at component initialization to prevent invalid role
+ /// attributes from reaching the DOM.
///
[Parameter]
- public string AccessibilityRole { get; set; } = string.Empty;
+ public string AccessibilityRole
+ {
+ get => _accessibilityRole;
+ set
+ {
+ DataVizCommonHelper.AriaRoleValidator.EnsureValidRole(value, nameof(AccessibilityRole));
+ _accessibilityRole = value;
+ }
+ }
+
+ private string _accessibilityRole = string.Empty;
///
/// Gets or sets the accessibility keyboard navigation focus option for the .
@@ -253,4 +268,4 @@ public override void AddRenderer(IChartElementRenderer renderer)
}
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/Components/Charts/Chart/ChartArea/ChartSubTitleStyle.cs b/src/Components/Charts/Chart/ChartArea/ChartSubTitleStyle.cs
index cfa21dc..8270f57 100644
--- a/src/Components/Charts/Chart/ChartArea/ChartSubTitleStyle.cs
+++ b/src/Components/Charts/Chart/ChartArea/ChartSubTitleStyle.cs
@@ -115,6 +115,10 @@ public class ChartSubTitleStyle : ChartDefaultFont
///
///
/// Use this property to provide an accessibility role for the chart subtitle.
+ /// The value, if non-empty, must be a valid WAI-ARIA role (for example
+ /// "heading", "region"). Invalid values are rejected at
+ /// component initialization to prevent invalid role attributes from
+ /// reaching the DOM.
///
///
///
@@ -127,7 +131,17 @@ public class ChartSubTitleStyle : ChartDefaultFont
///
///
[Parameter]
- public string AccessibilityRole { get; set; } = string.Empty;
+ public string AccessibilityRole
+ {
+ get => _accessibilityRole;
+ set
+ {
+ DataVizCommonHelper.AriaRoleValidator.EnsureValidRole(value, nameof(AccessibilityRole));
+ _accessibilityRole = value;
+ }
+ }
+
+ private string _accessibilityRole = string.Empty;
///
/// Gets or sets the accessibility keyboard navigation focus option for the chart subtitle.
diff --git a/src/Components/Charts/Chart/ChartArea/ChartTitleStyle.cs b/src/Components/Charts/Chart/ChartArea/ChartTitleStyle.cs
index 09ef7d2..cb8d809 100644
--- a/src/Components/Charts/Chart/ChartArea/ChartTitleStyle.cs
+++ b/src/Components/Charts/Chart/ChartArea/ChartTitleStyle.cs
@@ -207,6 +207,10 @@ public class ChartTitleStyle : ChartDefaultFont
///
///
/// Use this property to provide an accessibility role for the chart title.
+ /// The value, if non-empty, must be a valid WAI-ARIA role (for example
+ /// "heading", "region"). Invalid values are rejected at
+ /// component initialization to prevent invalid role attributes from
+ /// reaching the DOM.
///
///
///
@@ -219,7 +223,17 @@ public class ChartTitleStyle : ChartDefaultFont
///
///
[Parameter]
- public string AccessibilityRole { get; set; } = string.Empty;
+ public string AccessibilityRole
+ {
+ get => _accessibilityRole;
+ set
+ {
+ DataVizCommonHelper.AriaRoleValidator.EnsureValidRole(value, nameof(AccessibilityRole));
+ _accessibilityRole = value;
+ }
+ }
+
+ private string _accessibilityRole = string.Empty;
///
/// Gets or sets the accessibility keyboard navigation focus option for the chart title.
diff --git a/src/Components/Charts/Chart/Legend/LegendSettings.cs b/src/Components/Charts/Chart/Legend/LegendSettings.cs
index f23bb00..ff38efa 100644
--- a/src/Components/Charts/Chart/Legend/LegendSettings.cs
+++ b/src/Components/Charts/Chart/Legend/LegendSettings.cs
@@ -1,6 +1,6 @@
-using Microsoft.AspNetCore.Components;
+using System.ComponentModel;
+using Microsoft.AspNetCore.Components;
using Syncfusion.Blazor.Toolkit.Charts.Internal;
-using System.ComponentModel;
namespace Syncfusion.Blazor.Toolkit.Charts
{
@@ -250,6 +250,10 @@ public string Height
///
///
/// Use this property to provide an accessibility role for the .
+ /// The value, if non-empty, must be a valid WAI-ARIA role (for example
+ /// "region", "group", "list"). Invalid values are
+ /// rejected at component initialization to prevent invalid role
+ /// attributes from reaching the DOM.
///
///
///
@@ -265,7 +269,17 @@ public string Height
///
///
[Parameter]
- public string AccessibilityRole { get; set; } = string.Empty;
+ public string AccessibilityRole
+ {
+ get => _accessibilityRole;
+ set
+ {
+ DataVizCommonHelper.AriaRoleValidator.EnsureValidRole(value, nameof(AccessibilityRole));
+ _accessibilityRole = value;
+ }
+ }
+
+ private string _accessibilityRole = string.Empty;
///
/// Gets or sets the accessibility keyboard navigation focus option for the .
diff --git a/src/Components/Charts/Chart/Renderer/AxisRenderer/ChartAxisRenderer.cs b/src/Components/Charts/Chart/Renderer/AxisRenderer/ChartAxisRenderer.cs
index 4ad9d55..5fa93c6 100644
--- a/src/Components/Charts/Chart/Renderer/AxisRenderer/ChartAxisRenderer.cs
+++ b/src/Components/Charts/Chart/Renderer/AxisRenderer/ChartAxisRenderer.cs
@@ -1820,7 +1820,7 @@ internal void CustomizeGridRenderingOptions(string key)
foreach (PathOptions option in axisGridOptions)
{
option.Stroke = Axis?.MajorGridLines.Color ?? string.Empty;
- option.StrokeWidth = Axis?.Renderer?.MajorGridLinesWidth ?? 0;
+ option.StrokeWidth = Axis?.MajorGridLines.Width ?? 0;
option.StrokeDashArray = Axis?.MajorGridLines.DashArray ?? string.Empty;
}
}
@@ -1829,7 +1829,7 @@ internal void CustomizeGridRenderingOptions(string key)
foreach (CircleOptions option in AxisRenderInfo.MajorGridCircleOptions)
{
option.Stroke = Axis?.MajorGridLines.Color ?? string.Empty;
- option.StrokeWidth = Axis?.Renderer?.MajorGridLinesWidth ?? 0;
+ option.StrokeWidth = Axis?.MajorGridLines.Width ?? 0;
option.StrokeDashArray = Axis?.MajorGridLines.DashArray ?? string.Empty;
}
}
diff --git a/src/Components/Charts/Chart/Series/ChartSeries.cs b/src/Components/Charts/Chart/Series/ChartSeries.cs
index 8817721..7588549 100644
--- a/src/Components/Charts/Chart/Series/ChartSeries.cs
+++ b/src/Components/Charts/Chart/Series/ChartSeries.cs
@@ -1,11 +1,11 @@
-using Microsoft.AspNetCore.Components;
-using Syncfusion.Blazor.Toolkit.Charts.Internal;
-using Syncfusion.Blazor.Toolkit.Data;
-using Syncfusion.Blazor.Toolkit.Internal;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Globalization;
+using Microsoft.AspNetCore.Components;
+using Syncfusion.Blazor.Toolkit.Charts.Internal;
+using Syncfusion.Blazor.Toolkit.Data;
+using Syncfusion.Blazor.Toolkit.Internal;
namespace Syncfusion.Blazor.Toolkit.Charts
{
@@ -328,6 +328,10 @@ public double Width
/// A string that defines the accessibility role for the .
///
/// Use this property to specify the accessibility role for the root element.
+ /// The value, if non-empty, must be a valid WAI-ARIA role (for example
+ /// "region", "img", "list"). Invalid values are
+ /// rejected at component initialization to prevent invalid role
+ /// attributes from reaching the DOM.
///
///
///
@@ -340,7 +344,17 @@ public double Width
///
///
[Parameter]
- public string AccessibilityRole { get; set; } = string.Empty;
+ public string AccessibilityRole
+ {
+ get => _accessibilityRole;
+ set
+ {
+ DataVizCommonHelper.AriaRoleValidator.EnsureValidRole(value, nameof(AccessibilityRole));
+ _accessibilityRole = value;
+ }
+ }
+
+ private string _accessibilityRole = string.Empty;
///
/// Gets or sets a value indicating whether the series root can receive keyboard focus.
diff --git a/src/Components/Charts/Chart/Series/Trendline/ChartTrendline.cs b/src/Components/Charts/Chart/Series/Trendline/ChartTrendline.cs
index 8805657..d9ddcb4 100644
--- a/src/Components/Charts/Chart/Series/Trendline/ChartTrendline.cs
+++ b/src/Components/Charts/Chart/Series/Trendline/ChartTrendline.cs
@@ -258,7 +258,13 @@ public TrendlineTypes Type
///
/// Gets or sets the ARIA role for the trendline.
///
- /// A string representing the ARIA role. Default is empty.
+ /// A string representing the ARIA role. Default is empty.
+ ///
+ /// The value, if non-empty, must be a valid WAI-ARIA role (for example
+ /// "region", "group"). Invalid values are rejected at
+ /// component initialization to prevent invalid role attributes from
+ /// reaching the DOM.
+ ///
///
///
///
///
[Parameter]
- public string AccessibilityRole { get; set; } = string.Empty;
+ public string AccessibilityRole
+ {
+ get => _accessibilityRole;
+ set
+ {
+ DataVizCommonHelper.AriaRoleValidator.EnsureValidRole(value, nameof(AccessibilityRole));
+ _accessibilityRole = value;
+ }
+ }
+
+ private string _accessibilityRole = string.Empty;
///
/// Gets or sets whether the trendline is focusable via keyboard navigation.
diff --git a/src/Components/Charts/Chart/SfChart.razor.LifeCycle.cs b/src/Components/Charts/Chart/SfChart.razor.LifeCycle.cs
index aa43653..4e47dd8 100644
--- a/src/Components/Charts/Chart/SfChart.razor.LifeCycle.cs
+++ b/src/Components/Charts/Chart/SfChart.razor.LifeCycle.cs
@@ -1,7 +1,7 @@
-using Microsoft.JSInterop;
-using Syncfusion.Blazor.Toolkit.Charts.Internal;
-using System.Collections.Specialized;
+using System.Collections.Specialized;
using System.ComponentModel;
+using Microsoft.JSInterop;
+using Syncfusion.Blazor.Toolkit.Charts.Internal;
namespace Syncfusion.Blazor.Toolkit.Charts
{
@@ -304,6 +304,12 @@ protected override async ValueTask DisposeAsyncCore()
_chartJsModule = null;
_chartJsInProcessModule = null;
}
+
+ // Clear instance-level font measurement caches to prevent memory retention
+ // after the chart is disposed. This ensures per-circuit/per-chart isolation.
+ _fontSizeCache?.Clear();
+ _requestedFontKeys?.Clear();
+
await base.DisposeAsyncCore().ConfigureAwait(true);
}
diff --git a/src/Components/Charts/Chart/SfChart.razor.Members.cs b/src/Components/Charts/Chart/SfChart.razor.Members.cs
index 6fdfc88..640d4d8 100644
--- a/src/Components/Charts/Chart/SfChart.razor.Members.cs
+++ b/src/Components/Charts/Chart/SfChart.razor.Members.cs
@@ -1,8 +1,8 @@
-using Microsoft.AspNetCore.Components;
-using Syncfusion.Blazor.Toolkit.Internal;
+using System.Collections.Specialized;
using System.ComponentModel;
+using Microsoft.AspNetCore.Components;
using Syncfusion.Blazor.Toolkit.Charts.Internal;
-using System.Collections.Specialized;
+using Syncfusion.Blazor.Toolkit.Internal;
namespace Syncfusion.Blazor.Toolkit.Charts
{
@@ -178,6 +178,10 @@ internal class ChartDataState
///
///
/// Use this property to provide an accessibility role for the Chart component.
+ /// The value, if non-empty, must be a valid WAI-ARIA role (for example
+ /// "region", "figure", "img"). Invalid values are
+ /// rejected at component initialization to prevent invalid role
+ /// attributes from reaching the DOM.
///
///
///
@@ -189,7 +193,17 @@ internal class ChartDataState
///
///
[Parameter]
- public string AccessibilityRole { get; set; } = string.Empty;
+ public string AccessibilityRole
+ {
+ get => _accessibilityRole;
+ set
+ {
+ DataVizCommonHelper.AriaRoleValidator.EnsureValidRole(value, nameof(AccessibilityRole));
+ _accessibilityRole = value;
+ }
+ }
+
+ private string _accessibilityRole = string.Empty;
///
/// Gets or sets the accessibility keyboard navigation focus option for the Chart component.
diff --git a/src/Components/Charts/Chart/SfChart.razor.cs b/src/Components/Charts/Chart/SfChart.razor.cs
index 022984c..e085022 100644
--- a/src/Components/Charts/Chart/SfChart.razor.cs
+++ b/src/Components/Charts/Chart/SfChart.razor.cs
@@ -1,15 +1,16 @@
-using Microsoft.AspNetCore.Components;
-using Microsoft.AspNetCore.Components.Rendering;
-using Microsoft.JSInterop;
-using Syncfusion.Blazor.Toolkit.Charts.Internal;
+using System.Collections.Concurrent;
+using System.ComponentModel;
using System.Globalization;
+using System.Reflection;
+using System.Runtime.CompilerServices;
using System.Text.Json;
using System.Text.Json.Serialization;
-using System.Reflection;
-using System.ComponentModel;
-using Syncfusion.Blazor.Toolkit.Data;
+using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.Extensions.Localization;
-using System.Runtime.CompilerServices;
+using Microsoft.JSInterop;
+using Syncfusion.Blazor.Toolkit.Charts.Internal;
+using Syncfusion.Blazor.Toolkit.Data;
[assembly: InternalsVisibleTo("Syncfusion.Blazor.Toolkit.BUnitTest")]
namespace Syncfusion.Blazor.Toolkit.Charts
@@ -178,6 +179,9 @@ internal class JsInteropState
internal List _seriesBorders = [];
internal List _axes = [];
internal List _highLightPatternCollection = [];
+ // Instance-level font measurement caches
+ internal ConcurrentDictionary _fontSizeCache = new();
+ internal ConcurrentDictionary _requestedFontKeys = new();
internal ChartAnnotations _annotations = new();
internal DomRect _elementOffset = new();
/*To store the SVGElement's dimensions value.*/
@@ -1244,9 +1248,9 @@ private async Task GetOtherLanguageCharSizeAsync(bool _updateDataSource)
/// The text to analyze.
/// The font options for the text.
/// The collection to populate with distinct character keys.
- private static void GetDistinctCharacter(string text, ChartFontOptions font, List distinctKeys)
+ private void GetDistinctCharacter(string text, ChartFontOptions font, List distinctKeys)
{
- ChartHelper.GetDistinctCharacter(text, font, distinctKeys);
+ ChartHelper.GetDistinctCharacter(text, font, distinctKeys, this);
}
///
@@ -1271,7 +1275,7 @@ private async Task LoadCharacterDictionaryAsync(List distinctKeys)
Dictionary charSizeList = JsonSerializer.Deserialize>(result) ?? null!;
foreach (KeyValuePair charSize in charSizeList)
{
- _ = ChartHelper.SizePerCharacter.TryAdd(charSize.Key, new Size { Width = charSize.Value.X, Height = charSize.Value.Y });
+ _ = _fontSizeCache.TryAdd(charSize.Key, new Size { Width = charSize.Value.X, Height = charSize.Value.Y });
}
}
@@ -1832,10 +1836,9 @@ internal async Task GetCharSizeListAsync(List fontKeys)
List uniqueKeys = [];
foreach (string fontKey in fontKeys)
{
- if (!ChartHelper.ChartFontKeys.Contains(fontKey))
+ if (_requestedFontKeys.TryAdd(fontKey, 0))
{
uniqueKeys.Add(fontKey);
- ChartHelper.ChartFontKeys.Add(fontKey);
}
}
@@ -1855,7 +1858,7 @@ internal async Task GetCharSizeListAsync(List fontKeys)
int i = 33, j = 0;
foreach (string width in result_2)
{
- _ = ChartHelper.SizePerCharacter.TryAdd(Convert.ToChar(i) + Constants.Underscore + uniqueKeys[j], new Size { Width = Convert.ToInt16(width, null), Height = 133 });
+ _ = _fontSizeCache.TryAdd(Convert.ToChar(i) + Constants.Underscore + uniqueKeys[j], new Size { Width = Convert.ToInt16(width, null), Height = 133 });
i++;
if (i > 590)
{
@@ -2590,17 +2593,6 @@ protected override void OnParametersSet()
PushSubcomponent();
}
- ///
- /// Performs cleanup operations when the component is being disposed.
- ///
- ///
- [EditorBrowsable(EditorBrowsableState.Never)]
- [Browsable(false)]
- protected override ValueTask DisposeAsyncCore()
- {
- return base.DisposeAsyncCore();
- }
-
#endregion
#region Protected Methods
diff --git a/src/Components/Charts/Common/ChartUtils/ChartHelper.cs b/src/Components/Charts/Common/ChartUtils/ChartHelper.cs
index 76d12ef..fd27661 100644
--- a/src/Components/Charts/Common/ChartUtils/ChartHelper.cs
+++ b/src/Components/Charts/Common/ChartUtils/ChartHelper.cs
@@ -1,13 +1,12 @@
+using System.Collections.ObjectModel;
+using System.Drawing;
using System.Dynamic;
+using System.Globalization;
using System.Text.Json;
using System.Text.RegularExpressions;
-using Microsoft.AspNetCore.Components.Rendering;
-using System.Drawing;
-using System.Globalization;
using Microsoft.AspNetCore.Components;
+using Microsoft.AspNetCore.Components.Rendering;
using Syncfusion.Blazor.Toolkit.Internal;
-using System.Collections.ObjectModel;
-using System.Collections.Concurrent;
namespace Syncfusion.Blazor.Toolkit.Charts.Internal
{
@@ -28,34 +27,6 @@ public class ChartHelper
#region Properties
- ///
- /// Gets a process-wide, thread-safe cache of measured character sizes indexed by font characteristics.
- ///
- ///
- ///
- /// Glyph metrics for a given (character, FontWeight, FontStyle, FontFamily) tuple are deterministic
- /// for the lifetime of the process (the JavaScript side measures the actual rendered glyph), so the cache
- /// is shared across all circuits and chart instances on this process to avoid redundant JS interop.
- ///
- ///
- /// Do NOT clear this cache on chart disposal: clearing on one chart's teardown would invalidate entries
- /// still in use by every other live chart on the process, forcing them to re-measure. The cache is
- /// intrinsically bounded by the set of characters × font weights × font styles × font families
- /// the process ever renders, which is small in practice.
- ///
- ///
- internal static ConcurrentDictionary SizePerCharacter { get; } = new ConcurrentDictionary();
-
- ///
- /// Gets the set of font keys for which character sizes have already been requested from JavaScript.
- ///
- ///
- /// Mirrors keys minus the character prefix; used to short-circuit
- /// duplicate JS-interop requests on the same circuit. See the remarks on
- /// for why this is process-wide and not cleared per-chart.
- ///
- internal static List ChartFontKeys { get; } = new List();
-
///
/// Gets a read-only lookup table mapping characters to their approximate pixel widths.
///
@@ -118,6 +89,33 @@ private static Size MeasureBreakText(string originalText, ChartFontOptions font)
return new Size(width, height);
}
+ ///
+ /// Measures multi-line text (split by <br>) using a chart instance's cache to avoid process-wide memory leak.
+ ///
+ /// The text that may contain line breaks.
+ /// The font settings used during measurement.
+ /// The chart instance owning the cache.
+ /// The measured size encompassing all lines.
+ private static Size MeasureBreakText(string originalText, ChartFontOptions font, object chart)
+ {
+ originalText = originalText.Replace(" ", " ", StringComparison.InvariantCulture);
+ List textCollection = originalText.Split(" ").ToList();
+ double width = 0;
+ double height = 0;
+
+ foreach (string text in textCollection)
+ {
+ Size size = MeasureText(text, font, chart);
+ if (size is not null)
+ {
+ width = Math.Max(width, size.Width);
+ height += size.Height;
+ }
+ }
+
+ return new Size(width, height);
+ }
+
///
/// Retrieves the cached character size for a font and caches the value if missing.
///
@@ -126,27 +124,55 @@ private static Size MeasureBreakText(string originalText, ChartFontOptions font)
/// The measured character size.
private static Size GetCharSize(char character, ChartFontOptions font)
{
+ if (FontWidthLookup.TryGetValue(character, out double charWidth))
+ {
+ return new Size { Width = charWidth * 6.25, Height = 130 };
+ }
+
+ return new Size { Width = 50, Height = 130 };
+ }
+
+ ///
+ /// Retrieves the cached character size for an SfChart caller, or computes the fallback value for non-chart callers.
+ ///
+ ///
+ /// This method uses instance-level caching (per SfChart) to keep font measurements isolated to the chart
+ /// lifetime and avoid unbounded process-wide memory retention. Non-chart callers use the same approximate
+ /// dimensions without retaining them in a shared cache.
+ ///
+ ///
+ /// Sharing measurements across charts could reduce repeated work, but a bounded shared cache would be a
+ /// separate optimization with explicit capacity and eviction behavior.
+ ///
+ /// The chart instance owning the cache.
+ /// The character to measure.
+ /// The font settings used during measurement.
+ /// The measured character size.
+ private static Size GetCharSize(object chart, char character, ChartFontOptions font)
+ {
+ var sfChart = chart as Charts.SfChart;
+ if (sfChart is null)
+ return GetCharSize(character, font);
+
+ var fontCache = sfChart._fontSizeCache;
string key = character + Constants.Underscore + font.FontWeight + Constants.Underscore + font.FontStyle + Constants.Underscore + font.FontFamily;
try
{
- if (SizePerCharacter.TryGetValue(key, out Size? charSize))
+ if (fontCache.TryGetValue(key, out Size? charSize))
{
return charSize ?? null!;
}
double charWidth;
if (FontWidthLookup.TryGetValue(character, out charWidth))
{
- // Create the new size for this character
Size newSize = new Size { Width = charWidth * 6.25, Height = 130 };
- // Thread-safe add operation using GetOrAdd (available in all .NET versions)
- Size result = SizePerCharacter.GetOrAdd(key, newSize);
+ Size result = fontCache.GetOrAdd(key, newSize);
return result ?? null!;
}
else
{
- // Default size for characters not in Font dictionary
Size defaultSize = new Size { Width = 50, Height = 130 };
- Size result = SizePerCharacter.GetOrAdd(key, defaultSize);
+ Size result = fontCache.GetOrAdd(key, defaultSize);
return result ?? null!;
}
}
@@ -1163,10 +1189,44 @@ internal static Size MeasureText(string text, ChartFontOptions font)
double width = 0, height = 0, fontSize = PixelToNumber(font.Size);
Size charSize;
+ for (int i = 0; i < text.Length; i++)
+ {
+ charSize = GetCharSize(text[i], font);
+ if (charSize is not null)
+ {
+ width += charSize.Width > 0 ? charSize.Width : 100;
+ height = Math.Max(charSize.Height, height);
+ }
+ }
+
+ return new Size((width * fontSize) / 100, (height * fontSize) / 100);
+ }
+
+ ///
+ /// Measures text using a chart instance's font cache to avoid process-wide memory accumulation.
+ ///
+ ///
+ /// This overload uses the chart's instance-level _fontSizeCache, ensuring per-circuit/per-chart memory isolation.
+ ///
+ /// The text to measure.
+ /// The font options for the text.
+ /// The chart instance owning the cache.
+ /// The measured text size.
+ internal static Size MeasureText(string text, ChartFontOptions font, object chart)
+ {
+ if (text.Contains(" ", StringComparison.InvariantCulture) || text.Contains(" ", StringComparison.InvariantCulture))
+ {
+ return MeasureBreakText(text, font, chart);
+ }
+
+ double width = 0, height = 0, fontSize = PixelToNumber(font.Size);
+ Size charSize;
+
if (IsRTLText(text))
{
string key = text + Constants.Underscore + font.FontWeight + Constants.Underscore + font.FontStyle + Constants.Underscore + font.FontFamily;
- if (SizePerCharacter.TryGetValue(key, out Size? value))
+ var sfChart = chart as Charts.SfChart;
+ if (sfChart is not null && sfChart._fontSizeCache.TryGetValue(key, out Size? value))
{
charSize = value;
return new Size(charSize.Width * (fontSize / 100), charSize.Height * (fontSize / 100));
@@ -1175,7 +1235,7 @@ internal static Size MeasureText(string text, ChartFontOptions font)
for (int i = 0; i < text.Length; i++)
{
- charSize = GetCharSize(text[i], font);
+ charSize = GetCharSize(chart, text[i], font);
if (charSize is not null)
{
width += charSize.Width > 0 ? charSize.Width : 100;
@@ -2358,7 +2418,8 @@ internal static List
[Parameter]
public string AccessibilityText { get; set; } = string.Empty;
+
+ ///
+ /// Gets the effective tabindex value to emit on the element. When the rectangle is hidden
+ /// from assistive technology ( == "true"), the attribute is
+ /// suppressed so the node is not pulled into the keyboard tab order with no accessible name.
+ ///
+ private string EffectiveTabIndex =>
+ string.Equals(AriaHidden, "true", System.StringComparison.OrdinalIgnoreCase) ? string.Empty : TabIndex;
+
+ ///
+ /// Gets the effective ARIA role to emit on the element. When the rectangle is hidden
+ /// from assistive technology ( == "true"), the role="img"
+ /// attribute is suppressed — advertising an image role on a node that is hidden from AT
+ /// is contradictory and trips the axe aria-allowed-attr rule.
+ ///
+ private string EffectiveRole =>
+ string.Equals(AriaHidden, "true", System.StringComparison.OrdinalIgnoreCase) ? string.Empty : "img";
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/src/Components/Charts/Common/Utils/Helper.cs b/src/Components/Charts/Common/Utils/Helper.cs
index d68cc79..1d1469a 100644
--- a/src/Components/Charts/Common/Utils/Helper.cs
+++ b/src/Components/Charts/Common/Utils/Helper.cs
@@ -1,4 +1,6 @@
-using System.Dynamic;
+using System;
+using System.Collections.Generic;
+using System.Dynamic;
using System.Globalization;
using System.Text.Json;
@@ -75,5 +77,90 @@ public static double StringToNumber(string size, double containerSize)
: double.NaN;
}
#endregion
+
+ #region Nested Validator
+
+ ///
+ /// Validates a string value against the WAI-ARIA 1.2 abstract role list.
+ ///
+ ///
+ ///
+ /// The Chart component family exposes an AccessibilityRole string parameter
+ /// on six different types (,
+ /// ,
+ /// ,
+ /// ,
+ /// ,
+ /// ,
+ /// ). The role is
+ /// forwarded verbatim into the DOM role attribute, so an unknown
+ /// value (for example "count") becomes an invalid ARIA role at
+ /// runtime. This validator runs at the parameter setter and rejects
+ /// unknown non-empty values with so the
+ /// bug is caught at component initialization rather than at audit time.
+ ///
+ ///
+ /// Empty / null values are always considered valid — the component's
+ /// own renderers fall back to "region" when the role is unset,
+ /// and existing valid values (region, status, group, img, heading,
+ /// button, link, list, listitem, navigation, presentation, none, etc.)
+ /// are unchanged.
+ ///
+ ///
+ internal static class AriaRoleValidator
+ {
+ // WAI-ARIA 1.2 abstract roles, compared case-insensitively.
+ // Sourced from
+ // https://www.w3.org/TR/wai-aria-1.2/#role_definitions — the same
+ // set used by the audit's Full Assessment spec.
+ private static readonly HashSet ValidRoles = new HashSet(StringComparer.OrdinalIgnoreCase)
+ {
+ "alert", "alertdialog", "application", "article", "banner",
+ "button", "cell", "checkbox", "columnheader", "combobox",
+ "complementary", "contentinfo", "definition", "dialog",
+ "directory", "document", "feed", "figure", "form", "grid",
+ "gridcell", "group", "heading", "img", "input", "link", "list",
+ "listbox", "listitem", "log", "main", "marquee", "math", "menu",
+ "menubar", "menuitem", "menuitemcheckbox", "menuitemradio",
+ "navigation", "none", "note", "option", "presentation",
+ "progressbar", "radio", "radiogroup", "region", "row", "rowgroup",
+ "rowheader", "scrollbar", "search", "searchbox", "separator",
+ "slider", "spinbutton", "status", "switch", "tab", "table",
+ "tablist", "tabpanel", "term", "textbox", "timer", "toolbar",
+ "tooltip", "tree", "treegrid", "treeitem"
+ };
+
+ ///
+ ///
+ /// Ensures the supplied role string is a valid WAI-ARIA abstract role.
+ ///
+ ///
+ /// The role string supplied by the consumer. May be null or empty.
+ /// The parameter name to surface in any thrown exception.
+ ///
+ /// Thrown when is non-empty and is not a recognized
+ /// WAI-ARIA role. Empty / null values are accepted unchanged.
+ ///
+ internal static void EnsureValidRole(string? value, string paramName)
+ {
+ if (string.IsNullOrEmpty(value))
+ {
+ return;
+ }
+
+ if (!ValidRoles.Contains(value))
+ {
+ throw new ArgumentException(
+ $"'{value}' is not a valid WAI-ARIA role for {paramName}. " +
+ "Use one of the roles listed at " +
+ "https://www.w3.org/TR/wai-aria-1.2/#role_definitions " +
+ "(for example: region, status, group, img, heading, button, link, " +
+ "list, listitem, navigation, presentation, none). " +
+ "Leave the property empty to use the component default.",
+ paramName);
+ }
+ }
+ }
+ #endregion
}
-}
\ No newline at end of file
+}
diff --git a/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/Annotation.razor b/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/Annotation.razor
index 23f95d5..1d470e5 100644
--- a/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/Annotation.razor
+++ b/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/Annotation.razor
@@ -7,7 +7,7 @@
Checking Chart Annotation
-
+
Highest Medal Count
@@ -71,4 +71,4 @@
font-size: 18px;
font-weight: 600;
}
-
\ No newline at end of file
+
diff --git a/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/ChartBasics.razor b/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/ChartBasics.razor
index dcd9032..8a19dda 100644
--- a/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/ChartBasics.razor
+++ b/tests/Syncfusion.Blazor.Playwright.Test/Blazor.Toolkit.Playwright.Samples/Components/Pages/Charts/Others/ChartBasics.razor
@@ -20,7 +20,7 @@