diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/SKILL.md b/.github/skills/syncfusion-blazor-toolkit-charts/SKILL.md index d850dfc..2267f1d 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/SKILL.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/SKILL.md @@ -1,643 +1,594 @@ --- +license: MIT name: syncfusion-blazor-toolkit-charts -description: Implement Syncfusion Blazor Chart (SfChart) component for core data visualizations. Use this when creating line, area, column/bar, scatter, bubble, spline and stacking chart variants in Blazor applications. +description: > + Implement the Syncfusion Blazor Toolkit SfChart component (namespace + Syncfusion.Blazor.Toolkit.Charts; shipped inside NuGet package + Syncfusion.Blazor.Toolkit — there is no separate + Syncfusion.Blazor.Toolkit.Charts package). + USE FOR: line, column, bar, area, scatter, bubble, spline, and stacking + series; category / numeric / DateTime / logarithmic axes; dual axes and + multiple panes; tooltip, crosshair, zoom, pan, selection; trend lines, + strip lines; ARIA, keyboard, RTL, i18n; live data via SfDataManager; + data editing. + REQUIRES interactive render mode for tooltip / crosshair / zoom / + selection / live updates. Static SSR renders the SVG frame only + (default 600×450); for interactivity place the chart in an interactive + child component or switch the page to Server / WebAssembly / Auto. + Data binding requires List (or SfDataManager) properties whose names + match the XName / YName / Size strings exactly (case-sensitive). + DO NOT USE FOR: any control outside Syncfusion.Blazor.Toolkit (Grid, + Scheduler, Diagram, Maps belong to other Syncfusion products — stop + and ask); date / time inputs (syncfusion-blazor-toolkit-calendars); + form fields, checkbox, radio, switch (syncfusion-blazor-toolkit-inputs); + buttons only (syncfusion-blazor-toolkit-buttons); SfDialog or + SfTooltip hosting a chart (syncfusion-blazor-toolkit-popups); + loading spinner overlay (syncfusion-blazor-toolkit-notifications). +compatibility: .NET 8+. Render modes: Server, WebAssembly, Auto (interactive) — interactive features require an interactive circuit. Static SSR renders the SVG frame only. metadata: author: "Syncfusion Inc" version: "1.0.0" category: "Data Visualization" --- -# Implementing Syncfusion Blazor Charts - -**NuGet:** `Syncfusion.Blazor.Toolkit` + `Syncfusion.Blazor.Themes` -**Namespace:** `Syncfusion.Blazor.Toolkit` - -A comprehensive guide for implementing the Syncfusion Blazor Chart component to create interactive, feature-rich data visualizations in Blazor applications. The Chart component supports core series types (line, area, column/bar, scatter, bubble, spline) and stacking/step/spline variants, multiple axes, interactivity, and customization. - -## When to Use This Skill - -Use this skill when you need to: -- **Create data visualizations** in Blazor applications (line, column, bar, area, etc.) -- **Display comparative data** with stacked or grouped charts -- **Add interactive features** like tooltips, zooming, crosshair, selection -- **Customize chart appearance** with themes, gradients, annotations -- **Handle dynamic data** with live updates and data editing -- **Implement accessible charts** with ARIA support and internationalization - -## Component Overview - -The Syncfusion Blazor Chart component is a powerful data visualization tool that provides: - -- **33+ Chart Types:** Line, Column, Bar, Area, Spline, Scatter, Bubble, and more -- **Multiple Axes:** Support for category, numeric, datetime, and logarithmic axes -- **Rich Interactivity:** Zooming, panning, crosshair, trackball, tooltips, selection -- **Data Binding:** Work with List, DataManager, dynamic updates, and live data -- **Visual Elements:** Markers, data labels, annotations, legends, gradients -- **Advanced Features:** Technical indicators, trend lines, strip lines, multiple panes -- **Accessibility:** Full ARIA support, keyboard navigation, localization, RTL -- **Customization:** Themes, responsive design, print support, adaptive layout - -## Documentation and Navigation Guide - -### Complete API Reference - -📄 **Read:** [references/api-reference.md](references/api-reference.md) - -**CRITICAL: Use this reference FIRST for all API-related questions** - -Use this authoritative API reference when: -- Looking up correct enum values (ChartSeriesType, ValueType, SelectionMode, etc.) -- Finding public method signatures (RefreshAsync, ExportAsync, ShowTooltip, etc.) -- Verifying property names and types -- Generating code samples -- Troubleshooting API-related issues - -Topics covered: -- Complete list of SfChart public methods with signatures -- All chart enumerations with correct values -- Key component classes and their properties -- Method usage examples -- Common patterns and best practices - -**Key Points:** -- All enum values are **exact** - do not use variations -- Method names follow C# conventions (e.g., `RefreshAsync` not `Refresh`) -- Always use `@ref` to access chart instance for method calls -- Namespace: `Syncfusion.Blazor.Toolkit.Charts` - ---- - -### Getting Started - -📄 **Read:** [references/getting-started.md](references/getting-started.md) - -Use this when: -- Setting up a new Blazor Chart project -- Installing NuGet packages and configuring services -- Creating your first chart component -- Understanding basic chart structure and data binding -- Working with Visual Studio, VS Code, or .NET CLI - -Topics covered: -- Installation and prerequisites -- Package setup (Syncfusion.Blazor.Toolkit.Charts) -- Namespace imports and service registration -- Script references -- Basic chart implementation -- Simple data binding example - ---- - -### Chart Types - -#### Common Chart Types - -📄 **Read:** [references/chart-types-common.md](references/chart-types-common.md) - -Use this for frequently-used chart types: -- Line charts for trend visualization -- Area charts for showing magnitude over time -- Column charts for categorical comparisons -- Bar charts for horizontal comparisons -- Spline charts for smooth curves -- Step charts for stepped data progression - -Topics covered: -- Line, Area, Column, Bar chart implementations -- Spline and Spline Area variations -- Step Line and Step Area patterns -- When to use each chart type -- Configuration and customization -- Multi-series examples - -#### Specialized Chart Types - -📄 **Read:** [references/chart-types-specialized.md](references/chart-types-specialized.md) - -Use this for specialized visualization needs: -- Stacked charts (Stack Area/Bar/Column/Line, 100% variants) -- Scatter and Bubble charts -- Multicolored Line / Multicolored Area -- Vertical chart orientation - -Topics covered: -- Financial chart patterns and configurations -- Statistical analysis chart types -- Stacking modes (normal vs 100%) -- Range visualization techniques -- Circular chart layouts -- XY scatter relationships -- Chart orientation options - ---- - -### Axes and Data Configuration - -📄 **Read:** [references/axes-and-scales.md](references/axes-and-scales.md) - -Use this when: -- Configuring axis types (category, numeric, datetime, logarithmic) -- Customizing axis appearance and behavior -- Formatting axis labels and values -- Working with multiple axes -- Setting axis ranges and intervals - -Topics covered: -- Category axis for discrete data -- Numeric axis for continuous values -- DateTime axis for time-series data -- Logarithmic axis for exponential data -- Axis customization (title, range, interval) -- Label formatting, rotation, and positioning -- Multiple axis configuration -- Inverse and opposed axes - -📄 **Read:** [references/data-handling.md](references/data-handling.md) - -Use this when: -- Binding data sources to charts -- Adding, removing, or updating data dynamically -- Enabling data editing -- Sorting chart data -- Working with live or streaming data - -Topics covered: -- Data source binding (List, DataManager) -- Dynamic data operations -- Data editing functionality -- Chart sorting options -- Real-time data updates -- Data serialization patterns - ---- - -### Visual Elements - -📄 **Read:** [references/visual-elements.md](references/visual-elements.md) - -Use this when: -- Adding data markers to chart points -- Displaying data labels on series -- Creating custom label templates -- Adding annotations (text, shapes, images) -- Applying gradient fills - -Topics covered: -- Data marker types and customization -- Data label visibility and formatting -- Label positioning strategies -- Data label templates -- Last data label highlighting -- Chart annotations (text, shapes, images) -- Gradient color fills - -📄 **Read:** [references/legend.md](references/legend.md) - -Use this when: -- Enabling and configuring chart legend -- Positioning legend (top, bottom, left, right) -- Customizing legend appearance -- Implementing legend click behavior -- Creating custom legend templates - -Topics covered: -- Legend visibility and positioning -- Legend shape and text customization -- Interactive legend (toggle series) -- Legend pagination -- Custom legend templates -- Legend alignment options - ---- - -### Interactive Features - -📄 **Read:** [references/interactive-features.md](references/interactive-features.md) - -Use this when: -- Enabling tooltips with custom formatting -- Adding crosshair or trackball for data tracking -- Implementing point, series, or cluster selection -- Enabling zooming and panning -- Creating interactive user experiences - -Topics covered: -- Tooltip configuration and templates -- Crosshair and trackball features -- Selection modes and patterns -- Zoom types (selection, pinch, mousewheel) -- Zoom toolbar configuration -- Pan functionality -- User interaction events - ---- - -### Customization and Appearance - -📄 **Read:** [references/appearance-styling.md](references/appearance-styling.md) - -Use this when: -- Customizing chart appearance and themes -- Setting chart dimensions and sizing -- Configuring responsive/adaptive layout -- Enabling print functionality -- Styling background, borders, and margins - -Topics covered: -- Chart appearance customization -- Theme configuration -- Chart dimensions and sizing -- Responsive design patterns -- Adaptive layout for mobile -- Print support -- Background and border styling -- Gradient customization - -📄 **Read:** [references/advanced-features.md](references/advanced-features.md) - -Use this when: -- Adding technical indicators (EMA, SMA, RSI, etc.) -- Implementing trend lines (linear, exponential, polynomial) -- Creating strip lines (horizontal/vertical bands) -- Using multiple panes (sub-charts) -- Handling empty points - -Topics covered: -- Technical indicators for financial charts -- Trend line types and configuration -- Strip line patterns -- Multiple pane layouts -- Empty point handling strategies -- Row and column definitions - ---- - -### Accessibility and Internationalization - -📄 **Read:** [references/accessibility-internationalization.md](references/accessibility-internationalization.md) - -Use this when: -- Implementing accessible charts (ARIA, keyboard nav) -- Configuring advanced accessibility features -- Enabling internationalization (i18n) -- Setting up localization (l10n) -- Supporting RTL layouts - -Topics covered: -- Accessibility features and ARIA support -- Keyboard navigation patterns -- Advanced accessibility configuration -- Internationalization setup -- Localization resources -- RTL support -- Screen reader compatibility - ---- - -### Events +# Syncfusion Blazor Toolkit — Charts + +**NuGet:** `Syncfusion.Blazor.Toolkit` *(the `Syncfusion.Blazor.Toolkit.Charts` +package referenced in legacy docs does not exist — the namespace +`Syncfusion.Blazor.Toolkit.Charts` lives inside `Syncfusion.Blazor.Toolkit`)* +**Namespace:** `Syncfusion.Blazor.Toolkit.Charts` +**Component:** `SfChart` + +## Purpose + +Implement `SfChart` to render any data visualization the `Syncfusion.Blazor.Toolkit` +package supports. Outcome: a working chart in a Blazor Server, WebAssembly, +or Auto app, bound to a `List` or `SfDataManager`, with the common +gotchas (enum fully-qualified, `ChartStriplines` plural, `ChartCrosshairLine` +narrow surface) already handled. + +## When NOT to use this skill + +Skill conflicts and routing errors are the #1 source of bad agent output. +Re-route before you start. + +| If the task is… | Use this skill instead | +|-----------------|------------------------| +| Single date/time picker (`SfDatePicker`, `SfCalendar`, `SfTimePicker`) | `syncfusion-blazor-toolkit-calendars` | +| TextBox, NumericTextBox, CheckBox, Radio, Switch | `syncfusion-blazor-toolkit-inputs` | +| Buttons, button groups, toggle buttons | `syncfusion-blazor-toolkit-buttons` | +| Modal dialogs (SfDialog) or hover tooltips (SfTooltip) | `syncfusion-blazor-toolkit-popups` | +| Loading spinners overlaid on a chart (SfSpinner) | `syncfusion-blazor-toolkit-notifications` | +| Grid, Scheduler, Diagram, Maps, Kanban (different Syncfusion products) | No skill in this repo — stop and ask | + +If the task mixes a chart + another control, load this skill **and** the +sibling — never start a chart inside a `SfDialog` without reading +`syncfusion-blazor-toolkit-popups`. + +### When you need to compose `SfChart` with another control + +| User phrase | Pair this skill with | Why the sibling is needed | +|-------------|----------------------|--------------------------| +| "Refresh the chart" / "Re-fetch button" | `syncfusion-blazor-toolkit-buttons` | `SfButton` with `OnClick="async () => await ChartRef.RefreshAsync()"` | +| "PNG export" / "Download chart" | `syncfusion-blazor-toolkit-buttons` + `references/api-reference.md` | Toolbar item triggers a built-in export method via `@ref` | +| "Show spinner while data loads" | `syncfusion-blazor-toolkit-notifications` | Overlay `SfSpinner` on the chart container; toggle via `Visible` | +| "Filter the chart by date range" | `syncfusion-blazor-toolkit-calendars` | Two `SfDatePicker`s bound to filter parameters drive the data source | +| "Confirm before deleting a series" | `syncfusion-blazor-toolkit-popups` | `SfDialog` hosts the chart and gates the destructive click | +| "Search by name" | `syncfusion-blazor-toolkit-inputs` | `SfTextBox OnChange` filters the `List` bound to `DataSource` | +| "Light/dark mode toggle" | `references/appearance-styling.md` | Drives `Theme` on `SfChart` from a flag in `@code` (no extra control) | + +The chart is the source of truth for **`SfChart` itself**; the sibling +skill owns the surrounding control. Load both. + +## Step 1 — Read project instructions + +Before scaffolding or modifying `SfChart`, read `codestudio-instructions.md` +at the repo root. Then read these four files under `.codestudio/knowledge/` +in order: + +1. `.codestudio/knowledge/architecture.md` — module layout, per-component + partial-class split, JS interop pattern, SCSS pipeline. +2. `.codestudio/knowledge/conventions.md` — naming, Allman braces, no + `private`, doc-comments, file organization. +3. `.codestudio/knowledge/stack.md` — `net8.0` / `net9.0` / `net10.0` + targets, bUnit + Playwright test stack. +4. `.codestudio/knowledge/boundaries.md` — Always do / Ask first / Never + do rules. **Hard-refuse any action that violates the "Never do" list.** + These rules supersede anything in this skill. + +(Readers of this skill from a consumer-app workspace — i.e. writing a Blazor +app that *uses* `Syncfusion.Blazor.Toolkit` rather than modifying the toolkit +itself — can skip this step.) + +## Step 2 — Pick the right series type + +The `ChartSeriesType` enum currently exposes **21 members** (declared in +order at `src/Base/Enumeration.cs`): + +`Line`, `Column`, `Area`, `Bar`, `StackingColumn`, `StackingArea`, +`StackingLine`, `StackingBar`, `StackingStepArea`, `StepLine`, `StepArea`, +`SplineArea`, `Scatter`, `Spline`, `StackingColumn100`, `StackingBar100`, +`StackingLine100`, `StackingArea100`, `Bubble`, `MultiColoredLine`, +`MultiColoredArea`. + +Pick from this discriminator, not from a marketing count: + +| Data shape | Pick | `ChartSeriesType` | +|------------|------|-------------------| +| Categorical comparison (one bar per item) | Column (vertical) or Bar (horizontal) | `Column`, `Bar` | +| Trend over time/sequence | Line or Spline | `Line`, `Spline` | +| Magnitude over time (filled) | Area or SplineArea | `Area`, `SplineArea` | +| Step changes | Step Line / Step Area | `StepLine`, `StepArea` | +| Step accumulations (filled, stepped) | Stacking Step Area | `StackingStepArea` | +| Part-to-whole, stacked | StackingColumn/Bar/Area/Line + the `…100` variants | `StackingColumn`, `StackingBar`, `StackingArea`, `StackingLine`, `StackingColumn100`, `StackingBar100`, `StackingArea100`, `StackingLine100` | +| Two-variable correlation, point cloud | Scatter | `Scatter` | +| Three-variable (size matters) | Bubble | `Bubble` | +| Per-segment color | MultiColoredLine / MultiColoredArea | `MultiColoredLine`, `MultiColoredArea` | + +Types in this repo today: **21** (line + column + area + bar + steps + +splines + scatter + bubble + multi-coloured + stacking variants). Pie, +candle / OHLC / HiLo, polar / radar, range / area-spline variants are +**not** part of the current toolkit — if the task requires them, stop +and confirm with the user before scaffolding. Detail lives in +`references/chart-types-specialized.md`. + +## Step 3 — Pick render mode and register services + +Charts are interactive components: tooltip / crosshair / zoom / selection +need an interactive circuit. Pick from the table below; for the +`Program.cs` registration snippet and SCSS pipeline plumbing, load +`references/getting-started.md`. + +| Data source | Render mode | Why | +|-------------|-------------|-----| +| Static `List` baked into the page | Server, WebAssembly, or Auto (interactive) | SSR renders the SVG frame at defaults (600×450); JS loads interactively for tooltips, zoom, export | +| Pure SSR (no JS) | Works for static-frame rendering only | Tooltip / crosshair / selection / zoom JS features need interactive | +| `IQueryable` / live-streaming binding | Server, WebAssembly, or Auto | Needs `OnAfterRenderAsync` to apply updates — Static SSR can't refresh | +| `SfDataManager` calling a remote API | Auto or WebAssembly | The API call crosses the runtime boundary | +| Toolkit services available app-wide | Server (one DI container) / Auto (register in **both** projects) | Render-mode aware | + +Minimal registration (no JS script tags needed — the chart loads its JS +modules from `_content/Syncfusion.Blazor.Toolkit/scripts/*` itself): + +```csharp +// Program.cs +using Syncfusion.Blazor.Toolkit; + +var builder = WebApplication.CreateBuilder(args); +builder.Services.AddSyncfusionBlazorToolkit(options => +{ + options.EnableRtl = false; + options.Animation = GlobalAnimationMode.Enable; +}); +``` -📄 **Read:** [references/events.md](references/events.md) +For Auto/WASM with prerendering, call `AddSyncfusionBlazorToolkit()` in +**both** `Program.cs` files (server bootstrap and `.Client` bootstrap). +Full walkthrough, including the JS-module loader and the SCSS pipeline +notes: `references/getting-started.md`. -Use this when: -- Handling chart lifecycle events -- Responding to user interactions (clicks, mouse events) -- Listening to axis, series, or point events -- Implementing custom event handlers -- Triggering actions on zoom, pan, or selection +## Step 3.5 — Apply a theme (C# enum, *not* CSS variables) -Topics covered: -- Chart load and render events -- Point and series events -- Mouse events (click, move, leave) -- Axis label render events -- Legend events -- Zoom and pan events -- Selection events -- Event handler patterns +`SfChart` has its own in-C# theme pipeline, declared in +`src/Base/Enumeration.cs`. **Theme colors come from the C# `Theme` +parameter** — there is no CSS-variable layer. The `Theme` enum currently +exposes **two values**: ---- +| `Theme` value | When to use | +|---|---| +| `Syncfusion.Blazor.Toolkit.Theme.Fluent` *(default)* | Light-mode app, default look | +| `Syncfusion.Blazor.Toolkit.Theme.FluentDark` | Dark-mode app, darkmode toggle | -### Practical Examples and How-To Guides - -📄 **Read:** [references/practical-examples.md](references/practical-examples.md) - -Use this for common implementation scenarios: -- Adding/removing series dynamically -- Hiding axes programmatically -- Converting milliseconds to datetime -- Updating points dynamically -- Implementing lazy loading -- Creating live/real-time charts -- Getting selected data -- Synchronizing multiple charts -- Adding threshold lines -- Custom tooltip tables - -Topics covered: -- Dynamic series management -- Axis visibility control -- Date conversion techniques -- Dynamic point updates -- Lazy loading patterns -- Live chart implementation -- Selection data retrieval -- Chart synchronization -- Threshold line implementation -- Custom tooltip tables +```razor + + + + +``` ---- +> **Older docs reference `Theme.Material`, `Theme.Bootstrap5`, +> `Theme.Tailwind`, or `Theme.HighContrast`.** Those values are **not +> part of `Syncfusion.Blazor.Toolkit.Theme`**. Non-existent values +> compile to silence and render nothing — pick `Theme.Fluent` or +> `Theme.FluentDark`. -## Public Methods Reference +Runtime theme switching (light/dark toggle): -The `SfChart` component provides several public methods for programmatic control. Always use `@ref` to access these methods: +```razor + + … + +``` -### Essential Methods +`Theme` re-renders the chart in place — no `RefreshAsync` call required. +SCSS pipeline notes (`:focus-visible`, legend-cursor, stack-label rules) +live in `references/getting-started.md`. + +## Step 4 — Gather inputs + +1. **Render mode**: SSR renders the SVG frame at default 600×450; the + JS module loader (chart.js, svgbase.js, touch.js, animation.js) is + wired in `SfChart.razor.LifeCycle.cs` and runs once an interactive + circuit is active. Tooltip / crosshair / zoom / selection only work + under Server, WebAssembly, or Auto render modes. A pure-Static-SSR + parent will render the chart frame but interactions stay inert. + If a host page is Static SSR, place the chart in an interactive + child component (per-page or per-component `@rendermode`). +2. **`Program.cs` registration**: confirm `AddSyncfusionBlazorToolkit()` + has been added (Step 3). +3. **NuGet**: `Syncfusion.Blazor.Toolkit` is referenced in the project + file. (The NuGet ID is *not* `Syncfusion.Blazor.Toolkit.Charts` — + that name only appears in the namespace.) +4. **Import**: `using Syncfusion.Blazor.Toolkit.Charts` (typically via + `_Imports.razor`). +5. **Where to drop it**: full-page route (`Pages/Foo.razor`) inside an + interactive render mode. +6. **Data shape**: `record`/`class` with primitive `XName`/`YName`/`Size` + properties (case-sensitive). Property names must match the + `XName`/`YName` strings exactly. +7. **Container size**: parent CSS usually needs an explicit height + (e.g. `height: 400px`); % sizes need a sized parent. + +## Step 5 — Scaffold the chart + +The order matters. After Steps 1–4, compose in this sequence: + +1. `` + `` + ``. +2. Set `ValueType` on every axis (Category / Double / DateTime / Logarithmic). +3. Bind ``. +4. Layer interactivity only when asked (Step 6). +5. Validate (Step 8). ```razor - - +@page "/chart-demo" +@using Syncfusion.Blazor.Toolkit.Charts + + + + + + + + + + + @code { - SfChart ChartRef; - - // Refresh the chart - async Task RefreshChart() => await ChartRef.RefreshAsync(); - - // Export the chart - async Task ExportChart() => await ChartRef.ExportAsync(ExportType.PNG, "chart.png"); - - // Print the chart - async Task PrintChart() => await ChartRef.PrintAsync(); - - // Show/Hide tooltip - void ShowChartTooltip() => ChartRef.ShowTooltip("January", 35); - void HideChartTooltip() => ChartRef.HideTooltip(); - - // Show/Hide crosshair - void ShowChartCrosshair() => ChartRef.ShowCrosshair(100, 50); - void HideChartCrosshair() => ChartRef.HideCrosshair(); - - // Selection control - void ClearSelections() => ChartRef.ClearSelection(); - - // Sorting - void SortData() => ChartRef.Sort("YValue", ListSortDirection.Descending); - void ClearChartSort() => ChartRef.ClearSort(); + public class SalesPoint + { + public string Month { get; set; } = string.Empty; + public double Revenue { get; set; } + } + + private readonly List SalesData = new() + { + new SalesPoint { Month = "Jan", Revenue = 35 }, + new SalesPoint { Month = "Feb", Revenue = 28 }, + new SalesPoint { Month = "Mar", Revenue = 34 }, + new SalesPoint { Month = "Apr", Revenue = 32 }, + new SalesPoint { Month = "May", Revenue = 40 }, + new SalesPoint { Month = "Jun", Revenue = 32 } + }; } ``` -**See [references/api-reference.md](references/api-reference.md) for complete method documentation.** +## Step 6 — Layer interactivity only when asked ---- +Tooltips, crosshair, zoom, pan, selection, legend, and secondary axes are +**not** part of the default chart. Add them only when the user explicitly +asks for hover-info, follow-cursor, zoom/pan, click-to-highlight, etc. + +| Setting element | Trigger phrase | +|-----------------|----------------| +| `` | "tooltip", "hover info", "labels on hover" | +| `` | vertical/horizontal follow-cursor line | +| `` | pinch / wheel zoom, or selection-zoom rectangle | +| `SfChart.SelectionMode="ChartSelectionMode.Point"` (root parameter) | click-to-highlight a point or region | +| `` | 2+ series, each with a different `Name` | -## ⚠️ CRITICAL: API Usage Guidelines +Detail: `references/interactive-features.md`. Visual fittings — markers, +data labels, annotations, gradients: `references/visual-elements.md`. -### 1. Enum Names - MUST Use Full Namespace +## Step 7 — Apply critical API rules (load before writing code) -**Syncfusion Blazor Toolkit Charts requires FULLY QUALIFIED enum names:** +These contradict the agent default. Each rule cites the source it was +verified against. + +### 7.1 Enums are always fully qualified + +The un-prefixed short names resolve correctly **only** if you also add +`@using Syncfusion.Blazor.Toolkit;`. The prefix is required for the agent +default where the chart namespace is the only one imported. ```razor - + - - + ``` -**Always use `Syncfusion.Blazor.Toolkit.` prefix for:** -- `ValueType` (Category, Double, DateTime, etc.) -- `ChartSeriesType` (Column, Line, Area, etc.) -- `LegendPosition`, `SelectionMode`, `ZoomMode`, `ChartShape`, etc. +Always use `Syncfusion.Blazor.Toolkit.` for `ValueType`, `ChartSeriesType`, +`LegendPosition`, `ZoomMode`, `ChartShape`, `TrendlineTypes`, `Theme`, +`EmptyPointMode`, `ToolbarMode`, `ZIndexPosition`, `ChartSelectionMode`, +`HighlightMode`, `ChartRangePadding`, `LineType`, +`EdgeLabelPlacement`, `LabelPlacement`, `LabelIntersectAction`, `Units`, +`Regions`, `Alignment`, `SplineType`, `StepPosition`, `Segment`, +`Orientation`, `RangeIntervalType`, `ToolbarItems`, `SelectionPattern`. + +> `TextWrap` is the **odd one out**: it lives in the root +> `Syncfusion.Blazor` namespace (not `Syncfusion.Blazor.Toolkit`). Pages +> that set `TextWrap="…"` on `ChartLegendSettings` need either +> `@using Syncfusion.Blazor;` or the fully qualified +> `Syncfusion.Blazor.TextWrap.Wrap`. Used unqualified, with only the +> toolkit usings in scope, the snippet will fail with **CS0103**. -### 2. Component Property Restrictions +### 7.2 Striplines are plural: `` → `` -**⚠️ Common Property Errors to Avoid:** +The non-existent `` will compile to silence +and render nothing. Always wrap in plural collection. + +### 7.3 `ChartCrosshairLine` only takes `Width` + `Color` + +DashArray, LineType, opacity are **not** on this child. Use the parent's +`DashArray` / `LineType`. -#### ChartCrosshairSettings - Supported Properties ```razor - + ``` -**Supported ChartCrosshairSettings Properties:** -- `Enable` - Enable/disable crosshair (boolean) -- `DashArray` - Dash pattern for dashed lines (e.g., "2,3") -- `LineType` - Crosshair line type (Vertical, Horizontal, Both) - -**Supported ChartCrosshairLine Properties:** -- `Width` - Line width (number) -- `Color` - Line color (string) +### 7.4 Bubble uses `Size="PropertyName"` — not `ZName` -#### Striplines - Use Plural Form ```razor - - - - - - - - - - - + + Type="Syncfusion.Blazor.Toolkit.ChartSeriesType.Bubble" /> ``` -### 3. Validation Checklist +### 7.5 Use `@ref` for programmatic methods -Before deploying, verify: -- ✅ All enums use `Syncfusion.Blazor.Toolkit.` prefix -- ✅ ChartCrosshairLine uses ONLY Width and Color -- ✅ Striplines use `` and `` -- ✅ Component references use `@ref` for method access -- ✅ Property names match official API exactly (case-sensitive) - ---- - -## Quick Start Example - -Here's a minimal example to create a column chart with data: +Public async methods on `SfChart`: `RefreshAsync`, `ShowTooltipAsync`, +`HideTooltipAsync`, `ShowCrosshairAsync`, `HideCrosshairAsync`. Public +sync: `Sort`, `ClearSort`, `ClearSelection`, `PreventRender`. Call them +through `@ref="ChartRef"`. Internal methods (`AddSeriesAsync`, +`RemoveSeries`, `ClearSeries`, `RefreshLiveData`) are +`[EditorBrowsable(EditorBrowsableState.Never)]` — do not document or +rely on them. Full signatures: `references/api-reference.md`. ```razor -@page "/chart-demo" -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - - - - - - - - -@code { - public class SalesInfo - { - public string Month { get; set; } - public double SalesValue { get; set; } - } - - public List SalesData = new List - { - new SalesInfo { Month = "Jan", SalesValue = 35 }, - new SalesInfo { Month = "Feb", SalesValue = 28 }, - new SalesInfo { Month = "Mar", SalesValue = 34 }, - new SalesInfo { Month = "Apr", SalesValue = 32 }, - new SalesInfo { Month = "May", SalesValue = 40 }, - new SalesInfo { Month = "Jun", SalesValue = 32 } - }; -} + +@code { SfChart ChartRef = default!; } ``` -**Prerequisites:** -1. Install `Syncfusion.Blazor.Toolkit.Charts` NuGet package -2. Add `@using Syncfusion.Blazor.Toolkit.Charts` to `_Imports.razor` -3. Register service: `builder.Services.AddSyncfusionBlazor();` in `Program.cs` -4. Add script reference in `App.razor` +### 7.6 `@onclick` handlers can't be inside `` ---- +Hook `OnPointClick` / `OnSeriesClick` on `` instead. -## Common Patterns +### 7.7 Accessibility surface uses `AccessibilityDescription` (not `Description`) -### Multi-Series Comparison Chart +The accessibility property on `` is `AccessibilityDescription` +(verified at `src/Components/Charts/Chart/SfChart.razor.Members.cs:171`). +A bare `Description="…"` is **not** a parameter on `SfChart` and will fail +to compile. There is also a sibling `AccessibilityRole` (e.g. `"img"`, +`"figure"`) you can set to override the implicit `presentation` role on +the chart container. ```razor - - - - - - - - - + + … ``` -### Time-Series Line Chart with Zooming +### 7.8 Every event — including per-axis callbacks — lives on a single root-level `` -```razor - - - - - - - - - - -``` - -### Stacked Area Chart with Legend +`OnAxisLabelRender`, `OnAxisMultiLevelLabelRender`, and +`OnAxisActualRangeCalculated` are properties on `ChartEvents`. Bind them +on a **single** `` child of `` — never nested +inside `` or `` (verified at +`src/Components/Charts/Chart/ChartEvent/ChartEvents.razor.cs`). ```razor - - - - - - - - - - - - + + + … ``` ---- +## Common pitfalls + +| Symptom | Cause | Fix | +|---------|-------|-----| +| Chart renders empty | `XName`/`YName` casing mismatch with data class | Property name must match exactly (case-sensitive) | +| `Ctors not found` on `ChartSeriesType` | Short enum (no prefix) | Use `Syncfusion.Blazor.Toolkit.ChartSeriesType.Column` | +| Chart height collapses to zero | `%` on an unsized parent | Use static `height` value or sized container | +| Legend isn't visible | `ChartLegendSettings.Visible="false"` is default | Set `Visible="true"` | +| Strip line preview appears off-axis | Used singular element | Use `` wrapper | +| Crosshair draws but child line is invisible | Passed `DashArray` to `ChartCrosshairLine` | Move `DashArray` to `ChartCrosshairSettings` | +| Bubble shows equal sizes | `Size` property not bound | Set `Size="PropertyName"` (not `ZName`) | +| Tooltip missing on multi-series | Forgot `Shared="true"` | Set `` | +| Multiple axes overlay | Two series with same default `Name` | Set `Name="…"` per series and per axis | +| Screen reader doesn't announce the chart | Set `Description="…"` on `` | `Description` isn't a parameter — use `AccessibilityDescription="…"` and optionally `AccessibilityRole="img"` | +| RTL flag "doesn't take" | Wrote `` | `EnableRtl` is internal. Set `options.EnableRtl = true` on `AddSyncfusionBlazorToolkit(options => …)` once at startup | +| `OnAxisLabelRender` "doesn't fire" | Put `` inside `` | All events live on a single `` block as a child of `` | + +## Step 8 — Validate + +1. **Build green**: `dotnet build ./src/Syncfusion.Blazor.Toolkit.slnx` + (covers net8.0, net9.0, net10.0). +2. **BUnit tests**: `dotnet test ./tests/Syncfusion.Blazor.Toolkit.BUnitTest`. +3. **Visual run** (manual): samples app at `samples/Blazor.Toolkit.Samples` + — chart renders with axis labels, legend, tooltip on hover. +4. **Accessibility scan** (manual): keyboard `Tab` reaches the chart; hover + tooltip; high-contrast theme applies; `ChartPrimaryXAxis` has a `Title` + (screen reader announces it); for charts that replace a table, + `AccessibilityDescription` is set on `` (and `AccessibilityRole` + if the chart conveys unique information). +5. **Final pre-commit checklist**: + - [ ] All enums use the `Syncfusion.Blazor.Toolkit.` prefix + - [ ] `` (plural) wrapper used + - [ ] `ChartCrosshairLine` carries only `Width` + `Color` + - [ ] `XName` / `YName` match property casing + - [ ] Bubble uses `Size=` not `ZName=` + - [ ] `@ref` for any call to `ChartRef.RefreshAsync` / `ShowTooltipAsync` / `HideCrosshairAsync` etc. + - [ ] All event handlers are on a single root-level `` (no per-axis nesting) + - [ ] Accessibility uses `AccessibilityDescription` / `AccessibilityRole`; `EnableRtl` is set on global `AddSyncfusionBlazorToolkit(options => …)` + - [ ] Component reference matches repo conventions (see repo `AGENTS.md`) + +## Don'ts + +- Don't shorten `Syncfusion.Blazor.Toolkit.ChartSeriesType.Column` — + it compiles only when `using Syncfusion.Blazor.Toolkit;` is also in + the same Razor file's imported namespaces. The default sample layout + imports only `Syncfusion.Blazor.Toolkit.Charts` (per + `samples/Blazor.Toolkit.Samples/Components/_Imports.razor`), so the + fully-qualified prefix is required. +- Don't call a made-up extension like `AddSyncfusionToolkit()` — the + real registration extension is `AddSyncfusionBlazorToolkit()`. +- Don't write `` — it doesn't exist. Wrap + singular `` in `` (plural). +- Don't put `DashArray` / `LineType` on `` — its + only valid attributes are `Width` and `Color`. Move them to the + parent ``. +- Don't use `ZName` for bubble size — use `Size="PropertyName"`. +- Don't call instance methods (`RefreshAsync`, `ShowTooltipAsync`, + `HideTooltipAsync`, `ShowCrosshairAsync`, `HideCrosshairAsync`, + `ClearSelection`, `Sort`, etc.) on `SfChart` without `@ref="ChartRef"`. +- Don't put `@onclick` directly on `` — hook + `OnPointClick` / `OnSeriesClick` via ``. +- Don't rely on percentage heights without an explicitly-sized parent + CSS container — the chart will collapse to zero height. +- Don't place a chart inside a route page without first reading + `codestudio-instructions.md` (Step 1) — partial-class + JS-interop + conventions will catch you later. +- Don't drop tooltips, crosshair, zoom, pan, selection, legend, or + secondary axes into the scaffold by default — add them in Step 6 only + when the user asks. +- Don't expect tooltips, crosshair, zoom, or selection under a pure + Static-SSR render mode — the chart JS modules load from + `_content/Syncfusion.Blazor.Toolkit/scripts/*` and require an + interactive circuit. The SVG frame itself renders in Static SSR at + default 600×450; only the interactive features need Server / + WebAssembly / Auto. If you must keep the host page static, place + the chart in an interactive child component. +- Don't pass a `Theme` value copied from older Syncfusion docs + (`Theme.Material`, `Theme.Bootstrap5`, `Theme.Tailwind`, + `Theme.HighContrast`). The `Syncfusion.Blazor.Toolkit.Theme` enum + has only `Fluent` and `FluentDark`; non-existent values compile to + silence and render nothing. See Step 3.5. +- Don't call `AddSyncfusionBlazor()` to "register themes" — themes live + on `SfChart` itself; the toolkit is registered once via + `AddSyncfusionBlazorToolkit()` (Step 3). +- Don't write `` — `EnableRtl` is an + **internal** property on `SfChart`. Set the RTL flag once on the + global options at registration: + `builder.Services.AddSyncfusionBlazorToolkit(o => o.EnableRtl = true)`. +- Don't write `` — that parameter doesn't + exist. Use `AccessibilityDescription="…"` (and optionally + `AccessibilityRole="…"`) instead. See § 7.7. +- Don't put `` inside `` or + `` to capture `OnAxisLabelRender` / + `OnAxisMultiLevelLabelRender` / `OnSelectionChanged` etc. Every event + binds on a single `` child of ``. See § 7.8. + +## Which reference to load + +| If the agent is doing… | Read | +|------------------------|------| +| First-time setup, NuGet, Program.cs registration | `references/getting-started.md` | +| Picking line / area / column / spline / step | `references/chart-types-common.md` | +| Stacking / scatter / bubble / multi-color / vertical | `references/chart-types-specialized.md` | +| Axis type, range, format, secondary axis | `references/axes-and-scales.md` | +| Tooltip / crosshair / zoom / pan / selection | `references/interactive-features.md` | +| Markers / data labels / annotations / gradients | `references/visual-elements.md` | +| Legend position and customization | `references/legend.md` | +| Theme, palette, dimensions, responsive, print | `references/appearance-styling.md` | +| Indicators, trend lines, striplines, panes, empty points | `references/advanced-features.md` | +| Dynamic data, sort, data manager, real-time | `references/data-handling.md` | +| Lifecycle / click / hover / zoom / selection events | `references/events.md` (skim the top-of-file callout — per-axis callbacks like `OnAxisLabelRender` live on the **root** ``, not nested) | +| ARIA, keyboard, RTL, i18n, l10n, color blindness | `references/accessibility-internationalization.md` | +| Public method signatures + property tables | `references/api-reference.md` | +| Drill-down, threshold lines, lazy load, sync | `references/practical-examples.md` | + +**Read order rule** (`.NET/blazor` convention): read **at most two** +references per task. If you still don't know which API to call, escalate +to `references/api-reference.md` last, never first. -## Key Configuration Properties - -### Chart Component (`SfChart`) -- `Title` - Chart title text -- `Width` / `Height` - Chart dimensions (accepts px or %, default: "100%") -- `Theme` - Visual theme (see Theme enum in API reference) -- `Background` - Chart background color -- `EnableAnimation` - Enable/disable animation (default: true) -- `SelectionMode` - Selection mode (None, Series, Point, Cluster, DragXY, DragX, DragY, Lasso) -- `HighlightMode` - Highlight mode (None, Series, Point, Cluster) - -### Primary Axes (`ChartPrimaryXAxis`, `ChartPrimaryYAxis`) -- `ValueType` - Axis type: `Syncfusion.Blazor.Toolkit.ValueType.Category`, `ValueType.Double`, `ValueType.DateTime`, `ValueType.Logarithmic`, `ValueType.DateTimeCategory` -- `Title` - Axis title -- `Minimum` / `Maximum` - Axis range -- `Interval` - Spacing between labels -- `LabelFormat` - Format string for labels (e.g., "C0", "N2", "dd MMM") -- `EdgeLabelPlacement` - Edge label handling (None, Hide, Shift) -- `LabelIntersectAction` - Label intersection handling (None, Hide, Trim, Wrap, MultipleRows, Rotate45, Rotate90) -- **Striplines** - Use `` (plural) for horizontal/vertical bands - -### Series (`ChartSeries`) -- `DataSource` - Data collection (IEnumerable) -- `XName` / `YName` - Property names for X and Y values (case-sensitive) -- `Type` - Chart type: `Syncfusion.Blazor.Toolkit.ChartSeriesType.Column`, `ChartSeriesType.Line`, etc. (see API reference) -- `Name` - Series name for legend -- `Fill` - Series color (CSS color string) -- `Width` - Line/border width (pixels) -- `DashArray` - Dash pattern (e.g., "5,5") -- `Opacity` - Transparency (0 to 1) - -### Interactivity -- `ChartTooltipSettings` - Tooltip configuration - - `Enable` - Show/hide tooltip - - `Shared` - Enable shared tooltip for multiple series - - `Format` - Custom tooltip format - - `Template` - Custom tooltip template (RenderFragment) -- `ChartZoomSettings` - Zoom and pan options - - `EnableSelectionZooming` - Enable selection-based zoom - - `EnableMouseWheelZooming` - Enable mouse wheel zoom - - `EnablePinchZooming` - Enable pinch zoom (touch devices) - - `EnablePan` - Enable panning - - `Mode` - Zoom mode (X, Y, XY) -- `SelectionMode` - Selection behavior (see SelectionMode enum) -- `ChartCrosshairSettings` - Crosshair configuration - - `Enable` - Show/hide crosshair - - `LineType` - Crosshair line type (Vertical, Horizontal, Both) - - `ChartCrosshairLine` - Line style (Width, Color ONLY - NO DashArray) - -### Visual Elements -- `ChartMarker` - Data point markers - - `Visible` - Show/hide markers - - `Shape` - Marker shape (see ChartShape enum) - - `Width` / `Height` - Marker dimensions -- `ChartDataLabel` - Data labels on points - - `Visible` - Show/hide labels - - `Position` - Label position - - `Template` - Custom label template -- `ChartLegendSettings` - Legend configuration - - `Visible` - Show/hide legend - - `Position` - Legend position (see LegendPosition enum) -- `ChartAnnotations` - Custom annotations - - Support for text, images, and shapes +## Documentation and Navigation Guide ---- +The canonical, external reference lives at the Syncfusion **Blazor Toolkit +Charts overview demo**, which mirrors the live components shipped by this +package: + +- **Toolkit Charts overview** — + Use this to confirm any visual / API behaviour before relying on the + snippets in `references/`. The demo page is regenerated from the + published package, so when it diverges from this skill, **trust the + demo** for the exact surface and **trust this skill** for the + repo-specific gotchas (enum prefix, plural wrappers, `ChartCrosshairLine` + limits, etc.). + +### Internal references — read order + +The "Which reference to load" table above is the navigation map. The +recommended staircase is: + +1. `references/getting-started.md` — first read when wiring a brand-new app. +2. `references/chart-types-common.md` or `…specialized.md` — when choosing a + series. +3. `references/axes-and-scales.md`, `interactive-features.md`, + `visual-elements.md`, `legend.md`, `appearance-styling.md` — when + deeper configuration is asked for. +4. `references/data-handling.md`, `events.md`, + `accessibility-internationalization.md` — for live data, hooks, and + a11y. +5. `references/advanced-features.md`, `practical-examples.md` — for + trend lines, panes, drill-down, lazy load. +6. `references/api-reference.md` — last resort, never first; it is the + big property-and-method catalogue. + +## Next Steps + +Once validation (Step 8) is green, the natural follow-on tasks are: + +1. **Pick the next visual layer.** If the user asked for any of + tooltips, crosshair, zoom / pan, selection, or a secondary axis → + load `references/interactive-features.md` and apply Step 6. +2. **Tune the visual.** Markers, data labels, annotations, gradients, + legend positioning → load `references/visual-elements.md` and + `references/legend.md`. +3. **Confirm accessibility.** Run the accessibility scan in Step 8; + if anything is missing (`Title` on every axis, keyboard reach, + contrast for the chosen `Theme`), load + `references/accessibility-internationalization.md` and fix the gap. +4. **Hook events.** If the user wants point-click, series-click, hover, + zoom-end, or selection callbacks → load `references/events.md` and + wire `` (do **not** put `@onclick` on `` — + rule 7.6). +5. **Bind real data.** If `List` is no longer enough or the user + needs paging / web-API backing → load `references/data-handling.md` + and migrate the `DataSource` to `SfDataManager`. +6. **Compose with another control.** For the chart's neighbours (a + header filter, refresh button, export-PNG button, loading overlay, + or confirm dialog) load the matching sibling skill in the same + folder — decisions are tabled in the "When you need to compose" + section near the top of this skill. +7. **Cross-check against the live demo.** Re-verify any behaviour the + user will see against the Syncfusion Toolkit Charts overview + (`https://blazor.syncfusion.com/demos/toolkit/charts/overview`) + before declaring done. \ No newline at end of file diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/references/accessibility-internationalization.md b/.github/skills/syncfusion-blazor-toolkit-charts/references/accessibility-internationalization.md index 1730951..1c58aea 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/references/accessibility-internationalization.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/references/accessibility-internationalization.md @@ -1,1058 +1,247 @@ -# Accessibility and Internationalization Reference +# Accessibility & Internationalization -## Table of Contents +> **Verified against source** — `AccessibilityDescription` parameter, +> `AccessibilityRole` parameter, `Theme` enum, and the `EnableRtl` flag +> (read from the global service, **not** settable per chart) verified +> against `src/Components/Charts/Chart/SfChart.razor.Members.cs` and +> `src/Base/SyncfusionService.cs`. Last source audit: **2026-08-24**. -- [Accessibility Features](#accessibility-features) - - [ARIA Labels and Roles](#aria-labels-and-roles) - - [Keyboard Navigation](#keyboard-navigation) - - [Screen Reader Support](#screen-reader-support) - - [High Contrast Modes](#high-contrast-modes) - - [Focus Management](#focus-management) -- [Internationalization (i18n)](#internationalization-i18n) - - [Locale Configuration](#locale-configuration) - - [Number Formatting](#number-formatting) - - [Date Formatting](#date-formatting) - - [Currency Symbols](#currency-symbols) -- [Localization (l10n)](#localization-l10n) - - [Text Translation](#text-translation) - - [RTL Support](#rtl-support) - - [Custom Locales](#custom-locales) - - [Loading Locale Data](#loading-locale-data) -- [Color Accessibility](#color-accessibility) - - [WCAG Compliance](#wcag-compliance) - - [Color-Blind Friendly Palettes](#color-blind-friendly-palettes) - - [Contrast Ratios](#contrast-ratios) - - [Pattern Alternatives](#pattern-alternatives) -- [Responsive Accessibility](#responsive-accessibility) - - [Touch Target Sizing](#touch-target-sizing) - - [Mobile Accessibility](#mobile-accessibility) - - [Adaptive Features](#adaptive-features) -- [Testing and Validation](#testing-and-validation) - - [Accessibility Testing Tools](#accessibility-testing-tools) - - [Compliance Checklists](#compliance-checklists) - - [Common Issues and Fixes](#common-issues-and-fixes) +Covers (a) WAI-ARIA / keyboard / high-contrast / color-blind friendliness, and +(b) per-locale formatting, RTL, and custom resource loading for `SfChart`. +Only includes properties & techniques that are **actually wired** in the +`Syncfusion.Blazor.Toolkit.Charts` assembly. Anything invented in older docs +(chart-specific keyboard shortcuts, custom `TouchTarget` rules, etc.) is +deliberately omitted. -## Accessibility Features +> **Sample data** — see [`_includes/sample-data.md`](_includes/sample-data.md). +> This file's snippets bind to `Data : List` where +> `CategoryValue(string Category, double Value)`. +> ``` -### ARIA Labels and Roles +## Table of contents -Syncfusion Blazor Charts follow WAI-ARIA standards to provide semantic information for assistive technologies. +- Accessibility surface (`Title`, `AccessibilityDescription`, `AccessibilityRole`, `Theme`) +- Keyboard interaction (focus order, tooltip on focus) +- Color-blind palettes +- Internationalization (Locale, LabelFormat) +- RTL support +- Localization (`Syncfusion.Blazor.Resources`) +- Testing checklist -**Default ARIA Attributes** +## Accessibility surface ```razor -@using Syncfusion.Blazor.Toolkit - - - - - - - - - - - - -@code { - public List ChartData = new List - { - new SalesData { Month = "Jan", Sales = 35 }, - new SalesData { Month = "Feb", Sales = 28 }, - new SalesData { Month = "Mar", Sales = 42 } - }; - - public class SalesData - { - public string Month { get; set; } - public double Sales { get; set; } - } -} -``` - -**ARIA Role Mappings** - -| Element | ARIA Role | Description | -|---------|-----------|-------------| -| Chart Container | `region` | Main chart area | -| Legend | `button` | Toggleable series visibility | -| Data Point | `img` | Individual data representations | -| Tooltip | `tooltip` | Contextual information | -| Axis Labels | `text` | Axis value descriptions | - -### Keyboard Navigation - -Complete keyboard support following WCAG 2.2 guidelines. - -**Basic Navigation** - -```razor -@using Syncfusion.Blazor.Toolkit - - - - - - - - - - Zoom - ZoomIn - ZoomOut - Pan - Reset - - - - - - -@code { - public List GrowthData = new List - { - new GrowthInfo { Year = 2020, Rate = 5.2 }, - new GrowthInfo { Year = 2021, Rate = 6.8 }, - new GrowthInfo { Year = 2022, Rate = 7.5 } - }; - - public class GrowthInfo - { - public int Year { get; set; } - public double Rate { get; set; } - } -} -``` - -**Keyboard Shortcuts Reference** - -| Key Combination | Action | -|----------------|--------| -| `Alt + J` | Focus chart element | -| `Tab` / `Shift + Tab` | Navigate elements | -| `Arrow Keys` | Navigate data points/series | -| `Enter` / `Space` | Select/toggle element | -| `Ctrl + +` / `Ctrl + -` | Zoom in/out | -| `Arrow Keys` (during pan) | Pan chart | -| `R` | Reset zoom | -| `Ctrl + P` | Print chart | - -### Screen Reader Support - -Optimize chart content for screen readers with descriptive labels. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts + + + + - - - - - - - - - - - - - + - -@code { - public List RevenueData = new List - { - new QuarterData { Quarter = "Q1", Amount = 25.5 }, - new QuarterData { Quarter = "Q2", Amount = 32.8 }, - new QuarterData { Quarter = "Q3", Amount = 28.3 }, - new QuarterData { Quarter = "Q4", Amount = 41.2 } - }; - - public class QuarterData - { - public string Quarter { get; set; } - public double Amount { get; set; } - } -} ``` -### High Contrast Modes +- `Title` is exposed to assistive technology as the chart's accessible name. +- `AccessibilityDescription` provides a longer announcement if supported by + the reader. (The property is **not** called `Description`; that name is + reserved on `SfBaseComponent` for a different purpose.) +- `AccessibilityRole` overrides the implicit role on the chart container + (default `null` → chart is treated as decorative). Set this when the + chart replaces a table or conveys unique information. +- Axis `Title` is announced alongside the tick labels — always set both. -Support system high contrast themes for improved visibility. +## Keyboard interaction -```razor -@using Syncfusion.Blazor.Toolkit.Charts +`SfChart` does **not** register custom keyboard shortcuts. Keyboard behavior +is restricted to: - - - - - - - - +- `Tab` into the chart container → focus the chart container. +- `Tab` again → focus any enabled sub-control (zoom toolbar buttons, legend + toggle). +- `Enter` / `Space` → activate (e.g. zoom toolbar button, legend item). +- `Esc` → close any open tooltip or context menu. -@code { - public List ContrastData = new List - { - new CategoryData { Category = "A", Value = 45 }, - new CategoryData { Category = "B", Value = 62 }, - new CategoryData { Category = "C", Value = 38 } - }; - - public class CategoryData - { - public string Category { get; set; } - public double Value { get; set; } - } -} -``` +If accessibility requires direct keyboard navigation **between data points**, +that's not built in. Either: -### Focus Management +1. Add an off-screen `` summary of the same data with the chart's role + set to `presentation`, or +2. Render the data both as a chart *and* a semantic `
` and let users + pick the view via a toggle button. -Implement proper focus indicators and management by enabling selection on the chart. +## Color-blind palettes -```razor -@using Syncfusion.Blazor.Toolkit.Charts +| Need | Approach | +|------|----------| +| Built-in light theme (default) | `Theme="Syncfusion.Blazor.Toolkit.Theme.Fluent"` | +| Built-in dark theme (the candidate for high-contrast application chrome) | `Theme="Syncfusion.Blazor.Toolkit.Theme.FluentDark"` | +| Custom safe palette | Pass `string[]` to `` — see `appearance-styling.md` for the recommended palette (Wong/Okabe-Ito). | +| Pattern fallback | Set `SelectionPattern="Syncfusion.Blazor.Toolkit.SelectionPattern.DiagonalForward"` (or `Dots`, `Crosshatch`, `Chessboard`, `Circle`, `Triangle`, etc.) — useful when the chart has selection. The 20-member `SelectionPattern` enum is verified in `src/Base/Enumeration.cs`. | - - - - - - - - - +> **Older docs reference `Theme.HighContrast`, `Theme.Material`, +> `Theme.Bootstrap5`, `Theme.Tailwind`, etc.** None of those values exist +> in `Syncfusion.Blazor.Toolkit.Theme` — only `Fluent` and `FluentDark` +> ship. Using a non-existent value compiles to silence and renders nothing. -@code { - public List ProductData = new List - { - new ProductInfo { Product = "Laptop", Units = 120 }, - new ProductInfo { Product = "Phone", Units = 250 }, - new ProductInfo { Product = "Tablet", Units = 95 } - }; - - public class ProductInfo - { - public string Product { get; set; } - public double Units { get; set; } - } -} -``` - ---- - -## Internationalization (i18n) - -### Locale Configuration - -Configure chart to use specific locales for formatting. - -```razor -@using Syncfusion.Blazor -@using Syncfusion.Blazor.Toolkit.Charts -@using System.Globalization +Default `Palettes=` is *not* color-blind safe. Replace it whenever the chart +displays a categorical comparison to user-facing readers. - - - - - - - - +## Internationalization -@code { - protected override void OnInitialized() - { - CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("de-DE"); - CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("de-DE"); - } - - public List SalesData = new List - { - new MonthlySales { Month = "Januar", Sales = 12500.50 }, - new MonthlySales { Month = "Februar", Sales = 15300.75 }, - new MonthlySales { Month = "März", Sales = 18200.25 } - }; - - public class MonthlySales - { - public string Month { get; set; } - public double Sales { get; set; } - } -} -``` +`SfChart` does **not** currently expose a `Locale` parameter. The toolkit +honors the host's `CultureInfo.CurrentCulture` automatically; configure +per-axis formatting via `LabelFormat`. -### Number Formatting +| Property | Effect | +|----------|--------| +| `` | Date and numeric formats (e.g. `"c2"`, `"dd MMM yyyy"`) | +| `` | Same as X axis — affects number / currency / compact formatting | +| Host's `CultureInfo.CurrentCulture` | Toggling the host culture re-formats axes automatically | -Apply culture-specific number formatting. +A standard pattern: ```razor -@using Syncfusion.Blazor.Toolkit.Charts -@using System.Globalization - - - - - - - - - - - - + + + @code { - public List PopulationData = new List - { - new RegionData { Region = "Asia", Population = 4641054775 }, - new RegionData { Region = "Africa", Population = 1340598147 }, - new RegionData { Region = "Europe", Population = 747636026 } - }; - - public class RegionData - { - public string Region { get; set; } - public double Population { get; set; } - } + private string numericFormat = "n0"; // picks up CurrentCulture } ``` -### Date Formatting - -Format dates according to locale conventions. +### Number / date / currency format examples ```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - - - -@code { - public List TemperatureData = new List - { - new TempData { Date = new DateTime(2024, 1, 1), Temp = 15.5 }, - new TempData { Date = new DateTime(2024, 2, 1), Temp = 18.2 }, - new TempData { Date = new DateTime(2024, 3, 1), Temp = 22.8 }, - new TempData { Date = new DateTime(2024, 4, 1), Temp = 25.3 } - }; - - public class TempData - { - public DateTime Date { get; set; } - public double Temp { get; set; } - } -} -``` + + -### Currency Symbols + + -Display currency using locale-specific symbols. + + -```razor -@using Syncfusion.Blazor.Toolkit.Charts -@using System.Globalization - - - - - - - - - - - -@code { - public List UsdRevenue = new List - { - new CurrencyData { Quarter = "Q1", Amount = 125000 }, - new CurrencyData { Quarter = "Q2", Amount = 138000 } - }; - - public List EurRevenue = new List - { - new CurrencyData { Quarter = "Q1", Amount = 110000 }, - new CurrencyData { Quarter = "Q2", Amount = 125000 } - }; - - public class CurrencyData - { - public string Quarter { get; set; } - public double Amount { get; set; } - } -} + + ``` ---- +`LabelFormat` for `DateTime` accepts standard .NET format strings; the +separator and month names follow the host culture. -## Localization (l10n) - -### Text Translation - -Translate chart text elements for different languages. +## RTL support ```razor -@using Syncfusion.Blazor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - +@* RTL is NOT a per-chart setting on SfChart. *@ +@* The flag lives on the global options; set it once at startup: *@ @code { - private string CurrentLocale = "en-US"; - - private Dictionary> Translations = new() - { - ["en-US"] = new Dictionary - { - ["ChartTitle"] = "Sales Overview", - ["XAxisTitle"] = "Products", - ["YAxisTitle"] = "Sales Amount", - ["SeriesName"] = "Current Year" - }, - ["es-ES"] = new Dictionary - { - ["ChartTitle"] = "Resumen de Ventas", - ["XAxisTitle"] = "Productos", - ["YAxisTitle"] = "Monto de Ventas", - ["SeriesName"] = "Año Actual" - }, - ["fr-FR"] = new Dictionary - { - ["ChartTitle"] = "Aperçu des Ventes", - ["XAxisTitle"] = "Produits", - ["YAxisTitle"] = "Montant des Ventes", - ["SeriesName"] = "Année en Cours" - } - }; - - private string GetLocalizedText(string key) - { - return Translations[CurrentLocale].ContainsKey(key) - ? Translations[CurrentLocale][key] - : key; - } - - public List LocalizedData = new List - { - new LocaleData { Category = "A", Value = 120 }, - new LocaleData { Category = "B", Value = 95 }, - new LocaleData { Category = "C", Value = 150 } - }; - - public class LocaleData - { - public string Category { get; set; } - public double Value { get; set; } - } + // Program.cs: + // builder.Services.AddSyncfusionBlazorToolkit(o => o.EnableRtl = true); } -``` - -### RTL Support -Enable right-to-left layout for RTL languages. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - + + - - - - - - - - - -@code { - public List RtlData = new List - { - new ProductSales { Product = "محمول", Sales = 85000 }, - new ProductSales { Product = "هاتف", Sales = 125000 }, - new ProductSales { Product = "جهاز لوحي", Sales = 65000 } - }; - - public class ProductSales - { - public string Product { get; set; } - public double Sales { get; set; } - } -} -``` - -### Custom Locales - -Define custom locale settings for specialized requirements. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts -@using System.Globalization - - - - - - - - -@code { - protected override void OnInitialized() - { - var customCulture = (CultureInfo)CultureInfo.CurrentCulture.Clone(); - customCulture.NumberFormat.NumberDecimalSeparator = ","; - customCulture.NumberFormat.NumberGroupSeparator = "."; - CultureInfo.DefaultThreadCurrentCulture = customCulture; - } - - public List MetricData = new List - { - new MetricInfo { Period = "Jan", Value = 25.5 }, - new MetricInfo { Period = "Feb", Value = 32.8 }, - new MetricInfo { Period = "Mar", Value = 28.3 } - }; - - public class MetricInfo - { - public string Period { get; set; } - public double Value { get; set; } - } -} -``` - -### Loading Locale Data - -Load and apply locale data dynamically. - -```razor -@using Syncfusion.Blazor -@using Syncfusion.Blazor.Toolkit.Charts - -
- - -
- - - - - - - - -@code { - private string SelectedLocale = "en-US"; - private string ChartTitle = "Monthly Sales"; - private string XAxisTitle = "Month"; - private string YAxisTitle = "Sales"; - private string SeriesName = "Revenue"; - - private void ChangeLocale(ChangeEventArgs e) - { - SelectedLocale = e.Value.ToString(); - LoadLocaleStrings(SelectedLocale); - } - - private void LoadLocaleStrings(string locale) - { - switch (locale) - { - case "de-DE": - ChartTitle = "Monatliche Verkäufe"; - XAxisTitle = "Monat"; - YAxisTitle = "Verkäufe"; - SeriesName = "Umsatz"; - break; - case "ja-JP": - ChartTitle = "月次売上"; - XAxisTitle = "月"; - YAxisTitle = "売上"; - SeriesName = "収益"; - break; - default: - ChartTitle = "Monthly Sales"; - XAxisTitle = "Month"; - YAxisTitle = "Sales"; - SeriesName = "Revenue"; - break; - } - } - - public List ChartData = new List - { - new SalesInfo { Month = "Jan", Sales = 45000 }, - new SalesInfo { Month = "Feb", Sales = 52000 }, - new SalesInfo { Month = "Mar", Sales = 48000 } - }; - - public class SalesInfo - { - public string Month { get; set; } - public double Sales { get; set; } - } -} -``` - ---- - -## Color Accessibility - -### WCAG Compliance - -Ensure color choices meet WCAG 2.2 Level AA standards. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - #0066CC - #E67300 - #00994D - #CC0000 - - - - - - - -@code { - public List ComplianceData = new List - { - new DataPoint { Category = "A", Value = 45 }, - new DataPoint { Category = "B", Value = 62 }, - new DataPoint { Category = "C", Value = 38 }, - new DataPoint { Category = "D", Value = 71 } - }; - - public class DataPoint - { - public string Category { get; set; } - public double Value { get; set; } - } -} -``` - -### Color-Blind Friendly Palettes - -Use palettes designed for various types of color blindness. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - #0173B2 - #DE8F05 - #029E73 - #CC78BC - #CA9161 - - - - - - - - - - - - - -@code { - public List SeriesA = new List - { - new RateData { Year = 2021, Rate = 5.2 }, - new RateData { Year = 2022, Rate = 6.5 }, - new RateData { Year = 2023, Rate = 7.8 } - }; - - public List SeriesB = new List - { - new RateData { Year = 2021, Rate = 4.8 }, - new RateData { Year = 2022, Rate = 5.9 }, - new RateData { Year = 2023, Rate = 6.2 } - }; - - public List SeriesC = new List - { - new RateData { Year = 2021, Rate = 6.1 }, - new RateData { Year = 2022, Rate = 7.3 }, - new RateData { Year = 2023, Rate = 8.5 } - }; - - public class RateData - { - public int Year { get; set; } - public double Rate { get; set; } - } -} -``` - -### Contrast Ratios - -Maintain proper contrast ratios between chart elements. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - - - - - - - - - - - - -@code { - public List ContrastData = new List - { - new MonthlyRevenue { Month = "Jan", Revenue = 32000 }, - new MonthlyRevenue { Month = "Feb", Revenue = 28000 }, - new MonthlyRevenue { Month = "Mar", Revenue = 35000 } - }; - - public class MonthlyRevenue - { - public string Month { get; set; } - public double Revenue { get; set; } - } -} -``` - -### Pattern Alternatives - -Provide pattern fills as alternatives to color coding for improved accessibility to color-blind users. Multiple series with different patterns help differentiate data. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - - - - - - - -@code { - public List SegmentA = new List - { - new MarketData { Segment = "A", Share = 35.5 } - }; - - public List SegmentB = new List - { - new MarketData { Segment = "B", Share = 28.2 } - }; - - public List SegmentC = new List - { - new MarketData { Segment = "C", Share = 36.3 } - }; - - public class MarketData - { - public string Segment { get; set; } - public double Share { get; set; } - } -} -``` - ---- - -## Responsive Accessibility - -### Touch Target Sizing - -Ensure touch targets meet minimum size requirements (44x44 pixels). - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - - - - - -@code { - public List TouchData = new List - { - new TouchDataPoint { Product = "A", Sales = 120 }, - new TouchDataPoint { Product = "B", Sales = 95 }, - new TouchDataPoint { Product = "C", Sales = 145 } - }; - - public class TouchDataPoint - { - public string Product { get; set; } - public double Sales { get; set; } - } -} -``` - -### Mobile Accessibility - -Optimize charts for mobile devices and touch interactions. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - - - - - - -@code { - public List MobileData = new List - { - new MobileDataPoint { Month = "Jan", Revenue = 28 }, - new MobileDataPoint { Month = "Feb", Revenue = 35 }, - new MobileDataPoint { Month = "Mar", Revenue = 42 } - }; - - public class MobileDataPoint - { - public string Month { get; set; } - public double Revenue { get; set; } - } -} -``` - -### Adaptive Features - -Implement features that adapt to different screen sizes and orientations. - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - -@code { - private bool IsSmallScreen = false; - private string ChartHeight = "400px"; - - protected override void OnInitialized() - { - // Simulate responsive behavior - IsSmallScreen = true; // Set based on actual screen detection - ChartHeight = IsSmallScreen ? "300px" : "500px"; - } - - public List AdaptiveData = new List - { - new AdaptiveDataPoint { Category = "A", Value = 65 }, - new AdaptiveDataPoint { Category = "B", Value = 78 }, - new AdaptiveDataPoint { Category = "C", Value = 55 } - }; - - public class AdaptiveDataPoint - { - public string Category { get; set; } - public double Value { get; set; } - } -} -``` - ---- - -## Testing and Validation - -### Accessibility Testing Tools - -Recommended tools for validating chart accessibility: - -- **axe DevTools**: Browser extension for WCAG compliance checking -- **WAVE**: Web accessibility evaluation tool -- **NVDA/JAWS**: Screen reader testing -- **Lighthouse**: Chrome DevTools accessibility audit -- **Pa11y**: Automated accessibility testing - -### Compliance Checklists - -**WCAG 2.2 Level AA Checklist** - -- [ ] All images have alt text -- [ ] Color contrast ratio ≥ 4.5:1 for normal text -- [ ] Color contrast ratio ≥ 3:1 for large text -- [ ] Information not conveyed by color alone -- [ ] Keyboard navigation fully functional -- [ ] Focus indicators visible -- [ ] Touch targets ≥ 44x44 pixels -- [ ] Content readable at 200% zoom -- [ ] Screen reader announces all elements -- [ ] RTL support for applicable languages - -### Common Issues and Fixes - -**Issue 1: Low Contrast Data Labels** - -```razor - - - - - - - -``` - -**Issue 2: Missing ARIA Labels** - -```razor - - - - - -``` - -**Issue 3: Small Touch Targets** - -```razor - - - -``` - -**Issue 4: Poor Keyboard Navigation** - -```razor - - - -``` - -**Best Practices Summary** - -1. Always provide text alternatives for visual information -2. Use sufficient color contrast (minimum 4.5:1) -3. Support keyboard navigation for all interactive elements -4. Test with screen readers regularly -5. Implement RTL support for applicable locales -6. Ensure touch targets meet minimum size requirements -7. Provide pattern alternatives to color coding -8. Use semantic HTML and proper ARIA attributes -9. Test across multiple devices and browsers -10. Validate with automated accessibility tools - ---- -**Compliance Standards Met:** -- WCAG 2.2 Level AA -- Section 508 -- ADA (Americans with Disabilities Act) -- EN 301 549 (European Standard) -- ARIA 1.2 Specification + +
+``` + +The `EnableRtl` flag on the global `SyncfusionBlazorToolkitOptions` +flips the chart container, axes, legend, and tooltips. It is **read +internally** by `SfChart.EnableRtl` (verified at +`src/Components/Charts/Chart/SfChart.razor.Members.cs:401`, +`internal bool EnableRtl => …`), so do not try to set it on +`` — that parameter does not exist and the +compiler will reject it. Combined with setting the host's +`CultureInfo.CurrentCulture` to the target locale (Arabic, Hebrew, etc.) +so numeric/date formatting follows. + +## Localization resource loading + +For non-built-in locales, use the host application's standard localization +plumbing. `SfChart` does not expose a `Locale` parameter — it picks up the +host's `CurrentCulture` automatically: + +```csharp +builder.Services.AddSyncfusionBlazorToolkit(); +builder.Services.AddLocalization(opts => opts.ResourcesPath = "Resources"); +``` + +The satellite resource files ship with the toolkit under +`Syncfusion.Blazor.Resources.*.resx`. Pick the culture you need, add it as +`ResourcesPath`, then set both `CultureInfo.DefaultThreadCurrentCulture` +and `UICulture` to that name. + +## Accessibility-Tuned Properties (verified at source) + +These properties are public, real, and ship in the current toolkit. The +prior checklist treated them as out-of-scope — they're not. Use them +when shipping user-facing analytics. + +| Property | Where | Effect | When to use | +|----------|-------|--------|-------------| +| `AccessibilityDescription` | `` | Long-form announcement for assistive tech | Replace a table you'll otherwise hide | +| `AccessibilityRole` | `` | WAI-ARIA role on the chart container (e.g. `"img"`, `"figure"`) | Default `null` treats the chart as decorative | +| `Title` | `` | Short accessible name | Every chart | +| `ChartPrimaryXAxis Title` / `ChartPrimaryYAxis Title` | axis | Announces the variable mapping | Every axis | +| `ChartLegendSettings EnableHighlight="true"` | legend | On hover, the matching series is highlighted and others dim | Multi-series dashboards where discoverability matters | +| `ChartLegendSettings TabIndex="…"` | legend | Default `3`; lower it to push the legend earlier in tab order, raise it to skip | Page-level focus ordering | +| `ChartLegendSettings Width` / `Height` (px) | legend | Constrains legend size so paging kicks in when series grow | > 6 series | +| `Palettes="@CvdSafePalette"` | chart | Replaces the default palette | When the chart is used by users with CVD | +| `SelectionPattern="…DiagonalForward"` (or `Dots`, `Crosshatch`, etc.) | chart | Replaces color-only encoding with a fill pattern | When selection may otherwise be invisible to colorblind users | + +The accessibility surface for axis labels is largely delegated to the +axis `Title`. The chart does not expose per-axis `aria-*` props — host +your chart inside a labelled container (`
` +or `
`) if you need a +documented label. + +## Testing checklist + +### Mandatory (baseline) + +- [ ] Every chart has a non-empty `Title`. +- [ ] Axis titles exist for X and Y. +- [ ] `AccessibilityDescription` is set when the chart replaces a table. +- [ ] `LabelFormat` produces locale-correct output. +- [ ] Pick a `Theme` that matches host intent (`Fluent` for light, `FluentDark` + for dark) OR override `Palettes` with a color-blind safe palette. +- [ ] When RTL: set `options.EnableRtl = true` at toolkit registration + AND host `CultureInfo.CurrentCulture` match. +- [ ] Keyboard `Tab` reaches the chart and any toggleable bits in expected + order; `Esc` dismisses any open tooltip. +- [ ] bUnit snapshot includes `aria-label` / `role` if declared on the + container. + +### Recommended for user-facing analytics + +- [ ] Multi-series charts set `ChartLegendSettings EnableHighlight="true"` + so keyboard / hover discoverability is provided. +- [ ] Tab order is reviewed: if the legend usually comes first in the + visual flow, lower `ChartLegendSettings TabIndex` (default `3`); if + it should be skipped, raise it. +- [ ] For charts with `> 6` series, constrain legend `Width`/`Height` so + paging kicks in instead of overflowing. +- [ ] Color-blind safe `Palettes` are configured (default palette is **not** + CVD-friendly — use Wong/Okabe-Ito or pause to ask the design team). +- [ ] If selection encodes meaning (filters / drill-down candidates), + set a `SelectionPattern` so the encoding survives grayscale or + color-blind rendering. + +**What this reference deliberately omits** (no-op in this toolkit): custom +keyboard shortcut customization, `TouchTarget` size hints. Don't add these +— they'd be hallucinated APIs the agent will patch into a build that +never had them. \ No newline at end of file diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/references/advanced-features.md b/.github/skills/syncfusion-blazor-toolkit-charts/references/advanced-features.md index 6bb0f7d..a9d18c5 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/references/advanced-features.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/references/advanced-features.md @@ -1,873 +1,186 @@ -# Advanced Features Reference - Syncfusion Blazor Charts - -This comprehensive reference covers advanced features for implementing sophisticated chart visualizations in Blazor applications using Syncfusion Charts. - -## Table of Contents - -- [Multiple Panes](#multiple-panes) - - [When to Use](#when-to-use) - - [Creating Rows (Horizontal Division)](#creating-rows-horizontal-division) - - [Creating Columns (Vertical Division)](#creating-columns-vertical-division) - - [Configuration Options](#configuration-options) -- [Technical Indicators](#technical-indicators) - - [When to Use](#when-to-use) - - [Moving Average (SMA, EMA, TMA)](#moving-average-sma-ema-tma) - - [RSI (Relative Strength Index)](#rsi-relative-strength-index) - - [Bollinger Bands](#bollinger-bands) - - [MACD (Moving Average Convergence Divergence)](#macd-moving-average-convergence-divergence) - - [Available Indicators](#available-indicators) -- [Trend Lines](#trend-lines) - - [When to Use](#when-to-use) - - [Linear Trend Line](#linear-trend-line) - - [Polynomial Trend Line](#polynomial-trend-line) - - [Exponential Trend Line](#exponential-trend-line) - - [Logarithmic Trend Line](#logarithmic-trend-line) - - [Moving Average Trend Line](#moving-average-trend-line) - - [Forecasting with Trend Lines](#forecasting-with-trend-lines) - - [Configuration Options](#configuration-options) -- [Strip Lines](#strip-lines) - - [When to Use](#when-to-use) - - [Horizontal Strip Lines](#horizontal-strip-lines) - - [Vertical Strip Lines](#vertical-strip-lines) - - [Segmented Strip Lines](#segmented-strip-lines) - - [Strip Line with Custom Text](#strip-line-with-custom-text) - - [Strip Line with Tooltip](#strip-line-with-tooltip) - - [Configuration Options](#configuration-options) -- [Multiple Axes](#multiple-axes) - - [When to Use](#when-to-use) - - [Dual Y-Axes](#dual-y-axes) - - [Multiple X and Y Axes](#multiple-x-and-y-axes) - - [Configuration Options](#configuration-options) -- [Data Editing](#data-editing) - - [When to Use](#when-to-use) - - [Basic Data Editing](#basic-data-editing) - - [Configuration Options](#configuration-options) -- [Empty Points](#empty-points) - - [When to Use](#when-to-use) - - [Empty Point Modes](#empty-point-modes) - - [Empty Point Modes Explained](#empty-point-modes-explained) -- [Chart Export](#chart-export) - - [When to Use](#when-to-use) - - [Export to Image Formats](#export-to-image-formats) - - [Export to PDF](#export-to-pdf) - - [Export to Excel (XLSX/CSV)](#export-to-excel-xlsxcsv) - - [Export as Base64 String](#export-as-base64-string) - - [Customize Export with Events](#customize-export-with-events) - - [Export Multiple Charts](#export-multiple-charts) - - [Supported Export Formats](#supported-export-formats) -- [Print](#print) - - [When to Use](#when-to-use) - - [Basic Printing](#basic-printing) - - [Print Multiple Charts](#print-multiple-charts) - - [Print-Specific Styling](#print-specific-styling) -- [RTL Support](#rtl-support) - - [When to Use](#when-to-use) - - [Enabling RTL Mode](#enabling-rtl-mode) - - [RTL with Localization](#rtl-with-localization) - - [RTL Configuration](#rtl-configuration) -- [Implementation Patterns](#implementation-patterns) - - [Pattern 1: Financial Dashboard](#pattern-1-financial-dashboard) - - [Pattern 2: Performance Monitoring](#pattern-2-performance-monitoring) - - [Pattern 3: Comparative Analysis](#pattern-3-comparative-analysis) -- [Best Practices](#best-practices) -- [Common Use Cases Summary](#common-use-cases-summary) -- [Reference Links](#reference-links) - - -## Multiple Panes - -Multiple panes allow you to divide the chart area into separate plotting regions, ideal for comparing different data series or displaying related metrics with different scales. - -### When to Use -- Comparing series with vastly different value ranges -- Creating dashboard-style layouts with multiple related charts -- Financial charts showing price and volume data -- Weather charts displaying temperature and humidity - -### Creating Rows (Horizontal Division) +# Advanced Features -```razor - - - - - - - - - - - - - - - - -``` +> **Verified against source** — verified against +> `src/Components/Charts/Chart/SfChart.razor.Methods.cs`, +> `src/Components/Charts/Chart/StriplineRenderer/`, +> `src/Components/Charts/Chart/UserInteractions/`. Last source audit: +> **2026-08-24**. -### Creating Columns (Vertical Division) +Covers multi-pane layouts, trend lines, strip lines, +multiple axes, data editing, empty points, RTL, and notes that print +and export are **not implemented** in this toolkit. Each section links +out to the place it inherits from — this file focuses on **what's +specific** to each feature. -```razor - - - - - - - - - - - - - - - - -``` - -### Configuration Options -- `Height`/`Width`: Set pane dimensions (percentage or pixels) -- `RowIndex`/`ColumnIndex`: Bind axis to specific pane -- `Span`: Span axis across multiple panes -- `Border`: Customize pane boundaries - ---- - -## Technical Indicators - -Technical indicators are mathematical calculations based on historical price, volume, or open interest data, used primarily in financial chart analysis. +> **Sample data** — see [`_includes/sample-data.md`](_includes/sample-data.md). +> This file declares `SamplePoint` (string X, double Y, double Y2 = 0) +> and `FinancePoint` records; snippets bind to the `Data` list of +> `SamplePoint`. -### When to Use -- Stock market analysis and trading platforms -- Financial forecasting applications -- Technical analysis dashboards -- Real-time market monitoring +## Table of contents +- Multiple panes (rows / columns) +- Trend lines (Linear, Polynomial, Exponential, Logarithmic, Power, Moving-Avg) + forecasting +- Strip lines (see also `axes-and-scales.md`) +- Multiple axes (see also `axes-and-scales.md`) +- Data editing +- Empty points +- RTL (configured via global `options.EnableRtl`) +## Multiple panes — split the chart into rows or columns -### Bollinger Bands +Use `` for horizontal split, `` for vertical. +Series bound to a pane use `` in ``. ```razor - - - - - - -``` - -### MACD (Moving Average Convergence Divergence) + + -```razor - - - - - -``` + + + + -### Available Indicators -- **SMA**: Simple Moving Average -- **EMA**: Exponential Moving Average -- **TMA**: Triangular Moving Average -- **RSI**: Relative Strength Index -- **MACD**: Moving Average Convergence Divergence -- **Bollinger Bands**: Volatility indicator -- **ATR**: Average True Range -- **Stochastic**: Momentum indicator -- **Momentum**: Rate of price change -- **Accumulation Distribution**: Volume flow indicator + + + ---- + -## Trend Lines + + +``` -Trend lines visualize the direction and pace of data trends using mathematical regression models. +`` works the same way with `ColumnIndex` instead of +`RowIndex`. Percentages in `Height` / `Width` resolve against the chart +area, not the page. -### When to Use -- Forecasting future data points -- Identifying data patterns and correlations -- Scientific data analysis -- Business intelligence dashboards +## Trend lines -### Linear Trend Line +`` is required (plural). It lives inside the *series*. ```razor - - + - + + + + + ``` -### Polynomial Trend Line - -```razor - - - -``` - -### Exponential Trend Line - -```razor - - - -``` - -### Logarithmic Trend Line - -```razor - - - -``` - -### Moving Average Trend Line - -```razor - - - -``` - -### Forecasting with Trend Lines +Add `ForwardForecast="N" BackwardForecast="M"` to extrapolate outside the +data range. -```razor - - - -``` - -### Configuration Options -- `Type`: Linear, Exponential, Logarithmic, Polynomial, Power, MovingAverage -- `Width`: Line thickness -- `Fill`: Trend line color -- `ForwardForecast`: Predict future points -- `BackwardForecast`: Show historical trend -- `Period`: Moving average calculation period -- `PolynomialOrder`: Degree for polynomial trends - ---- - -## Strip Lines - -Strip lines are horizontal or vertical bands that highlight specific ranges or thresholds in the chart. +## Strip lines — see `axes-and-scales.md` -### When to Use -- Highlighting target ranges or thresholds -- Marking acceptable/warning/critical zones -- Showing business hours or time periods -- Indicating baseline or benchmark values - -### Horizontal Strip Lines +Quick form: ```razor - + - - - - - - - - + + + ``` -### Vertical Strip Lines - -```razor - - - - - - -``` - -### Segmented Strip Lines - -```razor - - - - - -``` - -### Strip Line with Custom Text - -```razor - - - - -``` - -### Strip Line with Tooltip - -```razor - - - - - -``` - -### Configuration Options -- `Start`/`End`: Define strip line boundaries -- `Color`: Background color -- `Opacity`: Transparency level -- `ZIndex`: Drawing order (Behind/Over) -- `IsSegmented`: Create partial strip lines -- `Size`: Alternative to End for fixed width -- `StartFromAxis`: Begin from axis origin - ---- - -## Multiple Axes - -Multiple axes enable displaying series with different scales or units on the same chart. - -### When to Use -- Comparing metrics with different units (e.g., temperature and rainfall) -- Financial charts with price and volume -- Dual-scale dashboards -- Correlation analysis - -### Dual Y-Axes - -```razor - - - - - - - - - - - - - - - -``` - -### Multiple X and Y Axes - -```razor - - - - - - - - - - - - -``` - -### Configuration Options -- `Name`: Unique identifier for axis -- `OpposedPosition`: Place on opposite side -- `RowIndex`/`ColumnIndex`: Position in multi-pane layout -- `Span`: Span across multiple panes -- All standard axis properties (min, max, interval, etc.) - ---- - -## Data Editing - -Data editing allows users to interactively drag and modify data points at runtime. - -### When to Use -- Interactive data entry applications -- Manual data adjustment tools -- What-if analysis scenarios -- Training and simulation applications - -### Basic Data Editing - -```razor - - - - - - - - - - - - - - - - -``` - -### Configuration Options -- `Enable`: Enable/disable data editing -- `Fill`: Color for edited points -- `MinY`/`MaxY`: Restrict editing range - ---- - -## Empty Points - -Handle missing or null data points with various rendering modes. - -### When to Use -- Datasets with incomplete information -- Time series with gaps -- Sensor data with occasional failures -- Survey results with non-responses - -### Empty Point Modes - -```razor - - - - - - - - - - - - - - - - - - - - - - -``` - -### Empty Point Modes Explained -- **Zero**: Treats null/undefined as zero value -- **Average**: Calculates average of adjacent points -- **Gap**: Shows break in continuity (line/area charts) -- **Drop**: Completely ignores the point - ---- - -## Chart Export - -Export rendered charts to various formats for reporting and sharing. - -### When to Use -- Generating reports and presentations -- Saving charts for offline viewing -- Email attachments and documentation -- Archiving visualizations - -### Export to Image Formats - -```razor -@using Syncfusion.Blazor.Toolkit.Charts -@using Syncfusion.Blazor.Buttons - - - - - -
- - - -
- -@code { - SfChart ChartRef; - - private async Task ExportPNG() => - await ChartRef.ExportAsync(ExportType.PNG, "chart"); - - private async Task ExportJPEG() => - await ChartRef.ExportAsync(ExportType.JPEG, "chart"); - - private async Task ExportSVG() => - await ChartRef.ExportAsync(ExportType.SVG, "chart"); -} -``` - -### Export to PDF - -```razor - - -@code { - private async Task ExportPDF() - { - await ChartRef.ExportAsync(ExportType.PDF, "report", - PdfPageOrientation.Landscape); - } -} -``` - -### Export to Excel (XLSX/CSV) - -```razor - - - -@code { - private async Task ExportExcel() => - await ChartRef.ExportAsync(ExportType.XLSX, "data"); - - private async Task ExportCSV() => - await ChartRef.ExportAsync(ExportType.CSV, "data"); -} -``` - -### Export as Base64 String +`ZIndex="Syncfusion.Blazor.Toolkit.ZIndexPosition.Behind"` paints the strip line below the data +(`ZIndexPosition` lives in `Syncfusion.Blazor.Toolkit`). Strip lines +work on both `X` and `Y` axes. See `axes-and-scales.md` for `IsSegmented`, +custom text, and tooltip-enabled striplines. -```razor - - -@code { - private async Task ExportBase64() - { - await ChartRef.ExportAsync(ExportType.PDF, "chart", - PdfPageOrientation.Portrait, allowDownload: false, isBase64: true); - } - - private void ExportComplete(ExportEventArgs args) - { - string base64String = args.Base64; - // Use base64 string for custom operations - } -} -``` +## Multiple axes — see `axes-and-scales.md` -### Customize Export with Events +Quick form: ```razor - - -@code { - private void BeforeExport(ChartExportEventArgs args) - { - // Customize dimensions - args.Width = 1200; - args.Height = 800; - - // For Excel exports, customize workbook - if (args.Workbook != null) - { - var sheet = args.Workbook.Worksheets.First(); - sheet.Rows[0].Cells[0].CellStyle.BackColor = "#4472C4"; - sheet.Rows[0].Cells[0].CellStyle.Bold = true; - } - } -} + + + + ``` -### Export Multiple Charts - -```razor -
- ... - ... -
- - - -@code { - ElementReference ChartContainer; - SfChart Chart1; - - private async Task ExportAll() => - await Chart1.PrintAsync(ChartContainer); -} -``` - -### Supported Export Formats -- **PNG**: Raster image format -- **JPEG**: Compressed image format -- **SVG**: Vector graphics format -- **PDF**: Portable document format -- **XLSX**: Excel workbook -- **CSV**: Comma-separated values - ---- - -## Print - -Print charts directly from the browser with customization options. +See `axes-and-scales.md` for axis-range, label-format, and naming rules. -### When to Use -- Creating hard copies for meetings -- Generating physical reports -- Archiving visualizations -- Presentation materials - -### Basic Printing - -```razor - - - - - - -@code { - SfChart ChartRef; - - private async Task PrintChart() => await ChartRef.PrintAsync(); -} -``` - -### Print Multiple Charts - -```razor - - - - -@code { - ElementReference PrintContainer; - SfChart Chart1; - - private async Task PrintAll() => - await Chart1.PrintAsync(PrintContainer); -} -``` +## Data editing -### Print-Specific Styling +Enables drag-to-edit on each point of a series. Bind `OnDataEdit` / +`OnDataEditCompleted` (see `events.md`). ```razor - + + + + ``` ---- - -## RTL Support +Always set `MinY` / `MaxY` to the same scale as your Y axis or you'd end up +with a dragged bar outside the visible chart area. -Right-to-left (RTL) rendering for internationalization in languages like Arabic and Hebrew. +## Empty points -### When to Use -- Applications supporting RTL languages -- Multi-language dashboard applications -- Internationalized reporting tools -- Global market applications - -### Enabling RTL Mode +Inside a series: ```razor - - - - - - -``` - -### RTL with Localization - -```razor - - - - - - - - - - + + + ``` -### RTL Configuration -- `EnableRtl`: Enable right-to-left rendering -- `Locale`: Set culture-specific formatting -- Automatically mirrors: legends, tooltips, data labels -- Reverses: axis direction, series rendering order +| `EmptyPointMode` | Effect | +|------------------|--------| +| `Zero` | null becomes 0 (only reasonable when interpretation is numeric) | +| `Average` | interpolates between neighbours | +| `Gap` | leaves a hole in line/area charts | +| `Drop` | drops the point entirely | ---- - -## Implementation Patterns - - - -### Pattern 2: Performance Monitoring +## RTL ```razor - - - - - - - - - - - - - -``` - -### Pattern 3: Comparative Analysis +@* RTL is configured globally at toolkit registration, not per-chart. *@ +@* Program.cs: *@ +@* builder.Services.AddSyncfusionBlazorToolkit(o => o.EnableRtl = true); *@ -```razor - - - - - - - - - - - - - - - - - - - - - + + + … ``` ---- - -## Best Practices - -1. **Performance Optimization** - - Limit number of technical indicators (use max 3-4) - - Use data editing judiciously for large datasets - - Consider data aggregation for trend lines on large datasets - -2. **User Experience** - - Provide clear labels for multiple axes - - Use contrasting colors for strip lines - - Include legends when using multiple indicators - - Add tooltips for interactive features - -3. **Accessibility** - - Use sufficient color contrast for strip lines - - Provide text alternatives for visual indicators - - Enable keyboard navigation for data editing - - Support screen readers with proper ARIA labels - -4. **Export Optimization** - - Set appropriate dimensions before export - - Use vector formats (SVG, PDF) for scalable output - - Optimize image quality vs. file size for raster formats - - Include chart title and legends in exports - -5. **RTL Considerations** - - Test thoroughly with actual RTL content - - Ensure custom styling respects RTL mode - - Verify numeric formatting in RTL cultures - - Check tooltip and legend positioning - ---- - -## Common Use Cases Summary - -| Feature | Primary Use Case | Best Chart Types | -|---------|-----------------|------------------| -| Multiple Panes | Financial analysis, Multi-metric dashboards | Line, Column | -| Technical Indicators | Stock trading, Market analysis | Line | -| Trend Lines | Forecasting, Pattern recognition | Scatter, Line, Area | -| Strip Lines | Threshold monitoring, Range highlighting | All types | -| Multiple Axes | Dual-scale comparison | Line, Column, Area | -| Data Editing | Interactive forecasting, Manual adjustment | Column, Line, Scatter | -| Empty Points | Incomplete data handling | Line, Area, Spline | -| Export | Reporting, Documentation | All types | -| Print | Hard copy generation | All types | -| RTL | International applications | All types | - ---- \ No newline at end of file +The `EnableRtl` flag on `SyncfusionBlazorToolkitOptions` flips the chart +direction (axes, legend, tooltips). It is **read internally** by +`SfChart.EnableRtl` (verified at +`src/Components/Charts/Chart/SfChart.razor.Members.cs:401`, +`internal bool EnableRtl => …`), so do not put `EnableRtl="true"` on +`` — that parameter does not exist. To localize the labels, +also set the host's `CultureInfo.CurrentCulture` to the target locale; +the chart picks it up. See `accessibility-internationalization.md` for the +full i18n setup. + +## Common implementation patterns + +| Pattern | Use it for | Read | +|---------|-----------|------| +| Financial dashboard | Ticker + indicator (MACD/Bollinger) | Indicators section above | +| Performance monitor | Metric + threshold strip lines | Strip lines + `axes-and-scales.md` | +| Sales by region (multi-axis) | Two metrics, different units | Multiple axes section above | +| Live updating chart | Streaming feed | `data-handling.md` (real-time updates) | \ No newline at end of file diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/references/api-reference.md b/.github/skills/syncfusion-blazor-toolkit-charts/references/api-reference.md index bc2b0ba..55fee98 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/references/api-reference.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/references/api-reference.md @@ -1,4 +1,10 @@ -# Syncfusion Blazor Charts - Complete API Reference +# Syncfusion Blazor Charts - Complete API Reference + +> **Verified against source** — when this and the source code diverge, +> **source wins**. Enum members verified against +> `src/Base/Enumeration.cs`. Method signatures verified against +> `src/Components/Charts/Chart/SfChart.razor.Methods.cs`. Last source +> audit: **2026-08-24**. ## Table of Contents @@ -11,7 +17,6 @@ - [SelectionMode](#selectionmode) - [HighlightMode](#highlightmode) - [SelectionPattern](#selectionpattern) - - [ExportType](#exporttype) - [LegendPosition](#legendposition) - [EmptyPointMode](#emptypointmode) - [LabelPlacement](#labelplacement) @@ -19,7 +24,6 @@ - [LabelIntersectAction](#labelintersectaction) - [ChartShape](#chartshape) - [TrendlineTypes](#trendlinetypes) - - [TechnicalIndicators](#technicalindicators) - [ZoomMode](#zoommode) - [ToolbarItems](#toolbaritems) - [Theme](#theme) @@ -79,84 +83,24 @@ public Task RefreshAsync(bool shouldAnimate = true) --- -#### ExportAsync(ExportType type, string fileName, PdfPageOrientation? orientation = null, bool allowDownload = true, bool isBase64 = false) - -Exports the chart to various formats (PDF, PNG, JPEG, SVG). - -```csharp -public Task ExportAsync(ExportType type, string fileName, PdfPageOrientation? orientation = null, bool allowDownload = true, bool isBase64 = false) -``` - -**Parameters:** -- `type` - The export format (`ExportType` enum) -- `fileName` - The name of the exported file -- `orientation` - PDF page orientation (Portrait/Landscape) -- `allowDownload` - Whether to download the file -- `isBase64` - Whether to return as base64 string - -**Returns:** `Task` - -**Example:** -```razor - - - - -@code { - SfChart ChartRef; - - async Task ExportChart() - { - await ChartRef.ExportAsync(ExportType.PNG, "SalesChart"); - } -} -``` - ---- -#### PrintAsync(ElementReference elementRef = default) -Prints the chart. -```csharp -public Task PrintAsync(ElementReference elementRef = default) -``` -**Parameters:** -- `elementRef` - Optional reference to the chart element - -**Returns:** `Task` - -**Example:** -```razor - - - - -@code { - SfChart ChartRef; - - async Task PrintChart() - { - await ChartRef.PrintAsync(); - } -} -``` - ---- - -#### ShowTooltip(object x, double y, bool isPoint = true) +#### ShowTooltipAsync(object x, double y, bool isPoint = true) Displays tooltip at specified coordinates or data points. ```csharp -public void ShowTooltip(object x, double y, bool isPoint = true) +public Task ShowTooltipAsync(object x, double y, bool isPoint = true) ``` **Parameters:** - `x` - X-value of the point or x-coordinate -- `y` - Y-value of the point or y-coordinate -- `isPoint` - Whether x and y are data points (true) or coordinates (false) +- `y` - Y-value of the point or y-coordinate +- `isPoint` - Whether x and y are data points (true) or coordinates (false). Default `true`. + +**Returns:** `Task` **Example:** ```razor @@ -166,50 +110,49 @@ public void ShowTooltip(object x, double y, bool isPoint = true) @code { - SfChart ChartRef; - - void DisplayTooltip() + SfChart ChartRef = default!; + + async Task DisplayTooltip() { - ChartRef.ShowTooltip("January", 35); + await ChartRef.ShowTooltipAsync("January", 35); } } ``` --- -#### HideTooltip() +#### HideTooltipAsync() Hides the currently displayed tooltip. ```csharp -public void HideTooltip() +public Task HideTooltipAsync() ``` **Example:** ```razor @code { - SfChart ChartRef; - - void HideChartTooltip() - { - ChartRef.HideTooltip(); - } + SfChart ChartRef = default!; + + async Task HideChartTooltip() => await ChartRef.HideTooltipAsync(); } ``` --- -#### ShowCrosshair(double x, double y) +#### ShowCrosshairAsync(double x, double y) Displays crosshair at specified coordinates. ```csharp -public void ShowCrosshair(double x, double y) +public Task ShowCrosshairAsync(double x, double y) ``` **Parameters:** -- `x` - X-coordinate on the chart -- `y` - Y-coordinate on the chart +- `x` - X-coordinate on the chart (pixels) +- `y` - Y-coordinate on the chart (pixels) + +**Returns:** `Task` **Example:** ```razor @@ -219,34 +162,31 @@ public void ShowCrosshair(double x, double y) @code { - SfChart ChartRef; - - void DisplayCrosshair() + SfChart ChartRef = default!; + + async Task DisplayCrosshair() { - ChartRef.ShowCrosshair(100, 50); + await ChartRef.ShowCrosshairAsync(100, 50); } } ``` --- -#### HideCrosshair() +#### HideCrosshairAsync() Hides the currently displayed crosshair. ```csharp -public void HideCrosshair() +public Task HideCrosshairAsync() ``` **Example:** ```razor @code { - SfChart ChartRef; - - void HideChartCrosshair() - { - ChartRef.HideCrosshair(); - } + SfChart ChartRef = default!; + + async Task HideChartCrosshair() => await ChartRef.HideCrosshairAsync(); } ``` @@ -262,30 +202,31 @@ public void ClearSelection() **Example:** ```razor - + @code { - SfChart ChartRef; - - void ClearAllSelections() - { - ChartRef.ClearSelection(); - } + SfChart ChartRef = default!; + + void ClearAllSelections() => ChartRef.ClearSelection(); } ``` --- -#### Sort(string propertyName, ListSortDirection direction) +#### Sort(string propertyName, Syncfusion.Blazor.Toolkit.Data.ListSortDirection direction) Sorts chart data by property name and direction. ```csharp -public void Sort(string propertyName, ListSortDirection direction) +// Verified at src/Components/Charts/Chart/SfChart.razor.Methods.cs +public void Sort(string propertyName, Syncfusion.Blazor.Toolkit.Data.ListSortDirection direction) ``` +> **Don't** use `System.ComponentModel.ListSortDirection`; it is not +> assignable. The toolkit ships its own `Syncfusion.Blazor.Toolkit.Data.ListSortDirection`. + **Parameters:** - `propertyName` - Property name to sort by - `direction` - Sort direction (`Ascending` or `Descending`) @@ -302,7 +243,7 @@ public void Sort(string propertyName, ListSortDirection direction) void SortByValue() { - ChartRef.Sort("Y", ListSortDirection.Descending); + ChartRef.Sort("Y", Syncfusion.Blazor.Toolkit.Data.ListSortDirection.Descending); } } ``` @@ -427,20 +368,22 @@ public enum ValueType --- -### SelectionMode +### ChartSelectionMode -Specifies the selection mode. +Specifies the selection mode. **Note the `Chart` prefix in the type +name** — it is not bare `SelectionMode`. Defined in +`Syncfusion.Blazor.Toolkit`. NS: `Syncfusion.Blazor.Toolkit`. ```csharp -public enum SelectionMode +public enum ChartSelectionMode { None, Series, Point, Cluster, DragXY, - DragX, DragY, + DragX, Lasso } ``` @@ -510,27 +453,34 @@ public enum SelectionPattern --- -### ExportType +### ToolbarMode -Specifies export types. +Controls when the zoom toolbar is visible. ```csharp -public enum ExportType +public enum ToolbarMode { - PNG, - JPEG, - SVG, - PDF + OnDemand = 0, // toolbar shown only while chart is zoomed + Always = 1, // always visible + None = 2 // never visible } ``` -**Values:** -- `PNG` - Export as PNG image -- `JPEG` - Export as JPEG image -- `SVG` - Export as SVG vector -- `PDF` - Export as PDF document +NS: `Syncfusion.Blazor.Toolkit`. ---- +### ZIndexPosition + +Controls whether the strip line paints over or behind the series. + +```csharp +public enum ZIndexPosition +{ + Over, + Behind +} +``` + +NS: `Syncfusion.Blazor.Toolkit`. ### LegendPosition @@ -648,24 +598,29 @@ public enum LabelIntersectAction ### ChartShape -Specifies marker shapes. +Specifies marker shapes. NS: `Syncfusion.Blazor.Toolkit`. ```csharp public enum ChartShape { - Circle, - Rectangle, - Triangle, - Diamond, - Pentagon, - Cross, - HorizontalLine, - VerticalLine, - InvertedTriangle, - Image + Circle = 0, + Triangle = 1, + Diamond = 2, + Rectangle = 3, + Pentagon = 4, + InvertedTriangle = 5, + VerticalLine = 6, + Cross = 7, + Plus = 8, + HorizontalLine = 9, + Image = 10, + Auto = 11 } ``` +Use `Syncfusion.Blazor.Toolkit.ChartShape.Auto` to let the chart pick a different shape per series +automatically. `Plus` is a valid shape distinct from `Cross`. + --- ### TrendlineTypes @@ -694,39 +649,6 @@ public enum TrendlineTypes --- -### TechnicalIndicators - -Specifies technical indicator types. - -```csharp -public enum TechnicalIndicators -{ - Sma, - Ema, - Tma, - Momentum, - Atr, - AccumulationDistribution, - Bollinger, - Macd, - Stochastic, - Rsi -} -``` - -**Common Values:** -- `Sma` - Simple Moving Average -- `Ema` - Exponential Moving Average -- `Tma` - Triangular Moving Average -- `Momentum` - Momentum indicator -- `Rsi` - Relative Strength Index -- `Macd` - Moving Average Convergence Divergence -- `Bollinger` - Bollinger Bands -- `Atr` - Average True Range -- `Stochastic` - Stochastic oscillator - ---- - ### ZoomMode Specifies zooming mode. @@ -764,43 +686,35 @@ public enum ToolbarItems --- -### Theme +### Theme -Specifies chart themes. Use `Syncfusion.Blazor.Theme` enum for setting the `Theme` property of `SfChart`. - -**IMPORTANT:** The enum name is `Theme`, not `ChartTheme`. Use it as `Theme="Syncfusion.Blazor.Theme.Material"` or `Theme="Theme.Material"` (with proper using directive). +Specifies chart themes. The `Theme` enum lives in the root toolkit +namespace `Syncfusion.Blazor.Toolkit.Theme` (per `src/Base/Enumeration.cs`) +and ships **only** two values in this toolkit: `Fluent` (default) and +`FluentDark`. Older guidance that points to `Syncfusion.Blazor.Theme.*` +or to Material/Bootstrap5/Tailwind/HighContrast members belongs to the +legacy `Syncfusion.Blazor` product and **does not apply here** — using an +unknown enum value compiles to silence and renders nothing. ```csharp public enum Theme { - Material, - Fabric, - Bootstrap, - Bootstrap4, - HighContrastLight, - MaterialDark, - FabricDark, - BootstrapDark, - Bootstrap4Dark, - HighContrast, - Tailwind, - TailwindDark, - Bootstrap5, - Bootstrap5Dark, - Fluent, - FluentDark, - Material3, - Material3Dark + Fluent, // default — light background, dark text, neutral accents + FluentDark // dark background, light text } ``` **Usage Example:** ```razor - + ``` +> **Don't** use `Theme.HighContrast`, `Theme.Material`, `Theme.Bootstrap5`, +> `Theme.Tailwind`, etc. — they are not part of this toolkit. + --- ## Key Classes and Components @@ -844,16 +758,17 @@ public LabelIntersectAction LabelIntersectAction { get; set; } ### ChartTooltipSettings -Configures tooltip behavior. +Configures tooltip behavior. Verified against +`src/Components/Charts/Chart/UserInteractions/Models/ChartTooltipSettings.cs`. **Key Properties:** ```csharp -public bool Enable { get; set; } +public bool Enable { get; set; } // default false public string Format { get; set; } public bool Shared { get; set; } public string Fill { get; set; } -public string TextStyle { get; set; } -public RenderFragment Template { get; set; } +public ChartTooltipTextStyle TextStyle { get; set; } // *typed* +public RenderFragment? Template { get; set; } ``` --- @@ -892,30 +807,46 @@ public ToolbarItems[] ToolbarItems { get; set; } ## Important Notes -1. **Correct Enum Usage**: Always use the fully qualified enum name: +1. **Correct enum usage**: Use fully-qualified enum names in the default + sample layout (which imports only `Syncfusion.Blazor.Toolkit.Charts`): ```razor - Type="ChartSeriesType.Column" - Type="Syncfusion.Blazor.Toolkit.ChartSeriesType.Column" + + + + + ``` -2. **Method Naming**: All public methods use proper C# naming conventions: - - `RefreshAsync()` - NOT `Refresh()` - - `ExportAsync()` - NOT `Export()` - - `ShowTooltip()` - NOT `Show_Tooltip()` +2. **Method naming**: Programmatic methods on `SfChart` are `*Async` + when they return `Task`, and `void` (no suffix) for sync helpers. + + | Async `Task` (public) | Sync `void` (public) | + |------------------------|------------------------| + | `RefreshAsync`, `ShowTooltipAsync`, `HideTooltipAsync`, `ShowCrosshairAsync`, `HideCrosshairAsync` | `Sort`, `ClearSort`, `ClearSelection`, `PreventRender` | -3. **Namespace**: Always include the namespace import: + Methods marked `` (decorated with + `[EditorBrowsable(EditorBrowsableState.Never)]`) include + `AddSeriesAsync`, `RemoveSeries`, `ClearSeries`, `RefreshLiveData`. + They compile and run, but are not visible in IntelliSense. Treat them + as **internal surface** unless your team has committed to using them; + the public API at the chart layer is just refresh/show/hide/sort. + +3. **Namespaces** — the standard pair: ```razor - @using Syncfusion.Blazor.Toolkit.Charts + @using Syncfusion.Blazor.Toolkit // enum roots & Theme + @using Syncfusion.Blazor.Toolkit.Charts // SfChart, components ``` -4. **Component Reference**: To call methods, use `@ref`: + `TextWrap` lives in the **root** `Syncfusion.Blazor` namespace (not the + toolkit). Pages that set `TextWrap="…" on ChartLegendSettings also need + `@using Syncfusion.Blazor;` or must use the fully qualified + `Syncfusion.Blazor.TextWrap.Wrap`. + +4. **Component reference**: To call methods, use `@ref`: ```razor - - - - @code { - SfChart ChartRef; - } + + @code { SfChart ChartRef = default!; } ``` --- @@ -925,17 +856,18 @@ public ToolbarItems[] ToolbarItems { get; set; } ### Basic Chart with Data ```razor +@using Syncfusion.Blazor.Toolkit @using Syncfusion.Blazor.Toolkit.Charts - - - + + + @code { @@ -962,13 +894,13 @@ public ToolbarItems[] ToolbarItems { get; set; } - - - - - - - -@code { - public class SalesInfo - { - public string Month { get; set; } - public double Revenue { get; set; } - } - - public List SalesData = new List - { - new SalesInfo { Month = "Jan", Revenue = 35 }, - new SalesInfo { Month = "Feb", Revenue = 28 }, - new SalesInfo { Month = "Mar", Revenue = 34 }, - new SalesInfo { Month = "Apr", Revenue = 32 }, - new SalesInfo { Month = "May", Revenue = 40 } - }; -} -``` - -### Percentage-Based Sizing - -Use percentages to make charts responsive to their container: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - -@code { - public class RevenueInfo - { - public string Quarter { get; set; } - public double Amount { get; set; } - } - - public List RevenueData = new List - { - new RevenueInfo { Quarter = "Q1", Amount = 120000 }, - new RevenueInfo { Quarter = "Q2", Amount = 135000 }, - new RevenueInfo { Quarter = "Q3", Amount = 145000 }, - new RevenueInfo { Quarter = "Q4", Amount = 160000 } - }; -} -``` - -### Container-Based Sizing - -Scale charts to fit within a container using CSS styles: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - -
- - - - - -
- -@code { - public class MetricInfo - { - public string Metric { get; set; } - public double Value { get; set; } - } - - public List MetricsData = new List - { - new MetricInfo { Metric = "Speed", Value = 85 }, - new MetricInfo { Metric = "Quality", Value = 92 }, - new MetricInfo { Metric = "Efficiency", Value = 78 } - }; -} -``` - ---- - -## Color Customization - -Control chart colors through color palettes, series-specific colors, and point-level customization. - -### Custom Color Palette - -Define a custom palette to apply colors consistently across all series: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - -@code { - public class MedalInfo - { - public string Country { get; set; } - public double Gold { get; set; } - public double Silver { get; set; } - public double Bronze { get; set; } - } - - public List MedalData = new List - { - new MedalInfo { Country = "USA", Gold = 46, Silver = 37, Bronze = 38 }, - new MedalInfo { Country = "China", Gold = 38, Silver = 32, Bronze = 18 }, - new MedalInfo { Country = "UK", Gold = 27, Silver = 23, Bronze = 17 }, - new MedalInfo { Country = "Japan", Gold = 27, Silver = 14, Bronze = 17 } - }; - - public string[] CustomPalette = new string[] { "#FFD700", "#C0C0C0", "#CD7F32" }; -} -``` - -### Series-Specific Colors - -Apply individual colors to each series using the Fill property: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - -@code { - public class ProductInfo - { - public string Product { get; set; } - public double Sales { get; set; } - public double Target { get; set; } - } - - public List ProductData = new List - { - new ProductInfo { Product = "Laptop", Sales = 120, Target = 150 }, - new ProductInfo { Product = "Phone", Sales = 210, Target = 200 }, - new ProductInfo { Product = "Tablet", Sales = 80, Target = 100 } - }; -} -``` - -### Point-Level Color Customization - -Customize individual data point colors: +# Appearance & Styling + +> **Verified against source** — `Theme` enum, `Palettes` parameter, +> animation and chart-area wiring verified against +> `src/Base/Enumeration.cs` and +> `src/Components/Charts/Chart/SfChart.razor.Members.cs`. Last source +> audit: **2026-08-24**. + +Covers dimensions, colors, background, borders, margins, title/subtitle, +themes, series styling, and responsive sizing for `SfChart`. + +> **Convention for every snippet in this reference.** Add the namespace +> once and reuse a single sample data set: +> +> ```razor +> @using Syncfusion.Blazor.Toolkit.Charts +> +> @code { +> // One record covers most snippets; pick one of: +> public record CategoryValue(string Name, double Value); +> public record MonthSeries(string Month, double Sales, double Target = 0, int Count = 0); +> +> private readonly List SampleData = new() +> { +> new("Jan", 35), new("Feb", 28), new("Mar", 34), new("Apr", 32), +> new("May", 40), new("Jun", 32) +> }; +> +> private readonly List DashboardData = new() +> { +> new("Jan", 35000, 40000), new("Feb", 42000, 40000), +> new("Mar", 38000, 40000), new("Apr", 45000, 45000) +> }; +> +> private string[] CorporatePalette = new[] { "#1976D2", "#388E3C", "#F57C00", "#7B1FA2" }; +> private string[] CvdSafePalette = new[] { "#0173B2", "#DE8F05", "#029E73", "#CA9161" }; +> } +> ``` +> +> Replace `DataSource="@SampleData"` with `@DashboardData` and adapt +> `XName` / `YName` as needed. Treat all snippets in this file as +> templates — paste, then change the data class name. + +## Table of contents + +- Dimensions (pixels, %, container) +- Color customization (palette, per-series, point-level) +- Background & border (chart, area, margin) +- Title & subtitle styling +- Themes (built-in + custom palette) +- Series styling (fill, opacity, border, animation) +- Responsive sizing +- Best practices + +## Dimensions ```razor -@using Syncfusion.Blazor.Toolkit.Charts + + - - - - - + + -@code { - public class ProjectPhase - { - public string Phase { get; set; } - public double Completion { get; set; } - public string Color { get; set; } - } - - public List ProjectData = new List - { - new ProjectPhase { Phase = "Planning", Completion = 100, Color = "#4CAF50" }, - new ProjectPhase { Phase = "Development", Completion = 75, Color = "#FF9800" }, - new ProjectPhase { Phase = "Testing", Completion = 40, Color = "#F44336" }, - new ProjectPhase { Phase = "Deployment", Completion = 0, Color = "#9E9E9E" } - }; -} + +
``` ---- - -## Chart Background and Border - -Customize the overall appearance of your chart with background colors and borders. +Default is **600×450px**; collapse to zero if you forget the parent height. -### Background Color - -Set the chart background using the Background property: +## Color customization ```razor -@using Syncfusion.Blazor.Toolkit.Charts + + - - - - - + + -@code { - public class TempInfo - { - public string Month { get; set; } - public double Temp { get; set; } - } - - public List TemperatureData = new List - { - new TempInfo { Month = "Jan", Temp = 15 }, - new TempInfo { Month = "Feb", Temp = 18 }, - new TempInfo { Month = "Mar", Temp = 22 }, - new TempInfo { Month = "Apr", Temp = 26 } - }; -} + + ``` -### Border Styling +`PointColorMapping` expects a *string* property on each row holding any CSS color. -Add borders to your chart with customizable color and width: +## Background, border, area, margin ```razor -@using Syncfusion.Blazor.Toolkit.Charts - - + - - - - - - -@code { - public class YearRevenue - { - public string Year { get; set; } - public double Revenue { get; set; } - } - - public List RevenueData = new List - { - new YearRevenue { Year = "2020", Revenue = 1200000 }, - new YearRevenue { Year = "2021", Revenue = 1450000 }, - new YearRevenue { Year = "2022", Revenue = 1680000 }, - new YearRevenue { Year = "2023", Revenue = 1920000 } - }; -} -``` - - ---- - -## Chart Area Customization - -The chart area is the region where data is plotted. Customize its background, border, and width. - -### Chart Area Background - -Set a distinct background for the plotting area: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - -@code { - public class QuarterlySales - { - public string Quarter { get; set; } - public double Sales { get; set; } - } - - public List SalesData = new List - { - new QuarterlySales { Quarter = "Q1", Sales = 150000 }, - new QuarterlySales { Quarter = "Q2", Sales = 175000 }, - new QuarterlySales { Quarter = "Q3", Sales = 195000 }, - new QuarterlySales { Quarter = "Q4", Sales = 220000 } - }; -} -``` - -### Chart Area Border - -Add a border around the chart plotting area: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - + + + - - - - + … - -@code { - public class CustomerInfo - { - public string Month { get; set; } - public double Customers { get; set; } - } - - public List CustomerData = new List - { - new CustomerInfo { Month = "Jan", Customers = 1200 }, - new CustomerInfo { Month = "Feb", Customers = 1450 }, - new CustomerInfo { Month = "Mar", Customers = 1680 }, - new CustomerInfo { Month = "Apr", Customers = 1920 } - }; -} ``` -### Chart Area Width +`Width`/`Height` of `ChartArea` are **percent of the inner plot area**, not of +the whole chart. Use `ChartMargin` to leaves room for title/legend. -Control the width of the chart area as a percentage: +## Title & subtitle ```razor -@using Syncfusion.Blazor.Toolkit.Charts + + + - - - - - - - - + - -@code { - public class ExpenseCategory - { - public string Category { get; set; } - public double Amount { get; set; } - } - - public List ExpenseData = new List - { - new ExpenseCategory { Category = "Housing", Amount = 2500 }, - new ExpenseCategory { Category = "Food", Amount = 800 }, - new ExpenseCategory { Category = "Transport", Amount = 500 }, - new ExpenseCategory { Category = "Entertainment", Amount = 400 } - }; -} ``` ---- +`ChartTitlePosition` values: `Top`, `Bottom`. Use subclass `ChartTitleFont` / +`ChartSubTitleFont` for **legacy** examples in older docs; new code uses the +*Style child above. -## Chart Margins +## Themes (`SfChart.Theme` parameter) -Configure spacing between the chart and its container using margin properties. +`SfChart` themes are an **in-C# enum**, declared in +`src/Base/Enumeration.cs`. They are a `SfChart` parameter, not a CSS layer — +do not generate a separate SCSS file for the chart. The enum currently +exposes **two values**: -### Basic Margin Configuration +| Value | Visual | When to use | +|---|---|---| +| `Syncfusion.Blazor.Toolkit.Theme.Fluent` *(default)* | Light background, dark text, neutral accents | Light-mode app, default look | +| `Syncfusion.Blazor.Toolkit.Theme.FluentDark` | Dark background, light text, adjusted accents | Dark-mode app, dark-mode toggle | -Set uniform margins around the chart: +> **Older docs reference `Theme.Material`, `Theme.Bootstrap5`, +> `Theme.Tailwind`, or `Theme.HighContrast`.** None of those values exist +> in `Syncfusion.Blazor.Toolkit.Theme` — using a non-existent value compiles +> to silence and renders nothing. Stick to `Fluent` / `FluentDark`. ```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - -@code { - public class TrafficInfo - { - public string Hour { get; set; } - public double Visitors { get; set; } - } - - public List TrafficData = new List - { - new TrafficInfo { Hour = "8 AM", Visitors = 320 }, - new TrafficInfo { Hour = "12 PM", Visitors = 580 }, - new TrafficInfo { Hour = "4 PM", Visitors = 720 }, - new TrafficInfo { Hour = "8 PM", Visitors = 450 } - }; -} + ``` -### Asymmetric Margins - -Apply different margins to each side: +### Runtime theme switching ```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - + + … - -@code { - public class AssetInfo - { - public string Asset { get; set; } - public double Value { get; set; } - } - - public List InvestmentData = new List - { - new AssetInfo { Asset = "Stocks", Value = 45000 }, - new AssetInfo { Asset = "Bonds", Value = 30000 }, - new AssetInfo { Asset = "Real Estate", Value = 80000 }, - new AssetInfo { Asset = "Commodities", Value = 15000 } - }; -} ``` ---- +Pair `_isDark` with your host app's dark-mode signal. `Theme` re-renders in +place — no `RefreshAsync` required. -## Title and Subtitle Styling +### Why NO service registration is needed for themes -Customize chart titles and subtitles with font properties, colors, and positioning. +The toolkit is registered once at app startup via +`builder.Services.AddSyncfusionBlazorToolkit()` (blazor/Startup — see +`getting-started.md`). `Theme` does **not** require any separate +`AddSyncfusionBlazor()` call. Older guidance pointing you at that call is +for the legacy `Syncfusion.Blazor` product, not for +`Syncfusion.Blazor.Toolkit`. -### Title Styling +### Custom theme = start from a built-in + override `Palettes` -Apply custom styling to the chart title: +`Theme` shapes background, text, grid lines, and axis/label colors. The +series palette is **separate** and is overridden by passing `Palettes` on +`` — applies in order to series, *over and above* `Theme`. There is +no CSS-variable layer you can poke from the host page. ```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - -@code { - public class AnnualRevenue - { - public string Year { get; set; } - public double Revenue { get; set; } - } - - public List AnnualData = new List - { - new AnnualRevenue { Year = "2020", Revenue = 850000 }, - new AnnualRevenue { Year = "2021", Revenue = 920000 }, - new AnnualRevenue { Year = "2022", Revenue = 1050000 }, - new AnnualRevenue { Year = "2023", Revenue = 1180000 } - }; -} + ``` -### Title and Subtitle Combined +Use `PointColorMapping` to override per-data-point (string property on the +row holding any CSS color). Use `Fill` on `` to override for a +single series. -Add both title and subtitle with distinct styling: +## Series styling ```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - -@code { - public class SurveyResult - { - public string Department { get; set; } - public double Score { get; set; } - } - - public List SurveyData = new List - { - new SurveyResult { Department = "Engineering", Score = 4.5 }, - new SurveyResult { Department = "Sales", Score = 4.2 }, - new SurveyResult { Department = "HR", Score = 4.8 }, - new SurveyResult { Department = "Finance", Score = 4.3 } - }; -} -``` - -### Title Position Customization - -Position the title at different locations: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - -@code { - public class WebTraffic - { - public string Month { get; set; } - public double Visits { get; set; } - } - - public List TrafficData = new List - { - new WebTraffic { Month = "Jan", Visits = 12500 }, - new WebTraffic { Month = "Feb", Visits = 14200 }, - new WebTraffic { Month = "Mar", Visits = 16800 }, - new WebTraffic { Month = "Apr", Visits = 18300 } - }; -} -``` - ---- - -## Theme Support - -Syncfusion Blazor Charts support built-in themes and custom theme creation. - -### Built-in Themes - -Apply predefined themes by including the theme API: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - -@code { - public class ProductPerformance - { - public string Product { get; set; } - public double Rating { get; set; } - } - - public List PerformanceData = new List - { - new ProductPerformance { Product = "Product A", Rating = 4.5 }, - new ProductPerformance { Product = "Product B", Rating = 3.8 }, - new ProductPerformance { Product = "Product C", Rating = 4.2 }, - new ProductPerformance { Product = "Product D", Rating = 4.7 } - }; -} -``` - -**Available Built-in Themes:** -- Material -- Bootstrap -- Bootstrap 4 -- Bootstrap 5 -- Fabric -- Tailwind -- Material 3 -- Fluent -- High Contrast - -### Custom Theme Colors - -Create a custom appearance by overriding default palette: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - -@code { - public class RegionalSales - { - public string Region { get; set; } - public double Sales { get; set; } - } - - public List RegionalData = new List - { - new RegionalSales { Region = "North", Sales = 125000 }, - new RegionalSales { Region = "South", Sales = 98000 }, - new RegionalSales { Region = "East", Sales = 112000 }, - new RegionalSales { Region = "West", Sales = 135000 } - }; - - // Custom corporate color palette - public string[] CustomThemePalette = new string[] - { - "#0066CC", "#FF6600", "#339933", "#CC0066", "#9933FF" - }; -} + + + + ``` ---- - -## Series Styling - -Customize individual series appearance including fill colors, opacity, and borders. +- `Opacity` 0–1 (rendered, not paint). Same opacity affects both line fill + and series border. +- `ChartSeriesAnimation` is per-series, not per-chart. -### Fill Color and Opacity - -Control series fill color and transparency: +## Responsive sizing ```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - -@code { - public class QuarterComparison - { - public string Quarter { get; set; } - public double Current { get; set; } - public double Previous { get; set; } - } - - public List ComparisonData = new List - { - new QuarterComparison { Quarter = "Q1", Current = 85000, Previous = 78000 }, - new QuarterComparison { Quarter = "Q2", Current = 92000, Previous = 85000 }, - new QuarterComparison { Quarter = "Q3", Current = 98000, Previous = 90000 }, - new QuarterComparison { Quarter = "Q4", Current = 105000, Previous = 95000 } - }; -} -``` - -### Series Border Styling - -Add borders to series elements: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - -@code { - public class TrendInfo - { - public string Month { get; set; } - public double Value { get; set; } - } - - public List TrendData = new List - { - new TrendInfo { Month = "Jan", Value = 450 }, - new TrendInfo { Month = "Feb", Value = 520 }, - new TrendInfo { Month = "Mar", Value = 480 }, - new TrendInfo { Month = "Apr", Value = 590 } - }; -} -``` - -### Series Animation - -Configure animation properties for series: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - -@code { - public class GrowthInfo - { - public string Year { get; set; } - public double Growth { get; set; } - } - - public List GrowthData = new List - { - new GrowthInfo { Year = "2019", Growth = 5.2 }, - new GrowthInfo { Year = "2020", Growth = 6.8 }, - new GrowthInfo { Year = "2021", Growth = 7.5 }, - new GrowthInfo { Year = "2022", Growth = 8.2 }, - new GrowthInfo { Year = "2023", Growth = 9.1 } - }; -} -``` - ---- - -## Chart Responsiveness - -Ensure charts adapt to different screen sizes and orientations. - -### Responsive Percentage Sizing - -Use percentage-based dimensions for automatic responsiveness: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - -
- - - - - +
+
- - - -@code { - public class DashboardMetric - { - public string Metric { get; set; } - public double Value { get; set; } - } - - public List DashboardData = new List - { - new DashboardMetric { Metric = "Users", Value = 15000 }, - new DashboardMetric { Metric = "Sessions", Value = 45000 }, - new DashboardMetric { Metric = "Pageviews", Value = 120000 } - }; -} ``` -### Container-Based Responsive Charts +For multi-breakpoint logic, render a `JSInterop` measurement and re-render +explicitly: read +`/memories/repo/` project conventions for the resize pattern, or compute +`Height` from the host's `ElementReference` (the agent should look up its +project's resize helper, not invent one). -Create fully responsive charts that adapt to parent container: +## Best practices -```razor -@using Syncfusion.Blazor.Toolkit.Charts - -
- - - - - -
- -@code { - public class FlexInfo - { - public string Category { get; set; } - public double Amount { get; set; } - } - - public List FlexData = new List - { - new FlexInfo { Category = "A", Amount = 120 }, - new FlexInfo { Category = "B", Amount = 150 }, - new FlexInfo { Category = "C", Amount = 180 }, - new FlexInfo { Category = "D", Amount = 140 } - }; -} -``` - ---- - -## Styling Best Practices +| Area | Recommendation | +|------|----------------| +| Palette size | 5–7 distinct colors max; reuse the same palette across all charts in a view | +| Fonts | Axis labels ≥ 12px; titles ≥ 18px; ensure WCAG AA contrast on label/bg pairs | +| Grid lines | Use the chart area's default grid; only enable minor grid when axes are numeric with sub-intervals | +| Color blindness | Default to `CvdSafePalette` (above) when the chart is user-facing analytics | +| Animation | Disable when dataset > 1,000 points (`ChartSeriesAnimation Enable="false"`) | +| Margin | Default 30–50 px each side; increase RHS if you have a vertical axis title that wraps | +| Fonts | Avoid `inherit`; the chart sets the font on its root and the axis labels override only when needed | -Follow these guidelines for optimal chart appearance and performance. +## Complete styling example -### Design Guidelines - -**Color Selection:** -- Use color palettes with sufficient contrast for accessibility -- Limit palette to 5-7 distinct colors for clarity -- Ensure colors are distinguishable for colorblind users -- Use consistent colors across related charts - -**Typography:** -- Choose readable fonts (12px minimum for labels) -- Use font weights to establish hierarchy (bold titles, regular labels) -- Ensure sufficient contrast between text and background - -**Spacing:** -- Provide adequate margins (30-50px minimum) -- Use chart area width of 80-90% for balanced appearance -- Leave space for legends and labels - -### Performance Tips - -**Optimize Rendering:** ```razor -@using Syncfusion.Blazor.Toolkit.Charts + + + + + + + + - - - - - -@code { - public class OptimizedDataPoint - { - public string Item { get; set; } - public double Value { get; set; } - } - - public List OptimizedData = new List - { - new OptimizedDataPoint { Item = "Item 1", Value = 45 }, - new OptimizedDataPoint { Item = "Item 2", Value = 62 }, - new OptimizedDataPoint { Item = "Item 3", Value = 38 } - }; -} -``` - -**Animation Best Practices:** -- Use animations sparingly for data updates -- Keep duration between 500-2000ms -- Disable animations for large datasets (>1000 points) - -### Accessibility Considerations - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - + + + + + + + + + - -@code { - public class AccessibleDataPoint - { - public string Label { get; set; } - public double Value { get; set; } - } - - public List AccessibleData = new List - { - new AccessibleDataPoint { Label = "Category A", Value = 75 }, - new AccessibleDataPoint { Label = "Category B", Value = 60 }, - new AccessibleDataPoint { Label = "Category C", Value = 85 } - }; - - // Color-blind friendly palette - public string[] AccessiblePalette = new string[] - { - "#0173B2", "#DE8F05", "#029E73", "#CC78BC", "#CA9161" - }; -} -``` - -### Troubleshooting Common Issues - -**Issue: Chart not rendering at correct size** -- Solution: Add script reference to avoid delayed rendering -```html - -``` - -**Issue: Colors not applying correctly** -- Solution: Ensure Palettes array matches or exceeds number of series -- Alternatively, use Fill property on individual series - -**Issue: Responsive behavior not working** -- Solution: Use percentage values (e.g., "100%") instead of fixed pixels -- Ensure parent container has defined dimensions - -**Issue: Title overlapping chart content** -- Solution: Adjust ChartMargin Top property to provide space -- Consider using title Position property - ---- - -## Complete Styling Example - -Here's a comprehensive example combining multiple styling techniques: - -```razor -@using Syncfusion.Blazor.Toolkit.Charts - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -@code { - public class CompleteDataPoint - { - public string Month { get; set; } - public double Sales { get; set; } - public double Target { get; set; } - } - - public List CompleteData = new List - { - new CompleteDataPoint { Month = "Jan", Sales = 35000, Target = 40000 }, - new CompleteDataPoint { Month = "Feb", Sales = 42000, Target = 40000 }, - new CompleteDataPoint { Month = "Mar", Sales = 38000, Target = 40000 }, - new CompleteDataPoint { Month = "Apr", Sales = 45000, Target = 45000 }, - new CompleteDataPoint { Month = "May", Sales = 48000, Target = 45000 }, - new CompleteDataPoint { Month = "Jun", Sales = 52000, Target = 50000 } - }; - - public string[] CompletePalette = new string[] - { - "#2196F3", "#FF9800", "#4CAF50", "#E91E63" - }; -} ``` ---- - -## Summary - -This reference guide covers all essential aspects of Syncfusion Blazor Charts appearance and styling: - -- **Dimensions**: Control chart size using pixels, percentages, or container sizing -- **Colors**: Customize using palettes, series colors, or point-level colors -- **Backgrounds**: Apply backgrounds to chart and chart area with borders -- **Margins**: Configure spacing around the chart -- **Titles**: Style titles and subtitles with fonts, colors, and positioning -- **Themes**: Use built-in themes or create custom color schemes -- **Series**: Customize individual series with fills, opacity, and borders -- **Responsiveness**: Create adaptive charts for all screen sizes -- **Best Practices**: Follow design guidelines for optimal appearance and performance +## Troubleshooting -Use these techniques to create professional, accessible, and visually appealing chart visualizations in your Blazor applications. \ No newline at end of file +| Symptom | Fix | +|---------|-----| +| Chart height is 0 | Parent of `` doesn't have a defined height | +| Background doesn't fill the chart | Use `` not the body background | +| Title font not applying | Use `` (modern) not `` (legacy) | +| Palette is ignored | `Palettes` length < number of series → fallback to default fills | +| Animation replay on every render | Disable animation with `Duration="0"` or `Enable="false"` | \ No newline at end of file diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/references/axes-and-scales.md b/.github/skills/syncfusion-blazor-toolkit-charts/references/axes-and-scales.md index 0e1fb97..f0179e7 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/references/axes-and-scales.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/references/axes-and-scales.md @@ -1,912 +1,216 @@ -# Blazor Chart Axes and Scales - Comprehensive Reference Guide - -## Table of Contents - -- [1. Category Axis](#1-category-axis) - - [Basic Setup](#basic-setup) - - [Label Placement](#label-placement) - - [Range and Interval](#range-and-interval) - - [Indexed Category Axis](#indexed-category-axis) -- [2. Numeric Axis](#2-numeric-axis) - - [Basic Configuration](#basic-configuration) - - [Numeric Range and Interval](#numeric-range-and-interval) - - [Range Padding Types](#range-padding-types) - - [Numeric Label Format](#numeric-label-format) - - [Grouping Separator](#grouping-separator) -- [3. DateTime Axis](#3-datetime-axis) - - [Basic DateTime Axis](#basic-datetime-axis) - - [DateTime Category Axis](#datetime-category-axis) - - [Interval Customization](#interval-customization) - - [DateTime Range Padding](#datetime-range-padding) - - [DateTime Label Format](#datetime-label-format) -- [4. Logarithmic Axis](#4-logarithmic-axis) - - [Logarithmic Basic Configuration](#logarithmic-basic-configuration) - - [Logarithmic Base](#logarithmic-base) - - [Logarithmic Interval](#logarithmic-interval) - - [Logarithmic Label Format](#logarithmic-label-format) -- [5. Axis Customization](#5-axis-customization) - - [Axis Titles](#axis-titles) - - [Axis Crossing](#axis-crossing) - - [Opposed Position](#opposed-position) - - [Inversed Axis](#inversed-axis) - - [Tick Lines](#tick-lines) - - [Grid Lines](#grid-lines) -- [6. Axis Labels](#6-axis-labels) - - [Smart Axis Labels](#smart-axis-labels) - - [Label Positioning](#label-positioning) - - [Label Rotation](#label-rotation) - - [Label Trimming](#label-trimming) - - [Label Wrapping](#label-wrapping) - - [Edge Label Placement](#edge-label-placement) - - [Multilevel Labels](#multilevel-labels) -- [7. Multiple Axes](#7-multiple-axes) - - [Secondary Axes](#secondary-axes) - - [Axis Naming](#axis-naming) - - [Multiple Rows and Columns](#multiple-rows-and-columns) -- [8. Common Properties](#8-common-properties) -- [9. Best Practices](#9-best-practices) -- [10. Troubleshooting](#10-troubleshooting) -- [Complete Working Example](#complete-working-example) -- [Summary](#summary) - - -## 1. Category Axis - -### Basic Setup -Category axis is used to represent string values instead of numeric values. - -```cshtml -@using Syncfusion.Blazor.Toolkit.Charts +# Axes and Scales - - - - - - - - -@code{ - public class ChartData - { - public string Country { get; set; } - public double Medals { get; set; } - } - - public List MedalDetails = new List - { - new ChartData { Country = "USA", Medals = 46 }, - new ChartData { Country = "GBR", Medals = 27 }, - new ChartData { Country = "CHN", Medals = 26 }, - new ChartData { Country = "UK", Medals = 23 }, - new ChartData { Country = "AUS", Medals = 16 } - }; -} -``` - -### Label Placement -Category labels can be positioned between ticks or on ticks. - -```cshtml - - -``` - -**Options:** -- `BetweenTicks` - Labels appear between tick marks (default) -- `OnTicks` - Labels appear on tick marks - -### Range and Interval -Control the visible range and spacing of category labels. - -```cshtml - - -``` +> **Verified against source** — strip-line pluralisation, shape enum, +> axis intervals verified against `src/Base/Enumeration.cs`. Last source +> audit: **2026-08-24**. -### Indexed Category Axis -Use data source index values for rendering category axis. +`SfChart` exposes two primary axes (``, +``) and an unbounded collection of extra axes +(``). Every axis is one of five value +types: `Category`, `Double`, `DateTime`, `Logarithmic`, `DateTimeCategory`. +Pick the type from the data shape — never default to `Category` "to be safe". -```cshtml - - +> **Sample data** — see [`_includes/sample-data.md`](_includes/sample-data.md). +> This file declares `Point` (string X, double Y) and `DatePoint` (DateTime +> When, double Y) lists named `Series` and `Dates` used by the snippets +> below. - - - - -``` +## Table of contents ---- +- Pick a `ValueType` (decision table) +- Category axis +- Numeric axis (`Double`) +- DateTime axis +- Logarithmic axis +- Axis namespaces, titles, labels, ticks, grids +- Multiple / opposed axes +- Strip lines (cross-axis highlights) +- Best practices + troubleshooting -## 2. Numeric Axis +## Pick a `ValueType` -### Basic Configuration -Numeric axis uses double values and is the default axis type. +| Data shape | `ValueType` | +|-----------|-------------| +| Discrete labels ("Jan", "Q1", "North") | `Category` | +| Continuous numeric (`double`) | `Double` | +| Timestamps | `DateTime` | +| Exponential growth/decay data | `Logarithmic` | +| Time-bucketed categories (e.g. months but worth treating as a series) | `DateTimeCategory` | +| **Default if you forget** | `Double` (auto-promotes dates to ordinals — usually wrong) | -```cshtml - - - +Setting the wrong `ValueType` silently sorts/treats data incorrectly. There +is **no warning** — it just looks "off". - - - +## Category axis -@code{ - public List Data = new List - { - new ChartData { XValue = 10, YValue = 21 }, - new ChartData { XValue = 20, YValue = 24 }, - new ChartData { XValue = 30, YValue = 36 }, - new ChartData { XValue = 40, YValue = 38 } - }; -} -``` - -### Numeric Range and Interval - -```cshtml - +```razor + + -``` - -### Range Padding Types - -**None** - Minimum and maximum based on data -```cshtml - - -``` -**Round** - Rounds to nearest interval value -```cshtml - - + ``` -**Additional** - Adds interval padding -```cshtml - - -``` +Useful `Category` controls: `LabelPlacement` (`BetweenTicks` default | +`OnTicks`), `Indexed` (display the row index on the axis instead of any +field value), `Interval` (`2` → show every 2nd label). -**Normal** - Applies default padding -```cshtml - - -``` - -**Auto** - Horizontal uses None, Vertical uses Normal -```cshtml - - -``` - -### Numeric Label Format - -```cshtml - - -``` +## Numeric (Double) axis -**Common Formats:** -| Format | Example | Description | -|--------|---------|-------------| -| n1 | 1000.0 | 1 decimal place | -| n2 | 1000.00 | 2 decimal places | -| p1 | 1.0% | Percentage with 1 decimal | -| c1 | $1000.0 | Currency with 1 decimal | -| c2 | $1000.00 | Currency with 2 decimals | - -**Custom Format:** -```cshtml - +```razor + + ``` -### Grouping Separator - -```cshtml - - - - -``` +`RangePadding` values that matter: ---- +| Padding | When to use | +|---------|-------------| +| `None` | Raw min–max; the chart looks clingy on edges | +| `Round` | Round to nearest interval (default-ish) | +| `Additional` | Keep room for grid lines | +| `Normal` | Recommended for series with zero baseline | +| `Auto` | X uses `None`, Y uses `Normal` | -## 3. DateTime Axis +`LabelFormat="c0"` formats as currency with 0 decimals (uses chart `Locale`). +See `references/appearance-styling.md` for format tokens. -### Basic DateTime Axis +## DateTime axis -```cshtml - - - - - - - - -@code{ - public class ChartData - { - public DateTime Date { get; set; } - public double Temperature { get; set; } - } - - public List WeatherReports = new List - { - new ChartData { Date = new DateTime(2005, 01, 01), Temperature = 21 }, - new ChartData { Date = new DateTime(2006, 01, 01), Temperature = 24 }, - new ChartData { Date = new DateTime(2007, 01, 01), Temperature = 36 } - }; -} -``` - -### DateTime Category Axis -Displays date-time values with non-linear intervals. - -```cshtml - - +```razor + ``` -### Interval Customization - -```cshtml - - -``` +| When your data is… | Set `IntervalType` to | +|--------------------|----------------------| +| Yearly | `Years` | +| Monthly | `Months` | +| Daily | `Days` | +| Hourly | `Hours` | +| Auto | `Auto` | -**Interval Types:** -- `Auto` -- `Years` -- `Months` -- `Days` -- `Hours` -- `Minutes` -- `Seconds` - -### DateTime Range Padding - -**None:** -```cshtml - - -``` +## Logarithmic axis -**Round:** -```cshtml - - +```razor + ``` -**Additional:** -```cshtml - - -``` +Use only when data spans multiple orders of magnitude. `LogBase` must be +`> 1`; default is `10`. Don't use `Logarithmic` for "smaller numbers" — use +`Double` with a tighter `Minimum/Maximum`. -### DateTime Label Format +## Titles, labels, ticks, grids -```cshtml - +```razor + + + + + + + ``` -**Common DateTime Formats:** -| Format | Example | Description | -|--------|---------|-------------| -| EEEE | Monday | Day of week | -| yMd | 04/10/2000 | Month/Date/Year | -| MMM | Apr | Short month name | -| hm | 12:00 AM | Hours:Minutes | -| hms | 12:00:00 AM | Hours:Minutes:Seconds | +`Rotation`: degree rotation; `0`–`90` for typical axis text. Use +`LabelIntersectAction` to handle long category labels: ---- +| Strategy | Use when | +|----------|----------| +| `Hide` | Lots of labels, low importance | +| `Trim` | One or two long words | +| `Wrap` | Multi-word labels | +| `Rotate45` / `Rotate90` | Compact presentation | +| `MultipleRows` | Long phrases that need full width | -## 4. Logarithmic Axis +## Multiple / opposed axes -### Logarithmic Basic Configuration +Use a separate `` in +`` and point at it with `YAxisName`: -```cshtml +```razor - - - - - - - - - - -@code{ - public List Data = new List - { - new ChartData { XValue = new DateTime(2005, 01, 01), YValue = 100 }, - new ChartData { XValue = new DateTime(2006, 01, 01), YValue = 200 }, - new ChartData { XValue = new DateTime(2007, 01, 01), YValue = 500 }, - new ChartData { XValue = new DateTime(2008, 01, 01), YValue = 1000 }, - new ChartData { XValue = new DateTime(2009, 01, 01), YValue = 8000 } - }; -} -``` - -### Logarithmic Base - -```cshtml - - -``` - -Common bases: 2, 5, 10 (default) - -### Logarithmic Interval - -```cshtml - - -``` - -When base is 10 and interval is 2, labels are placed at 10², 10⁴, 10⁶, etc. - -### Logarithmic Label Format - -```cshtml - - -``` - -**Custom Format:** -```cshtml - - -``` - ---- - -## 5. Axis Customization - -### Axis Titles - -```cshtml - - - - - - - - - -``` - -**Title Alignment Options:** -- `Alignment.Near` -- `Alignment.Center` -- `Alignment.Far` - -### Axis Crossing - -```cshtml - - - - - -``` - -**For Multiple Axes:** -```cshtml - - - - - - - -``` - -### Opposed Position - -```cshtml - - -``` - -Places axis on the opposite side (right for Y-axis, top for X-axis). - -### Inversed Axis - -```cshtml - - -``` - -Inverts the axis direction (greatest value near origin). - -### Tick Lines - -```cshtml - - - - - - - - - - - - - -``` - -### Grid Lines - -```cshtml - - - - - - -``` - ---- - -## 6. Axis Labels - -### Smart Axis Labels - -**Hide Overlapping Labels:** -```cshtml - - -``` - -**Rotate 45 Degrees:** -```cshtml - - -``` - -**Rotate 90 Degrees:** -```cshtml - - -``` - -### Label Positioning - -```cshtml - - -``` - -**Options:** -- `AxisPosition.Outside` (default) -- `AxisPosition.Inside` - -### Label Rotation - -Handled automatically by `LabelIntersectAction` or can be customized in events. - -### Label Trimming - -```cshtml - - -``` - -### Label Wrapping - -```cshtml - - - - - - - - - - -``` - -### Edge Label Placement - -```cshtml - - -``` - -**Options:** -- `None` - Leave as is -- `Shift` - Move label inside chart area -- `Hide` - Hide edge labels - -### Multilevel Labels - -```cshtml - - - - - - - - - - - - - - - - -``` - -**Border Types:** -- `Rectangle` -- `Brace` -- `WithoutBorder` -- `WithoutTopBorder` -- `WithoutTopandBottomBorder` -- `CurlyBrace` - ---- - -## 7. Multiple Axes - -### Secondary Axes - -```cshtml - - - - - - + + - - + - - - - + + + + ``` -### Axis Naming - -Each secondary axis requires a unique name specified in the `Name` property: - -```cshtml - - - - - - -``` - -Bind series to axis using `YAxisName` or `XAxisName`: - -```cshtml - - -``` - -### Multiple Rows and Columns - -**Rows:** -```cshtml - - - - - - - - - - - -``` - -**Columns:** -```cshtml - - - - - - - - - - - -``` - -**Span Across Rows/Columns:** -```cshtml - - -``` - ---- - -## 8. Common Properties - -**Essential Axis Properties:** - -| Property | Type | Description | -|----------|------|-------------| -| `Minimum` | object | Minimum value for axis range | -| `Maximum` | object | Maximum value for axis range | -| `Interval` | double | Spacing between axis labels | -| `ValueType` | ValueType | Category, Double, DateTime, DateTimeCategory, Logarithmic | -| `Name` | string | Unique identifier for axis | -| `Title` | string | Axis title text | -| `OpposedPosition` | bool | Places axis on opposite side | -| `IsInversed` | bool | Inverts axis direction | -| `LabelFormat` | string | Format string for labels | -| `LabelPlacement` | LabelPlacement | BetweenTicks or OnTicks | -| `LabelPosition` | AxisPosition | Inside or Outside | -| `EdgeLabelPlacement` | EdgeLabelPlacement | None, Shift, or Hide | -| `RangePadding` | ChartRangePadding | None, Round, Additional, Normal, Auto | -| `EnableTrim` | bool | Enables label trimming | -| `MaximumLabelWidth` | double | Maximum width for labels | -| `LabelIntersectAction` | LabelIntersectAction | None, Hide, Rotate45, Rotate90 | -| `RowIndex` | int | Row index for multi-pane charts | -| `ColumnIndex` | int | Column index for multi-pane charts | -| `Span` | int | Number of rows/columns to span | - ---- - -## 9. Best Practices - -1. **Choose the Right Axis Type:** - - Use Category axis for string labels - - Use Numeric axis for continuous numeric data - - Use DateTime axis for time-series data - - Use Logarithmic axis for data spanning multiple orders of magnitude - -2. **Optimize Label Display:** - - Use `LabelIntersectAction` to prevent overlapping labels - - Set appropriate `MaximumLabelWidth` for long labels - - Use `EnableTrim` when labels are too long - - Consider `EdgeLabelPlacement="Shift"` for better edge visibility - -3. **Range Configuration:** - - Set explicit `Minimum` and `Maximum` for consistent scaling - - Use appropriate `RangePadding` for better data visibility - - Set `Interval` to control label density - -4. **Multiple Axes:** - - Always provide unique `Name` for secondary axes - - Use `OpposedPosition` for better visual separation - - Consider using rows/columns for complex multi-axis scenarios - -5. **Performance:** - - Limit the number of visible labels using `Interval` - - Use `RangePadding="None"` when exact range is needed - - Avoid excessive multilevel labels - -6. **Accessibility:** - - Provide meaningful axis titles - - Use high-contrast colors for grid lines and labels - - Ensure label text is readable (minimum 10px size) - ---- - -## 10. Troubleshooting - -**Problem: Labels are overlapping** -```cshtml - - -``` - -**Problem: Axis range is too tight** -```cshtml - - -``` - -**Problem: Edge labels are cut off** -```cshtml - - -``` - -**Problem: Too many labels showing** -```cshtml - - -``` +`OpposedPosition="true"` puts the axis on the opposite side of the chart +(right vs left, top vs bottom). The same axis name pattern works for +secondary X axes. -**Problem: Labels are too long** -```cshtml - - -``` +## Strip lines (cross-axis bands) -**Problem: Secondary axis not showing** -```cshtml - - - - - - - - - -``` +Strip lines live inside the axis they belong to and **must** use the plural +child (see SKILL.md "Critical API rules" #2): -**Problem: Logarithmic axis showing negative values** -```cshtml - - +```razor + + + + + + ``` -**Problem: DateTime labels not formatted correctly** -```cshtml - - -``` - -**Problem: Category axis showing numeric indices** -```cshtml - - - -``` - ---- - -## Complete Working Example - -```cshtml -@using Syncfusion.Blazor.Toolkit.Charts - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -@code { - public class DataPoint - { - public string Month { get; set; } - public double Sales { get; set; } - public double Temperature { get; set; } - } - - public List SalesData = new List - { - new DataPoint { Month = "Jan", Sales = 35000, Temperature = 15 }, - new DataPoint { Month = "Feb", Sales = 28000, Temperature = 17 }, - new DataPoint { Month = "Mar", Sales = 34000, Temperature = 21 }, - new DataPoint { Month = "Apr", Sales = 32000, Temperature = 25 }, - new DataPoint { Month = "May", Sales = 40000, Temperature = 30 }, - new DataPoint { Month = "Jun", Sales = 32000, Temperature = 35 }, - new DataPoint { Month = "Jul", Sales = 35000, Temperature = 38 }, - new DataPoint { Month = "Aug", Sales = 45000, Temperature = 36 }, - new DataPoint { Month = "Sep", Sales = 38000, Temperature = 32 }, - new DataPoint { Month = "Oct", Sales = 30000, Temperature = 26 }, - new DataPoint { Month = "Nov", Sales = 25000, Temperature = 20 }, - new DataPoint { Month = "Dec", Sales = 42000, Temperature = 16 } - }; -} -``` - ---- +Strip lines are useful for highlighting SLA bands, time-of-day windows, or +threshold zones. They work on both X and Y axes. -## Summary +## Best practices -This reference guide provides comprehensive coverage of Blazor Chart axes and scales including: +1. **Set the `ValueType` explicitly** — relying on defaults creates + categorical axes that "look sorted" but treat data incorrectly. +2. **Match `IntervalType` to your data** — DateTime axes default to auto and + produce inconsistent labels. +3. **Set `Minimum` / `Maximum`** on at least one axis when the chart has + thresholds or fixed scales (compare charts and trend targets). +4. **Prefer `RangePadding.Round` for monetary series** — avoid the "phantom + zero issue" pulled in by `None`. +5. **Use `ChartStriplines` (plural) once per axis** — multiple striplines per + axis are supported. +6. **Right-side axis for percentage metrics** — `OpposedPosition="true"` + separates metrics with different units cleanly. -- **4 Axis Types**: Category, Numeric, DateTime, and Logarithmic -- **Extensive Customization**: Titles, positioning, styling, and behavior -- **Label Management**: Smart labels, rotation, trimming, and multilevel labels -- **Multiple Axes Support**: Secondary axes, rows, columns, and spanning -- **Best Practices**: Optimization tips and common patterns -- **Troubleshooting**: Solutions to common issues +## Troubleshooting -Use this guide as a quick reference for implementing and customizing chart axes in your Blazor applications. +| Symptom | Fix | +|---------|-----| +| Labels overlap | `LabelIntersectAction="Rotate45"` or `Wrap` | +| "0" between negative and positive bars | `RangePadding="None"` instead of `Additional` | +| Strip line paints outside expected region | Used singular `` wrapper | Fix to `` plural (also use `Syncfusion.Blazor.Toolkit.ZIndexPosition.Behind` if setting Z-order) | +| Date axis labels skip months | `IntervalType` not matching your data granularity | +| Numeric axis max isn't the value you set | Verify `RangePadding="None"`, otherwise the chart rounds up | +| Multi-axis series renders on the wrong axis | Missing `Name` on the secondary axis or wrong `YAxisName` on series | \ No newline at end of file diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/references/chart-types-common.md b/.github/skills/syncfusion-blazor-toolkit-charts/references/chart-types-common.md index 46ea52c..a5827f4 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/references/chart-types-common.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/references/chart-types-common.md @@ -1,4 +1,7 @@ -# Common Chart Types +# Common Chart Types + +> **Verified against source** — series-type & shape enums verified +> against `src/Base/Enumeration.cs`. Last source audit: **2026-08-24**. ## Table of Contents @@ -87,19 +90,12 @@ Line charts visualize time-dependent data by connecting data points with lines, @code { - public class ChartData - { - public string Month { get; set; } - public double Sales { get; set; } - } - - public List SalesData = new List + public record ChartData(string Month, double Sales); + + private readonly List SalesData = new() { - new ChartData { Month = "Jan", Sales = 35 }, - new ChartData { Month = "Feb", Sales = 28 }, - new ChartData { Month = "Mar", Sales = 34 }, - new ChartData { Month = "Apr", Sales = 32 }, - new ChartData { Month = "May", Sales = 40 } + new("Jan", 35), new("Feb", 28), new("Mar", 34), + new("Apr", 32), new("May", 40) }; } ``` @@ -160,18 +156,13 @@ Display different colors for each line segment: @code { - public class ColoredChartData - { - public string Month { get; set; } - public double Value { get; set; } - public string Color { get; set; } - } - - public List ColoredData = new List + public record ColoredChartData(string Month, double Value, string Color); + + private readonly List ColoredData = new() { - new ColoredChartData { Month = "Jan", Value = 35, Color = "#1f77b4" }, - new ColoredChartData { Month = "Feb", Value = 28, Color = "#ff7f0e" }, - new ColoredChartData { Month = "Mar", Value = 34, Color = "#2ca02c" } + new("Jan", 35, "#1f77b4"), + new("Feb", 28, "#ff7f0e"), + new("Mar", 34, "#2ca02c") }; } ``` @@ -190,7 +181,7 @@ Area charts fill the region below the line, emphasizing magnitude and trends ove - @@ -248,9 +239,9 @@ Area charts fill the region below the line, emphasizing magnitude and trends ove YName="Value" Type="Syncfusion.Blazor.Toolkit.ChartSeriesType.MultiColoredArea"> - - - + + + ``` @@ -269,7 +260,7 @@ Column charts compare values across categories using vertical bars. Most common - @@ -328,7 +319,7 @@ Column charts compare values across categories using vertical bars. Most common - @@ -382,7 +373,7 @@ Bar charts display horizontal bars for comparing categories. Ideal when category - @@ -422,7 +413,7 @@ Spline charts draw smooth curves through data points using cubic spline interpol - @@ -462,7 +453,7 @@ Combines smooth curves of spline charts with filled areas. Shows trends with smo - @@ -491,7 +482,7 @@ Step line charts display data as a series of horizontal and vertical line segmen - @@ -513,7 +504,7 @@ Step area charts combine stepped lines with filled areas below. Shows discrete c - @@ -547,19 +538,20 @@ All chart types support empty point handling for `null`, `double.NaN`, or `undef XName="Month" YName="Value" Type="Syncfusion.Blazor.Toolkit.ChartSeriesType.Line"> - - + ``` -**Empty Point Modes:** +**Empty Point Modes:** (source order — verified at +`src/Base/Enumeration.cs:1062`) - `Gap` (default) - Leave gap in series - `Zero` - Plot as zero value -- `Average` - Use average of adjacent points - `Drop` - Drop the point entirely +- `Average` - Use average of adjacent points --- @@ -648,14 +640,14 @@ Display multiple chart types together: - - **Verified against source** — series-type & shape enums verified +> against `src/Base/Enumeration.cs`. Last source audit: **2026-08-24**. A comprehensive guide to implementing specialized Syncfusion Blazor chart types including stacked, scatter, and bubble charts. This document is self-contained with complete examples and best practices. @@ -34,7 +37,7 @@ A comprehensive guide to implementing specialized Syncfusion Blazor chart types - - - - + @code { - public class StackedData - { - public double Year { get; set; } - public double ProductA { get; set; } - public double ProductB { get; set; } - public double ProductC { get; set; } - } + public record StackedData(double Year, double ProductA, double ProductB, double ProductC); - public List RevenueData = new List + private readonly List RevenueData = new() { - new StackedData { Year = 2020, ProductA = 0.61, ProductB = 0.03, ProductC = 0.48 }, - new StackedData { Year = 2021, ProductA = 0.81, ProductB = 0.05, ProductC = 0.53 }, - new StackedData { Year = 2022, ProductA = 0.91, ProductB = 0.06, ProductC = 0.57 } + new(2020, 0.61, 0.03, 0.48), + new(2021, 0.81, 0.05, 0.53), + new(2022, 0.91, 0.06, 0.57) }; } ``` @@ -118,25 +115,38 @@ A comprehensive guide to implementing specialized Syncfusion Blazor chart types ```cshtml - -fix th - + - - - + + +@code { + public record ScatterPoint(string Country, double GoldMedals, double SilverMedals); + + private readonly List ScatterData = new() + { + new("USA", 39, 41), + new("China", 38, 32), + new("Japan", 27, 14), + new("UK", 22, 20), + new("Australia", 17, 7) + }; +} ``` --- @@ -149,7 +159,7 @@ fix th - @code { - public class BubbleData - { - public double LiteracyRate { get; set; } - public double GrowthRate { get; set; } - public double Population { get; set; } - public string Country { get; set; } - } + public record BubbleData(double LiteracyRate, double GrowthRate, double Population, string Country); - public List PopulationData = new List + private readonly List PopulationData = new() { - new BubbleData { LiteracyRate = 92.2, GrowthRate = 7.8, Population = 1.347, Country = "China" }, - new BubbleData { LiteracyRate = 74, GrowthRate = 6.5, Population = 1.241, Country = "India" } + new(92.2, 7.8, 1.347, "China"), + new(74.0, 6.5, 1.241, "India") }; } ``` @@ -183,7 +187,7 @@ fix th - @@ -196,7 +200,7 @@ fix th + ``` @@ -269,6 +273,6 @@ fix th ](#basic-data-binding-with-listt) - - [IEnumerable Data Binding](#ienumerable-data-binding) - - [Multiple Series with Different Data Sources](#multiple-series-with-different-data-sources) -- [2. DataManager Integration](#2-datamanager-integration) - - [Remote Data Binding](#remote-data-binding) - - [Local DataManager with Query](#local-datamanager-with-query) - - [Custom DataManager with Filtering](#custom-datamanager-with-filtering) -- [3. Dynamic Data Updates](#3-dynamic-data-updates) - - [Adding Data Points Dynamically](#adding-data-points-dynamically) - - [Removing Data Points](#removing-data-points) - - [Updating Existing Data](#updating-existing-data) - - [Replacing Entire Dataset](#replacing-entire-dataset) -- [4. Data Editing](#4-data-editing) - - [Enable Inline Data Editing](#enable-inline-data-editing) - - [Data Editing with Drag and Drop](#data-editing-with-drag-and-drop) -- [5. Sorting](#5-sorting) - - [Sort by X-Axis (Ascending)](#sort-by-x-axis-ascending) - - [Sort by Y-Axis (Descending)](#sort-by-y-axis-descending) - - [Programmatic Sorting](#programmatic-sorting) -- [6. Empty Points Handling](#6-empty-points-handling) - - [Null Value Handling](#null-value-handling) - - [Average Mode for Empty Points](#average-mode-for-empty-points) - - [Zero Mode for Empty Points](#zero-mode-for-empty-points) - - [Drop Mode (Skip Empty Points)](#drop-mode-skip-empty-points) -- [7. Data Serialization](#7-data-serialization) - - [JSON Data Binding](#json-data-binding) - - [Deserialize from API Response](#deserialize-from-api-response) - - [Complex JSON Structure](#complex-json-structure) -- [8. Live/Real-time Data](#8-livereal-time-data) - - [Continuous Data Updates with Timer](#continuous-data-updates-with-timer) - - [SignalR Real-time Updates](#signalr-real-time-updates) -- [9. Performance Tips for Large Datasets](#9-performance-tips-for-large-datasets) - - [Virtual Scrolling Pattern](#virtual-scrolling-pattern) - - [Lazy Loading Pattern](#lazy-loading-pattern) - - [Data Aggregation for Performance](#data-aggregation-for-performance) - - [Disable Animations for Large Datasets](#disable-animations-for-large-datasets) -- [Best Practices](#best-practices) -- [Common Pitfalls](#common-pitfalls) - -# Blazor Chart Data Handling Reference - -Complete guide to data handling, binding, manipulation, and optimization patterns for Syncfusion Blazor Charts. - ---- - -## 1. Data Binding - -### Basic Data Binding with List +# Data Handling -```razor -@using Syncfusion.Blazor.Toolkit.Charts +> **Verified against source** — exposed binding source is +> `IEnumerable`-shaped via the `SfBaseComponent`-derived `ChartSeries` +> `DataSource` parameter. Verified against +> `src/Components/Charts/Chart/Series/ChartSeries.cs`. Last source +> audit: **2026-08-24**. - - - - +`SfChart` accepts a few different data sources, when each is appropriate, +and how to mutate them at runtime. -@code { - public class SalesData - { - public string Month { get; set; } - public double Sales { get; set; } - } +> **Sample data** — see [`_includes/sample-data.md`](_includes/sample-data.md). +> This file's snippets use `LatestData : List` (in-memory) +> and `Live : ObservableCollection` (live-streaming), +> with `SeriesPoint(string X, double Y)` and `DatePoint(DateTime When, +> double Value)`. - private List salesData = new List - { - new SalesData { Month = "Jan", Sales = 35 }, - new SalesData { Month = "Feb", Sales = 28 }, - new SalesData { Month = "Mar", Sales = 34 }, - new SalesData { Month = "Apr", Sales = 32 }, - new SalesData { Month = "May", Sales = 40 } - }; -} -``` +## Table of contents -### IEnumerable Data Binding +- Pick a data source (decision table) +- In-memory `List` (most common) +- `DataManager` / `SfDataManager` (server-side paging, filtering) +- Dynamic update (replace the list entirely) +- Live / streaming updates (observable + state notification) +- Sort (`ChartSorting`, `Sort(propertyName, direction)`) +- Clearing sort +- Data editing (drag-to-edit — see also `advanced-features.md`) +- Empty points (see also `advanced-features.md`) -```razor - - - +## Pick a data source -@code { - public class ChartPoint - { - public double X { get; set; } - public double Y { get; set; } - } +| Need | Recipe | +|------|--------| +| ≤ 1,000 items, host-rendered | `DataSource="@MyList"` | +| Server paging/filtering | `DataSource="@new SfDataManager() { Url = … }"` or adapter | +| Re-render on push | `ObservableCollection` + `OnInitialized` subscribe, or `IDataManager` event | +| Static set with `Sort()` | `List` is enough; `Sort()` reorders at the chart layer | +| Streaming telemetry | Re-set `_data = NewData` then call `StateHasChanged` + `RefreshAsync` | - private IEnumerable GetChartData() - { - return Enumerable.Range(1, 10).Select(i => new ChartPoint - { - X = i, - Y = Math.Sin(i * 0.5) * 100 - }); - } -} -``` +All paths require **interactive** render mode unless the data is pre-baked +and you are OK with the chart not responding to post-render state changes. -### Multiple Series with Different Data Sources +## In-memory `List` ```razor - - - - + + - -@code { - private List actualData = new List(); - private List forecastData = new List(); - - protected override void OnInitialized() - { - actualData = GenerateData(DateTime.Now.AddMonths(-6), 180); - forecastData = GenerateData(DateTime.Now, 90); - } - - private List GenerateData(DateTime startDate, int days) - { - var data = new List(); - for (int i = 0; i < days; i++) - { - data.Add(new DataPoint - { - Date = startDate.AddDays(i), - Value = 50 + (i * 0.5) + (new Random().NextDouble() * 10) - }); - } - return data; - } - - public class DataPoint - { - public DateTime Date { get; set; } - public double Value { get; set; } - } -} ``` ---- - -## 2. DataManager Integration - -### Remote Data Binding - -```razor -@using Syncfusion.Blazor.Toolkit.Charts -@using Syncfusion.Blazor.Data - - - - - - - -``` +`XName` / `YName` are **case-sensitive string property names that match +your record's CLR properties**. This is the single most common reason a +chart silently renders empty. If you can't get `YName` working, verify the +property casing in the toolbar pane of bUnit (or with a break on the chart +series render event). -### Local DataManager with Query +## `SfDataManager` (server or OData) ```razor -@using Syncfusion.Blazor.Data - - - - + + + + @code { - private object[] products = new object[] - { - new { Category = "Electronics", Amount = 150 }, - new { Category = "Clothing", Amount = 120 }, - new { Category = "Food", Amount = 90 }, - new { Category = "Books", Amount = 60 } + SfDataManager manager = new() { + Url = "/api/sales", + CrossDomain = true, + Adaptor = Adaptors.WebApiAdaptor }; } ``` -### Custom DataManager with Filtering - -```razor - - - - - @{ - var query = new Syncfusion.Blazor.Data.Query() - .Where("Value", "greaterthan", 50) - .Take(10); - } - - - - - -@code { - private List allData = new List(); - - protected override void OnInitialized() - { - allData = Enumerable.Range(1, 50).Select(i => new DataItem - { - Name = $"Item {i}", - Value = new Random().Next(20, 100) - }).ToList(); - } - - public class DataItem - { - public string Name { get; set; } - public double Value { get; set; } - } -} -``` - ---- - -## 3. Dynamic Data Updates +Adaptor values ship with the Blazor Datas package: `UrlAdaptor`, +`WebApiAdaptor`, `ODataAdaptor`, `WebMethodAdaptor`. See +`Syncfusion.Blazor.Data` for the full list and their parameters. -### Adding Data Points Dynamically +## Dynamic update (replace the list) ```razor - - - + - +Reload @code { - private SfChart chart; - private List chartData = new List(); - private int counter = 0; - - protected override void OnInitialized() - { - for (int i = 0; i < 10; i++) - { - chartData.Add(new TimeSeriesData { Time = i, Value = i * 10 }); - } - counter = 10; - } - - private async Task AddDataPoint() - { - chartData.Add(new TimeSeriesData { Time = counter, Value = counter * 10 + new Random().Next(-5, 5) }); - counter++; - await chart.RefreshAsync(); - } + SfChart ChartRef = default!; + List LatestData = new() { /* … */ }; - public class TimeSeriesData + async Task Reload() { - public int Time { get; set; } - public double Value { get; set; } + // Replace the field reference; Blazor's standard diff+kick triggers re-render. + LatestData = await FetchSeriesAsync(); + await ChartRef.RefreshAsync(); } } ``` -### Removing Data Points +`RefreshAsync(bool shouldAnimate = true)` is the canonical way to mark +"data changed, redraw". Wait for the await — sync refresh is **not** +exposed; the toolkit only has the `Task`-returning variant. -```razor - - +## Live / streaming updates -@code { - private async Task RemoveLastPoint() - { - if (chartData.Any()) - { - chartData.RemoveAt(chartData.Count - 1); - await chart.RefreshAsync(); - } - } - - private async Task RemoveByCondition() - { - chartData.RemoveAll(d => d.Value < 50); - await chart.RefreshAsync(); - } -} -``` - -### Updating Existing Data - -```razor - - - -@code { - private async Task UpdateRandomPoint() - { - if (chartData.Any()) - { - var random = new Random(); - var index = random.Next(chartData.Count); - chartData[index].Value = random.Next(10, 100); - await chart.RefreshAsync(); - } - } - - private async Task UpdateAllValues() - { - foreach (var item in chartData) - { - item.Value *= 2; - } - await chart.RefreshAsync(); - } -} -``` - -### Replacing Entire Dataset - -```razor - - -@code { - private async Task LoadNewDataset() - { - chartData.Clear(); - var random = new Random(); - for (int i = 0; i < 20; i++) - { - chartData.Add(new TimeSeriesData { Time = i, Value = random.Next(50, 150) }); - } - await chart.RefreshAsync(); - } -} -``` - ---- - -## 4. Data Editing - -### Enable Inline Data Editing - -```razor - - - - - - -@code { - public class EditablePoint - { - public string X { get; set; } - public double Y { get; set; } - } - - private List editableData = new List - { - new EditablePoint { X = "A", Y = 20 }, - new EditablePoint { X = "B", Y = 30 }, - new EditablePoint { X = "C", Y = 25 } - }; -} -``` - -### Data Editing with Drag and Drop - -```razor - - - - - - - -
Last Edit: @lastEditMessage
- -@code { - private string lastEditMessage = "None"; - private List dragData = new List - { - new SalesData { Month = "Jan", Sales = 35 }, - new SalesData { Month = "Feb", Sales = 28 }, - new SalesData { Month = "Mar", Sales = 34 } - }; - - private void HandleDragComplete(IDragCompleteEventArgs args) - { - lastEditMessage = $"Point {args.X} updated to value {args.Y}"; - } -} -``` - ---- - -## 5. Sorting - -### Sort by X-Axis (Ascending) - -```razor - - - - - - -@code { - private List unsortedData = new List - { - new CategoryData { Category = "Zebra", Value = 45 }, - new CategoryData { Category = "Apple", Value = 30 }, - new CategoryData { Category = "Mango", Value = 60 } - }; - - public class CategoryData - { - public string Category { get; set; } - public double Value { get; set; } - } -} -``` - -### Sort by Y-Axis (Descending) - -```razor - - - - - - -@code { - private List salesByRegion = new List - { - new RegionSales { Region = "North", Revenue = 120 }, - new RegionSales { Region = "South", Revenue = 200 }, - new RegionSales { Region = "East", Revenue = 150 }, - new RegionSales { Region = "West", Revenue = 180 } - }; - - public class RegionSales - { - public string Region { get; set; } - public double Revenue { get; set; } - } -} -``` - -### Programmatic Sorting - -```razor - - - -@code { - private void SortAscending() - { - salesByRegion = salesByRegion.OrderBy(x => x.Revenue).ToList(); - StateHasChanged(); - } - - private void SortDescending() - { - salesByRegion = salesByRegion.OrderByDescending(x => x.Revenue).ToList(); - StateHasChanged(); - } -} -``` - ---- - -## 6. Empty Points Handling - -### Null Value Handling - -```razor - - - - - - -@code { - public class DataWithNulls - { - public int X { get; set; } - public double? Y { get; set; } - } - - private List dataWithNulls = new List - { - new DataWithNulls { X = 1, Y = 20 }, - new DataWithNulls { X = 2, Y = null }, - new DataWithNulls { X = 3, Y = 30 }, - new DataWithNulls { X = 4, Y = null }, - new DataWithNulls { X = 5, Y = 40 } - }; -} -``` - -### Average Mode for Empty Points - -```razor - - - -``` - -### Zero Mode for Empty Points - -```razor - - - -``` - -### Drop Mode (Skip Empty Points) - -```razor - - - - -``` - ---- - -## 7. Data Serialization - - - -### Deserialize from API Response - -```razor -@inject HttpClient Http - -@code { - protected override async Task OnInitializedAsync() - { - var response = await Http.GetStringAsync("api/chartdata"); - jsonData = JsonSerializer.Deserialize>(response); - } -} -``` - -### Complex JSON Structure - -```razor -@code { - protected override void OnInitialized() - { - string complexJson = @"{ - ""sales"": [ - { ""month"": ""Jan"", ""revenue"": 45000, ""costs"": 30000 }, - { ""month"": ""Feb"", ""revenue"": 52000, ""costs"": 32000 } - ] - }"; - - var jsonDoc = JsonDocument.Parse(complexJson); - var salesArray = jsonDoc.RootElement.GetProperty("sales"); - - complexData = JsonSerializer.Deserialize>(salesArray.GetRawText()); - } - - private List complexData = new List(); - - public class ComplexData - { - public string Month { get; set; } - public double Revenue { get; set; } - public double Costs { get; set; } - } -} -``` - ---- - -## 8. Live/Real-time Data - -### Continuous Data Updates with Timer +The chart re-renders when the bound reference changes. Two flavors work: ```razor @implements IDisposable - - - - + + @code { - private SfChart liveChart; - private List liveData = new List(); - private System.Threading.Timer timer; - private int timeCounter = 0; - private Random random = new Random(); + ObservableCollection Live = new(); + SfChart ChartRef = default!; protected override void OnInitialized() { - // Initialize with some data - for (int i = 0; i < 20; i++) - { - liveData.Add(new LiveDataPoint { Time = i, Value = 50 + random.Next(-10, 10) }); - } - timeCounter = 20; - - // Start live updates every 1 second - timer = new System.Threading.Timer(async _ => await UpdateLiveData(), null, 1000, 1000); - } - - private async Task UpdateLiveData() - { - await InvokeAsync(async () => - { - // Add new point - liveData.Add(new LiveDataPoint - { - Time = timeCounter++, - Value = liveData.Last().Value + random.Next(-5, 5) - }); - - // Keep only last 50 points - if (liveData.Count > 50) - { - liveData.RemoveAt(0); - } - - await liveChart.RefreshAsync(); - }); + Live.CollectionChanged += (_, _) => _ = ChartRef.RefreshAsync(); + _ = Task.Run(StreamLoopAsync); } - public void Dispose() + async Task StreamLoopAsync() { - timer?.Dispose(); - } - - public class LiveDataPoint - { - public int Time { get; set; } - public double Value { get; set; } - } -} -``` - -### SignalR Real-time Updates - -```razor -@using Microsoft.AspNetCore.SignalR.Client -@implements IAsyncDisposable - - - - - -@code { - private SfChart signalChart; - private HubConnection hubConnection; - private List signalData = new List(); - - protected override async Task OnInitializedAsync() - { - hubConnection = new HubConnectionBuilder() - .WithUrl("https://yourserver.com/stockhub") - .Build(); - - hubConnection.On("ReceiveStockUpdate", async (stockPrice) => + while (true) { - signalData.Add(stockPrice); - if (signalData.Count > 100) signalData.RemoveAt(0); - await signalChart.RefreshAsync(); - StateHasChanged(); - }); - - await hubConnection.StartAsync(); - } - - public async ValueTask DisposeAsync() - { - if (hubConnection != null) - { - await hubConnection.DisposeAsync(); + Live.Add(new(DateTime.Now.Second.ToString(), Random.Shared.NextDouble() * 50)); + await Task.Delay(500); } } - public class StockPrice + public void Dispose() { - public DateTime Timestamp { get; set; } - public double Price { get; set; } + Live.CollectionChanged -= (_, _) => ChartRef.RefreshAsync(); } } ``` ---- +| Pattern | Caveat | +|---------|--------| +| `ObservableCollection` + `CollectionChanged` | Works in interactive render modes only | +| Replace the field with a new list | Always triggers re-render — simplest, lowest-friction | +| Replace with a `new List<>` after mutation | Don't — reference equality won't change → no re-render | -## 9. Performance Tips for Large Datasets +## Sort -### Virtual Scrolling Pattern +There are two parallel mechanisms — pick the one you need: ```razor - - - - - - - + + + + @code { - private List largeDataset = new List(); + SfChart ChartRef = default!; - protected override void OnInitialized() - { - // Generate 10,000 data points - var startDate = DateTime.Now.AddDays(-10000); - for (int i = 0; i < 10000; i++) - { - largeDataset.Add(new LargeDataPoint - { - Date = startDate.AddDays(i), - Value = 100 + (Math.Sin(i * 0.1) * 50) - }); - } - } + void SortByY() => + ChartRef.Sort("Y", Syncfusion.Blazor.Toolkit.Data.ListSortDirection.Descending); - public class LargeDataPoint - { - public DateTime Date { get; set; } - public double Value { get; set; } - } + void ClearSort() => ChartRef.ClearSort(); } ``` -### Lazy Loading Pattern - -```razor - - - - - -@code { - private List visibleData = new List(); - private int currentIndex = 0; - private const int chunkSize = 100; - - protected override void OnInitialized() - { - LoadNextChunk(); - } - - private void LoadNextChunk() - { - for (int i = 0; i < chunkSize; i++) - { - visibleData.Add(new DataPoint - { - Index = currentIndex++, - Value = new Random().NextDouble() * 100 - }); - } - } - - private void HandleScrollEnd(ScrollEventArgs args) - { - // Load more data when user scrolls to the end - LoadNextChunk(); - StateHasChanged(); - } - - public class DataPoint - { - public int Index { get; set; } - public double Value { get; set; } - } -} -``` - -### Data Aggregation for Performance - -```razor -@code { - private List AggregateData(List rawData, int groupSize) - { - return rawData - .Select((point, index) => new { point, index }) - .GroupBy(x => x.index / groupSize) - .Select(group => new AggregatedData - { - GroupIndex = group.Key, - AverageValue = group.Average(x => x.point.Value), - MaxValue = group.Max(x => x.point.Value), - MinValue = group.Min(x => x.point.Value) - }) - .ToList(); - } - - public class RawDataPoint - { - public double Value { get; set; } - } - - public class AggregatedData - { - public int GroupIndex { get; set; } - public double AverageValue { get; set; } - public double MaxValue { get; set; } - public double MinValue { get; set; } - } -} -``` - -### Disable Animations for Large Datasets - -```razor - - - - -``` - ---- - -## Best Practices - -1. **Use appropriate data structures**: List for mutable data, IEnumerable for read-only scenarios -2. **Call RefreshAsync() after data updates**: Ensures chart reflects changes -3. **Disable animations for real-time data**: Improves performance -4. **Limit visible data points**: Use scrolling/zooming for large datasets (>1000 points) -5. **Use DataManager for remote data**: Built-in adapters for API integration -6. **Handle null values explicitly**: Use EmptyPointSettings to control behavior -7. **Implement INotifyPropertyChanged**: For automatic updates on property changes -8. **Dispose timers and connections**: Prevent memory leaks in real-time scenarios -9. **Aggregate data when possible**: Reduce points while maintaining trends -10. **Test with production data volumes**: Performance varies with data size - ---- - -## Common Pitfalls - -- **Forgetting to call RefreshAsync()**: Chart won't update after data changes -- **Not disposing timers**: Memory leaks in live data scenarios -- **Enabling animations with frequent updates**: Causes performance issues -- **Binding to properties instead of collections**: Use ObservableCollection or call StateHasChanged() -- **Not handling empty/null data**: Can cause rendering errors -- **Excessive data points without optimization**: Browser performance degradation +Both go through the same underlying code. When you need flip-flopping between +sort orders, use programmatic. When it's a fixed order at construction, +use ``. ---- +## Common gotchas -**Last Updated**: March 2026 -**Version**: 1.0 -**Syncfusion Blazor Charts**: v25.x+ +- `XName` / `YName` property casing mismatches render an empty chart — verify + the property names match exactly. +- Replacing an `ObservableCollection`'s mutating in-place gives you no + reference change; Blazor may skip the diff. Use `Add`/`Remove` on the live + collection, or assign a new backing list. +- Data-driven render requires interactive render mode (`@rendermode + InteractiveServer` or `InteractiveWebAssembly`). +- `RefreshAsync` doesn't skip animation by default; pass `false` for live + feeds where steady-state is more important than visual transitions. +- `DataManager` paging is **not** automatic; you need the server endpoint + to honor `take` / `skip` like a Syncfusion DataManager-aware scaffold. \ No newline at end of file diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/references/events.md b/.github/skills/syncfusion-blazor-toolkit-charts/references/events.md index 712d928..760a3a8 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/references/events.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/references/events.md @@ -1,1068 +1,218 @@ -# Syncfusion Blazor Charts - Events Reference +# Events -Comprehensive reference guide for all chart events organized by category. +> **Verified against source** — the events listed below are the ones +> surfaced by `` in this toolkit. Last source audit: +> **2026-08-24**. -## Table of Contents +All chart-scoped events subscribe via ``, which is a **child of +``** (never of an axis). Per-axis callbacks like +`OnAxisLabelRender`, `OnAxisMultiLevelLabelRender`, and +`OnAxisActualRangeCalculated` all live on this same root-level +`` — they are *not* nested under `` or +``. Verified at +`src/Components/Charts/Chart/ChartEvent/ChartEvents.razor.cs:38, 367, 674, +891` and the dispatcher in +`src/Components/Charts/Chart/Renderer/AxisRenderer/ChartAxisRenderer.cs:1198`. -- [Chart Lifecycle Events](#chart-lifecycle-events) - - [Loaded](#loaded) - - [SizeChanged](#sizechanged) -- [Mouse and Touch Events](#mouse-and-touch-events) - - [ChartMouseMove](#chartmousemove) - - [ChartMouseClick](#chartmouseclick) - - [ChartMouseDown](#chartmousedown) - - [ChartMouseUp](#chartmouseup) - - [ChartMouseLeave](#chartmouseleave) - - [PointClick (OnPointClick)](#pointclick-onpointclick) - - [PointMove](#pointmove) -- [Rendering Events](#rendering-events) - - [OnPointRender](#onpointrender) - - [OnDataLabelRender](#ondatalabelrender) - - [OnAxisLabelRender](#onaxislabelrender) - - [OnLegendItemRender](#onlegenditemrender) - - [OnSeriesRender](#onseriesrender) -- [Interactive Events](#interactive-events) - - [OnSelectionChanged](#onselectionchanged) - - [OnLegendClick](#onlegendclick) - - [OnAxisLabelClick](#onaxislabelclick) - - [OnDataEdit](#ondataedit) - - [OnDataEditCompleted](#ondataeditcompleted) -- [Zoom and Scroll Events](#zoom-and-scroll-events) - - [OnZoomStart](#onzoomstart) - - [OnZoomEnd](#onzoomend) - - [OnScrollChanged](#onscrollchanged) -- [Export and Print Events](#export-and-print-events) - - [OnExportComplete](#onexportcomplete) - - [OnPrintComplete](#onprintcomplete) -- [Axis Events](#axis-events) - - [OnAxisActualRangeCalculated](#onaxisactualrangecalculated) - - [OnAxisMultiLevelLabelRender](#onaxismultilevellabelrender) - - [OnMultiLevelLabelClick](#onmultilevellabelclick) -- [Additional Events](#additional-events) - - [TooltipRender](#tooltiprender) - - [SharedTooltipRender](#sharedtooltiprender) +> **Sample data** — see [`_includes/sample-data.md`](_includes/sample-data.md). +> This file's snippets bind to `Data : List` where +> `SeriesPoint(string X, double Y)`. +This reference only lists events that are **wired** in the +`Syncfusion.Blazor.Toolkit.Charts` assembly. Older docs sometimes list +`ChartMouseDown` / `ChartMouseUp` handlers — those are not exposed at the +chart component level. -## Chart Lifecycle Events +## Table of contents -### Loaded +- Lifecycle (`Loaded`, `SizeChanged`) +- Mouse / touch (`ChartMouseMove`, `ChartMouseClick`, `ChartMouseLeave`, + `OnPointClick`) +- Rendering (`OnPointRender`, `OnSeriesRender`, `OnDataLabelRender`, + `OnAxisLabelRender`, `OnLegendItemRender`, `OnAxisActualRangeCalculated`, + `OnAxisMultiLevelLabelRender`) +- Selection / legend / data-edit +- Zoom / scroll +- Tooltip (`TooltipRender`, `SharedTooltipRender`) +- Export / print -Triggers after the chart has completed loading. +All rendering event handlers mutate `args` properties (`args.Fill`, +`args.Text`, …) and return; they cannot raise callbacks into Blazor. -**EventArgs**: `LoadedEventArgs` - -**Example**: - -```razor - - - - - - - -@code { - public void OnChartLoadedHandler(LoadedEventArgs args) - { - // Initialize chart-dependent operations - } -} -``` - -**Use Cases**: -- Initialize chart-dependent operations -- Trigger data refresh after chart initialization -- Set up external integrations - -### SizeChanged - -Triggers when the chart is resized. - -**EventArgs**: `ResizeEventArgs` -- `CurrentSize` - Current size of the chart -- `PreviousSize` - Previous size of the chart - -**Example**: - -```razor - - - - - - - -@code { - public void OnSizeChangedHandler(ResizeEventArgs args) - { - Console.WriteLine($"Resized from {args.PreviousSize.Width}x{args.PreviousSize.Height} to {args.CurrentSize.Width}x{args.CurrentSize.Height}"); - } -} -``` - -**Use Cases**: -- Responsive layout adjustments -- Recalculate chart dimensions for adaptive displays -- Log resize events for analytics - ---- - -## Mouse and Touch Events - -### ChartMouseMove - -Triggers when the mouse moves over the chart area. - -**EventArgs**: `ChartMouseEventArgs` -- `MouseX` - Current mouse X coordinate -- `MouseY` - Current mouse Y coordinate - -**Example**: - -```razor - - - - - - - -@code { - public void OnMouseMoveHandler(ChartMouseEventArgs args) - { - // Display coordinates in a custom tooltip or status bar - Console.WriteLine($"Mouse at X: {args.MouseX}, Y: {args.MouseY}"); - } -} -``` - -**Use Cases**: -- Custom cursor tracking -- Display real-time coordinates -- Implement custom hover effects - -### ChartMouseClick - -Triggers when the chart is clicked. - -**EventArgs**: `ChartMouseEventArgs` -- `MouseX` - Current mouse X coordinate -- `MouseY` - Current mouse Y coordinate - -**Example**: - -```razor - - - - - - - -@code { - public void OnChartClickHandler(ChartMouseEventArgs args) - { - // Handle chart background clicks - Console.WriteLine("Chart clicked"); - } -} -``` - -**Use Cases**: -- Clear selections on background click -- Show chart-level context menus -- Reset zoom/pan on click - -### ChartMouseDown - -Triggers when the mouse button is pressed on the chart. - -**EventArgs**: `ChartMouseEventArgs` -- `MouseX` - Current mouse X coordinate -- `MouseY` - Current mouse Y coordinate - -**Example**: - -```razor - - - - - - - -@code { - public void OnMouseDownHandler(ChartMouseEventArgs args) - { - // Capture mouse down for custom drag operations - } -} -``` - -**Use Cases**: -- Custom drag operations -- Selection box initialization -- Custom annotation placement - -### ChartMouseUp - -Triggers when the mouse button is released over the chart. - -**EventArgs**: `ChartMouseEventArgs` -- `MouseX` - Current mouse X coordinate -- `MouseY` - Current mouse Y coordinate - -**Example**: - -```razor - - - - - - - -@code { - public void OnMouseUpHandler(ChartMouseEventArgs args) - { - // Complete drag operation - } -} -``` - -**Use Cases**: -- Complete custom drag operations -- Finalize selection boxes -- Save annotation positions - -### ChartMouseLeave - -Triggers when the mouse leaves the chart area. This event has no specific arguments. - -**Example**: - -```razor - - - - - - - -@code { - public void OnMouseLeaveHandler() - { - // Hide custom tooltips - } -} -``` - -**Use Cases**: -- Hide custom tooltips or overlays -- Reset hover states -- Clean up temporary UI elements - -### PointClick (OnPointClick) - -Triggers when a data point is clicked. - -**EventArgs**: `PointEventArgs` -- `Chart` - Current chart instance -- `Point` - Clicked data point -- `PointIndex` - Index of the clicked point -- `Series` - Series containing the point -- `SeriesIndex` - Index of the series -- `PageX` - Window page X location -- `PageY` - Window page Y location -- `X` - X coordinate of click -- `Y` - Y coordinate of click - -**Example**: - -```razor - - - - - - - -@code { - public void OnPointClickHandler(PointEventArgs args) - { - Console.WriteLine($"Clicked: {args.Point.X} - {args.Point.Y}"); - // Navigate to detail view or show modal - } -} -``` - -**Use Cases**: -- Navigate to detail views -- Display point-specific modals -- Trigger data updates - -### PointMove - -Triggers when the mouse hovers over a data point. Uses the same `PointEventArgs` as PointClick. - -**Example**: - -```razor - - - - - - - - -@code { - public void OnPointMoveHandler(PointEventArgs args) - { - // Highlight related data or show additional info - } -} -``` - -**Use Cases**: -- Custom hover effects -- Display additional point information -- Highlight related data points - ---- - -## Rendering Events - -### OnPointRender - -Triggers before each data point is rendered. - -**EventArgs**: `PointRenderEventArgs` -- `Border` - Point border color and width -- `CornerRadius` - Corner radius for rectangular series -- `Fill` - Point fill color -- `Height` - Point height -- `Width` - Point width -- `Shape` - Marker shape -- `Point` - Current data point -- `Series` - Current series - -**Example**: - -```razor - - - - - - - -@code { - public void OnPointRenderHandler(PointRenderEventArgs args) - { - // Color points based on value - if ((double)args.Point.Y < 30) - args.Fill = "#FF0000"; - else if ((double)args.Point.Y > 50) - args.Fill = "#00FF00"; - } -} -``` - -**Use Cases**: -- Conditional point coloring -- Dynamic shape assignment -- Apply custom styling based on data - -### OnDataLabelRender - -Triggers before data labels are rendered. - -**EventArgs**: `TextRenderEventArgs` -- `Border` - Label border settings -- `Color` - Label text color -- `Font` - Font settings -- `Template` - Template data -- `Text` - Label text - -**Example**: - -```razor - - - - - - - - - - -@code { - public void OnDataLabelRenderHandler(TextRenderEventArgs args) - { - // Format labels with custom prefix/suffix - args.Text = "$" + args.Text + "K"; - args.Color = "#333333"; - } -} -``` - -**Use Cases**: -- Format label text with units or currency -- Apply conditional styling to labels -- Customize label appearance - -### OnAxisLabelRender - -Triggers before axis labels are rendered. - -**EventArgs**: `AxisLabelRenderEventArgs` -- `LabelStyle` - Font settings for the label -- `Text` - Label text -- `Value` - Label value - -**Example**: - -```razor - - - - - - - -@code { - public void OnAxisLabelRenderHandler(AxisLabelRenderEventArgs args) - { - // Abbreviate month names - if (args.Text.Length > 3) - args.Text = args.Text.Substring(0, 3); - } -} -``` - -**Use Cases**: -- Format axis labels -- Abbreviate long labels -- Apply custom number formatting - -### OnLegendItemRender - -Triggers before legend items are rendered. - -**EventArgs**: `LegendRenderEventArgs` -- `Fill` - Legend icon fill color -- `MarkerShape` - Marker shape -- `Shape` - Legend icon shape -- `Text` - Legend text - -**Example**: - -```razor - - - - - - - - - -@code { - public void OnLegendRenderHandler(LegendRenderEventArgs args) - { - // Customize legend text - args.Text = args.Text.ToUpper(); - } -} -``` - -**Use Cases**: -- Customize legend text -- Change legend icon shapes -- Apply custom legend styling - -### OnSeriesRender - -Triggers before each series is rendered. This event allows customization of series appearance before rendering. - -**Example**: +## Lifecycle ```razor - - - - - - -@code { - public void OnSeriesRenderHandler() - { - // Apply series-level customization - } -} -``` - -**Use Cases**: -- Apply conditional series styling -- Modify series properties before render -- Dynamic series configuration - ---- - -## Interactive Events - -### OnSelectionChanged - -Triggers after point, series, or cluster selection is completed. - -**EventArgs**: `SelectionCompleteEventArgs` -- `SelectedDataValues` - Collection of selected data X and Y values - -**Example**: - -```razor - - - - - + + + @code { - public void OnSelectionChangedHandler(SelectionCompleteEventArgs args) - { - Console.WriteLine($"Selected {args.SelectedDataValues.Count} points"); - // Update related components based on selection - } -} -``` - -**Use Cases**: -- Filter related data based on selection -- Update dashboards with selected data -- Enable/disable actions based on selection - -### OnLegendClick + void OnLoaded(LoadedEventArgs _) { /* render-ready hook */ } -Triggers when a legend item is clicked. - -**EventArgs**: `LegendClickEventArgs` -- `LegendShape` - Shape of the legend item -- `LegendText` - Text of the legend item -- `Series` - Associated series - -**Example**: - -```razor - - - - - - - - - -@code { - public void OnLegendClickHandler(LegendClickEventArgs args) + void OnSizeChanged(ResizeEventArgs args) { - Console.WriteLine($"Clicked legend: {args.LegendText}"); - // Toggle series visibility or filter data + Console.WriteLine($"size -> {args.CurrentSize.Width}x{args.CurrentSize.Height}"); } } ``` -**Use Cases**: -- Custom legend toggle behavior -- Filter data by series -- Track legend interactions - -### OnAxisLabelClick - -Triggers when an axis label is clicked. - -**EventArgs**: `AxisLabelClickEventArgs` -- `Axis` - Current axis -- `Chart` - Chart instance -- `Index` - Label index -- `LabelID` - Label element ID -- `Location` - Label location -- `Text` - Label text -- `Value` - Label value - -**Example**: +## Mouse / touch ```razor - - - - - - + @code { - public void OnAxisLabelClickHandler(AxisLabelClickEventArgs args) + void OnMove(ChartMouseEventArgs a) { /* MouseX, MouseY */ } + void OnClick(ChartMouseEventArgs a) { /* */ } + void OnLeave(ChartMouseEventArgs a) { /* */ } + void OnPoint(PointEventArgs a) { - Console.WriteLine($"Clicked axis label: {args.Text}"); - // Filter data by category or drill down + // a.PointIndex, a.SeriesIndex, a.Point.X, a.Point.Y } } ``` -**Use Cases**: -- Drill-down navigation by category -- Filter data by axis label -- Show category-specific details - -### OnDataEdit - -Triggers while dragging a data point (when data editing is enabled). - -**EventArgs**: `DataEditingEventArgs` -- `NewValue` - New value of the point -- `OldValue` - Previous value of the point -- `Point` - Current point being edited -- `PointIndex` - Index of the point -- `Series` - Current series -- `SeriesIndex` - Index of the series +`ChartMouseMove` triggers on every move; do not run heavy work in the +handler — debounce with `InvokeAsync(StateHasChanged)` if you call. -**Example**: +## Rendering customization ```razor - - - - - - - + @code { - public void OnDataEditHandler(DataEditingEventArgs args) + void SeriesRender(SeriesRenderEventArgs a) { - Console.WriteLine($"Editing: {args.OldValue} -> {args.NewValue}"); - // Validate changes during drag + if (a.Series.Name == "Sales") a.Fill = "#FF4081"; } -} -``` - -**Use Cases**: -- Real-time validation during editing -- Display preview of changes -- Constrain edit values - -### OnDataEditCompleted -Triggers when data point dragging is completed. - -**EventArgs**: `DataEditingEventArgs` (same as OnDataEdit) - -**Example**: - -```razor - - - - - - - - -@code { - public void OnDataEditCompletedHandler(DataEditingEventArgs args) + void PointRender(PointRenderEventArgs a) { - // Update data source with new value - SalesData[args.PointIndex].Sales = args.NewValue; + a.Fill = (a.Point.Index % 2 != 0) ? "#ff6347" : "#009cb8"; } -} -``` - -**Use Cases**: -- Save edited values to database -- Recalculate dependent values -- Log data changes ---- - -## Zoom and Scroll Events - -### OnZoomStart - -Triggers when zoom selection starts. - -**EventArgs**: `ZoomingEventArgs` -- `AxisCollection` - Collection of axes being zoomed - -**Example**: - -```razor - - - - - - - - -@code { - public void OnZoomStartHandler(ZoomingEventArgs args) + void DataLabelRender(TextRenderEventArgs a) { - Console.WriteLine("Zoom started"); - // Show zoom indicator + if (a.Point.Y > 50) a.Font.Color = "green"; } -} -``` - -**Use Cases**: -- Display zoom indicators -- Disable other interactions during zoom -- Log zoom operations - -### OnZoomEnd - -Triggers when zoom selection is completed. - -**EventArgs**: `ZoomingEventArgs` -- `AxisCollection` - Collection of axes that were zoomed - -**Example**: -```razor - - - - - - - - -@code { - public void OnZoomEndHandler(ZoomingEventArgs args) + void LegendRender(LegendRenderEventArgs a) { - // Load detailed data for zoomed range - // Update related charts + a.Shape = Syncfusion.Blazor.Toolkit.ChartShape.Circle; } } ``` -**Use Cases**: -- Load detailed data for zoomed range -- Synchronize zoom with other charts -- Save zoom state +| Use case | Render handler | Modify | +|----------|----------------|--------| +| Per-series color | `OnSeriesRender` | `args.Fill`, `args.Opacity`, `args.Width` | +| Per-point color | `OnPointRender` | `args.Fill`, `args.Border.Color/Width` | +| Per-label text | `OnDataLabelRender` | `args.Text`, `args.Font.*` | +| Per-axis-label | `OnAxisLabelRender` | `args.Text`, `args.LabelStyle` | +| Per-legend item | `OnLegendItemRender` | `args.Text`, `args.Shape`, `args.Fill` | -### OnScrollChanged +These run during render, not as separate dispatches — keep them pure and +allocation-light. -Triggers while scrolling the chart. - -**EventArgs**: `ScrollEventArgs` -- `Axis` - Current axis being scrolled -- `CurrentRange` - Current range -- `PreviousAxisRange` - Previous axis range -- `PreviousRange` - Previous range -- `PreviousZoomFactor` - Previous zoom factor -- `PreviousZoomPosition` - Previous zoom position -- `Range` - Current range -- `ZoomFactor` - Current zoom factor -- `ZoomPosition` - Current zoom position - -**Example**: +## Selection / legend / data-edit ```razor - - - - - - - - - -@code { - public void OnScrollChangedHandler(ScrollEventArgs args) - { - // Lazy load data as user scrolls - Console.WriteLine($"Scrolled to position: {args.ZoomPosition}"); - } -} -``` - -**Use Cases**: -- Lazy load data during scroll -- Synchronize scroll with other charts -- Update range indicators - ---- + -## Export and Print Events + -### OnExportComplete - -Triggers after chart export is completed. - -**EventArgs**: `ExportEventArgs` -- `DataUrl` - Data URL of the exported file - -**Example**: - -```razor - - - - - - - +@* All of these go on a single root-level block: *@ + @code { - SfChart chartRef; - - public async Task ExportChart() + void SelectionChanged(SelectionChangedEventArgs a) { - await chartRef.ExportAsync(ExportType.PNG, "SalesChart"); + // a.SelectedData, a.SelectedIndexes } - public void OnExportCompleteHandler(ExportEventArgs args) - { - Console.WriteLine("Export completed"); - // Show success message - } -} -``` - -**Use Cases**: -- Show export success notification -- Log export operations -- Process exported file data - -### OnPrintComplete - -Triggers after chart print is completed. This event has no specific arguments. - -**Example**: - -```razor - - - - - - - - -@code { - SfChart chartRef; - - public async Task PrintChart() - { - await chartRef.PrintAsync(); - } + void LegendClick(LegendClickEventArgs a) { /* toggle series */ } + void AxisLabelClick(AxisLabelClickEventArgs a) { /* */ } - public void OnPrintCompleteHandler() - { - Console.WriteLine("Print completed"); - // Log print operation - } + void OnEdit(DataEditingEventArgs a) { /* drag in progress */ } + void OnEditDone(DataEditingEventArgs a) { /* drag finished */ } } ``` -**Use Cases**: -- Show print confirmation -- Log print operations -- Track usage metrics - ---- - -## Axis Events - -### OnAxisActualRangeCalculated - -Triggers before each axis range is calculated. +`DataEditingEventArgs` is what you want for drag-to-edit pointers (see +`references/advanced-features.md` for the `ChartDataEditSettings` that +enables them). -**EventArgs**: `AxisRangeCalculatedEventArgs` -- `Interval` - Current axis interval -- `Maximum` - Current maximum value -- `Minimum` - Current minimum value - -**Example**: +## Zoom / scroll ```razor - - - - - - - -@code { - public void OnAxisRangeHandler(AxisRangeCalculatedEventArgs args) - { - // Adjust axis range dynamically - args.Maximum = args.Maximum * 1.1; // Add 10% padding - } -} -``` - -**Use Cases**: -- Adjust axis ranges dynamically -- Add padding to axis limits -- Synchronize axis ranges across multiple charts - -### OnAxisMultiLevelLabelRender + -Triggers while rendering multi-level axis labels. - -**EventArgs**: `AxisMultiLabelRenderEventArgs` -- `Alignment` - Label alignment -- `Text` - Label text -- `TextStyle` - Text style settings - -**Example**: - -```razor - - - - - - - - - - - - - - - + @code { - public void OnMultiLevelLabelRenderHandler(AxisMultiLabelRenderEventArgs args) - { - // Customize multi-level label appearance - args.Text = args.Text.ToUpper(); - } + void OnZoomStart(ZoomEventArgs a) { /* before rectangle drawn */ } + void OnZoomEnd(ZoomEventArgs a) { /* committed zoom range */ } + void OnScroll(ScrollEventArgs a) { /* panning */ } } ``` -**Use Cases**: -- Customize multi-level label text -- Apply conditional styling -- Format hierarchical labels - -### OnMultiLevelLabelClick +`OnScrollChanged` only fires when a `ChartZoomSettings.EnablePan="true"` is +set; without that flag the chart has no scroll surface. -Triggers when a multi-level axis label is clicked. - -**EventArgs**: `MultiLevelLabelClickEventArgs` -- `Axis` - Axis of the clicked label -- `CustomAttributes` - Custom attributes for the label -- `End` - End value of the label range -- `Level` - Current level of the label -- `Start` - Start value of the label range -- `Text` - Label text - -**Example**: +## Tooltip ```razor - - - - - - - - - - - - - - - + @code { - public void OnMultiLevelLabelClickHandler(MultiLevelLabelClickEventArgs args) + void TipRender(TooltipRenderEventArgs a) { - Console.WriteLine($"Clicked: {args.Text} (Level {args.Level})"); - // Filter data by quarter or drill down + a.Text = $"Series {a.Data.SeriesName}: {a.Data.Point.Y:0.##}"; } -} -``` - -**Use Cases**: -- Drill down by time periods -- Filter data by hierarchical categories -- Navigate to period-specific views - ---- -## Additional Events - -### TooltipRender - -Triggers before a tooltip is rendered for a single series. - -**EventArgs**: `TooltipRenderEventArgs` -- `HeaderText` - Tooltip header text -- `Text` - Tooltip content text - -**Example**: - -```razor - - - - - - - - -@code { - public void OnTooltipRenderHandler(TooltipRenderEventArgs args) + void SharedTipRender(TooltipRenderEventArgs a) { - args.Text = $"Sales: ${args.Text}K"; + a.HeaderText = $"{a.Data.Point.X} (combined)"; } } ``` -**Use Cases**: -- Format tooltip content -- Add custom metrics to tooltips -- Conditional tooltip styling - -### SharedTooltipRender - -Triggers before a shared tooltip (multiple series) is rendered. +Both render args expose `Data.Point` (X / Y from the source) and +`Data.SeriesName`. Mutating `Text` overrides the auto-format. -**EventArgs**: `SharedTooltipRenderEventArgs` -- `HeaderText` - Shared tooltip header -- `Text` - Shared tooltip content - -**Example**: - -```razor - - - - - - - - - - -@code { - public void OnSharedTooltipRenderHandler(SharedTooltipRenderEventArgs args) - { - args.HeaderText = $"Period: {args.HeaderText}"; - } -} -``` +## Handler-mode gotchas -**Use Cases**: -- Format shared tooltip headers -- Customize multi-series tooltip layout -- Add comparison data to tooltips +1. All rendering event handlers *must* mutate `args` (or be no-op); they + don't return values into the chart. +2. Handlers that call out to Blazor state (e.g. `myField = "x"`) need an + explicit `InvokeAsync(StateHasChanged)` if downstream UI depends on it. +3. Don't subscribe `OnPointClick` *and* `ChartMouseClick` to do the same + thing — `OnPointClick` only fires when a real point was clicked, and + the general click handler fires more frequently; using both produces + duplicate logic. +4. All events — including per-axis callbacks like `OnAxisLabelRender`, + `OnAxisMultiLevelLabelRender`, and `OnAxisActualRangeCalculated` — + live on a single root-level `` block. Putting + `` inside `` is a common typo and + will not compile (the axis's `[Parameter]` surface does not + accept a `ChartEvents` child). +5. The render handlers above never own thresholds or scale — keep business + logic in `OnChartMouseClick` / `OnSelectionChanged`, *not* in + `OnPointRender` (which runs once per point per render). \ No newline at end of file diff --git a/.github/skills/syncfusion-blazor-toolkit-charts/references/getting-started.md b/.github/skills/syncfusion-blazor-toolkit-charts/references/getting-started.md index 1f28cdd..5509370 100644 --- a/.github/skills/syncfusion-blazor-toolkit-charts/references/getting-started.md +++ b/.github/skills/syncfusion-blazor-toolkit-charts/references/getting-started.md @@ -1,4 +1,4 @@ -## Table of Contents +## Table of Contents - [Overview](#overview) - [Prerequisites](#prerequisites) @@ -25,12 +25,18 @@ - [Common Setup Issues](#common-setup-issues) - [Issue: Chart Not Rendering](#issue-chart-not-rendering) - [Issue: No Data Displayed](#issue-no-data-displayed) - - [Issue: Interactive Mode Error](#issue-interactive-mode-error) + - [Issue: Interactive Features Inactive Under Static SSR](#issue-interactive-features-inactive-under-static-ssr) - [Next Steps](#next-steps) - [Additional Resources](#additional-resources) # Getting Started with Blazor Chart Component +> **Verified against source** — enum members cross-checked against +> `src/Base/Enumeration.cs`; method surface and render-mode behaviour +> cross-checked against `src/Components/.../SfChart.razor.*.cs`. When +> this and the source code disagree, **source wins** — file a backlog +> task to update this file. Last source audit: **2026-08-24**. + This guide covers everything you need to set up and create your first Blazor Chart component, including installation, configuration, and basic chart implementation. ## Overview @@ -75,7 +81,7 @@ cd BlazorChartApp #### Step 2: Install NuGet Package ```bash -dotnet add package Syncfusion.Blazor.Toolkit.Charts +dotnet add package Syncfusion.Blazor.Toolkit dotnet restore ``` @@ -94,7 +100,7 @@ cd BlazorChartApp #### Step 3: Install Package ```bash -dotnet add package Syncfusion.Blazor.Toolkit.Charts +dotnet add package Syncfusion.Blazor.Toolkit dotnet restore ``` @@ -105,16 +111,18 @@ dotnet restore Open `_Imports.razor` and add: ```razor -@using Syncfusion.Blazor +@using Syncfusion.Blazor.Toolkit @using Syncfusion.Blazor.Toolkit.Charts ``` ### Step 2: Register Syncfusion Services -In `Program.cs`, add the Syncfusion Blazor service: +In `Program.cs`, register the toolkit once. The chart (and any other +toolkit components used in the same app) depend on this registration; +do **not** add any separate component-package registration. ```csharp -using Syncfusion.Blazor; +using Syncfusion.Blazor.Toolkit; var builder = WebApplication.CreateBuilder(args); @@ -122,28 +130,27 @@ var builder = WebApplication.CreateBuilder(args); builder.Services.AddRazorComponents() .AddInteractiveServerComponents(); -// Register Syncfusion Blazor Service -builder.Services.AddSyncfusionBlazor(); +// Register the Syncfusion Blazor Toolkit (one call per project — for Auto/WASM, +// register in BOTH the server Program.cs and .Client Program.cs). +builder.Services.AddSyncfusionBlazorToolkit(); var app = builder.Build(); ``` -### Step 3: Add Script Reference - -In `App.razor` (or `_Layout.cshtml` for older templates), add the script reference before the closing `` tag: - -```html - - - - - -``` - -**Note:** The Chart component script is included in `syncfusion-blazor.min.js`. For individual component scripts: -```html - -``` +> **JS modules are loaded by the chart itself.** Once `Chart.OnAfterRenderAsync` +> runs, the chart imports these modules from the NuGet static content +> (served by the host's static-files middleware, NOT by +> `_framework/blazor.web.js`): +> +> - `_content/Syncfusion.Blazor.Toolkit/scripts/svgbase.js` +> - `_content/Syncfusion.Blazor.Toolkit/scripts/touch.js` +> - `_content/Syncfusion.Blazor.Toolkit/scripts/animation.js` +> - `_content/Syncfusion.Blazor.Toolkit/scripts/chart.js` +> +> Do **not** add manual `