mirror of
https://github.com/radzenhq/radzen-blazor.git
synced 2026-07-08 18:16:08 +00:00
210 lines
7.2 KiB
C#
210 lines
7.2 KiB
C#
using Microsoft.AspNetCore.Components;
|
|
using Radzen.Blazor.Rendering;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Radzen.Blazor
|
|
{
|
|
/// <summary>
|
|
/// A chart series that displays data as vertical high-low lines in a <see cref="RadzenChart"/>.
|
|
/// Each data point renders a vertical line from the low value to the high value,
|
|
/// similar to a simplified candlestick chart without open and close values.
|
|
/// This is useful for showing value ranges such as daily temperature ranges or price ranges.
|
|
/// </summary>
|
|
/// <typeparam name="TItem">The type of data items in the series. Each item represents one high-low line.</typeparam>
|
|
/// <example>
|
|
/// <code>
|
|
/// <RadzenChart>
|
|
/// <RadzenHighLowSeries Data=@data CategoryProperty="Date"
|
|
/// HighProperty="High" LowProperty="Low" Title="Price Range" />
|
|
/// <RadzenCategoryAxis FormatString="{0:MM/dd}" />
|
|
/// </RadzenChart>
|
|
/// </code>
|
|
/// </example>
|
|
[UnconditionalSuppressMessage(TrimMessages.Trimming, TrimMessages.IL2026, Justification = TrimMessages.DataTypePreserved)]
|
|
public partial class RadzenHighLowSeries<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties | DynamicallyAccessedMemberTypes.PublicFields)] TItem> : CartesianSeries<TItem>
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the name of the property of <typeparamref name="TItem"/> that provides the High value.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string? HighProperty { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the name of the property of <typeparamref name="TItem"/> that provides the Low value.
|
|
/// </summary>
|
|
[Parameter]
|
|
public string? LowProperty { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the stroke (line) color.
|
|
/// Supports any valid CSS color value (e.g., "#FF0000", "rgb(255,0,0)").
|
|
/// If not set, the color is determined by the chart's theme color scheme.
|
|
/// </summary>
|
|
/// <value>The line color as a CSS color value, or <c>null</c> to use the theme default.</value>
|
|
[Parameter]
|
|
public string? Stroke { get; set; }
|
|
|
|
/// <summary>
|
|
/// Gets or sets the width of the high-low lines in pixels.
|
|
/// </summary>
|
|
/// <value>The stroke width in pixels. Default is 2.</value>
|
|
[Parameter]
|
|
public double StrokeWidth { get; set; } = 2;
|
|
|
|
/// <summary>
|
|
/// Gets or sets the line style pattern (solid, dashed, dotted).
|
|
/// Use <see cref="Blazor.LineType.Dashed"/> or <see cref="Blazor.LineType.Dotted"/> for non-solid lines.
|
|
/// </summary>
|
|
/// <value>The line style. Default is solid.</value>
|
|
[Parameter]
|
|
public LineType LineType { get; set; }
|
|
|
|
/// <inheritdoc />
|
|
public override async Task SetParametersAsync(ParameterView parameters)
|
|
{
|
|
// Sync ValueProperty from HighProperty so base class methods work correctly.
|
|
if (parameters.TryGetValue<string>(nameof(HighProperty), out var high) && high != HighProperty)
|
|
{
|
|
ValueProperty = high;
|
|
}
|
|
|
|
await base.SetParametersAsync(parameters);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override string Color => Stroke ?? string.Empty;
|
|
|
|
/// <inheritdoc />
|
|
public override bool ShowActivePoint => false;
|
|
|
|
/// <summary>
|
|
/// Gets a delegate that returns the High value from a data item.
|
|
/// </summary>
|
|
internal Func<TItem, double> High
|
|
{
|
|
get
|
|
{
|
|
if (string.IsNullOrEmpty(HighProperty))
|
|
{
|
|
throw new ArgumentException("HighProperty should not be empty");
|
|
}
|
|
|
|
return PropertyAccess.Getter<TItem, double>(HighProperty);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a delegate that returns the Low value from a data item.
|
|
/// </summary>
|
|
internal Func<TItem, double> Low
|
|
{
|
|
get
|
|
{
|
|
if (string.IsNullOrEmpty(LowProperty))
|
|
{
|
|
throw new ArgumentException("LowProperty should not be empty");
|
|
}
|
|
|
|
return PropertyAccess.Getter<TItem, double>(LowProperty);
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override ScaleBase TransformValueScale(ScaleBase scale)
|
|
{
|
|
ArgumentNullException.ThrowIfNull(scale);
|
|
|
|
if (Items != null && Items.Any())
|
|
{
|
|
var high = High;
|
|
var low = Low;
|
|
|
|
var minValue = Items.Min(item => low(item));
|
|
var maxValue = Items.Max(item => high(item));
|
|
|
|
scale.Input.MergeWidth(new ScaleRange { Start = minValue, End = maxValue });
|
|
}
|
|
|
|
return scale;
|
|
}
|
|
|
|
private string FormatValue(double v)
|
|
{
|
|
var chart = RequireChart();
|
|
return chart.ValueAxis.Format(chart.ValueScale, chart.ValueScale.Value(v));
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override string TooltipValue(TItem item)
|
|
{
|
|
return $"{FormatValue(Low(item))} - {FormatValue(High(item))}";
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override string TooltipStyle(TItem item)
|
|
{
|
|
var style = base.TooltipStyle(item);
|
|
|
|
if (Stroke != null)
|
|
{
|
|
return $"{style}; border-color: {Stroke};";
|
|
}
|
|
|
|
return style;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
internal override double TooltipY(TItem item)
|
|
{
|
|
var chart = RequireChart();
|
|
var highY = chart.ValueScale.Scale(High(item), true);
|
|
var lowY = chart.ValueScale.Scale(Low(item), true);
|
|
|
|
// Position tooltip at the midpoint of the high-low line.
|
|
return (highY + lowY) / 2;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override bool Contains(double x, double y, double tolerance)
|
|
{
|
|
return DataAt(x, y).Item1 != null;
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public override (object, Point) DataAt(double x, double y)
|
|
{
|
|
var chart = Chart;
|
|
if (chart == null || !Items.Any())
|
|
{
|
|
return (default!, new Point());
|
|
}
|
|
|
|
var category = ComposeCategory(chart.CategoryScale);
|
|
|
|
foreach (var data in Items)
|
|
{
|
|
var cx = category(data);
|
|
|
|
if (x >= cx - StrokeWidth && x <= cx + StrokeWidth)
|
|
{
|
|
var highY = chart.ValueScale.Scale(High(data), true);
|
|
var lowY = chart.ValueScale.Scale(Low(data), true);
|
|
var startY = Math.Min(highY, lowY);
|
|
var endY = Math.Max(highY, lowY);
|
|
|
|
if (y >= startY - StrokeWidth && y <= endY + StrokeWidth)
|
|
{
|
|
return (data!, new Point { X = cx, Y = y });
|
|
}
|
|
}
|
|
}
|
|
|
|
return (default!, new Point());
|
|
}
|
|
}
|
|
}
|