Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<SyncfusionControls>
<ControlCategory Name="Data Visualization">
<Control Title="Cartesian Charts" ControlName="SfCartesianChart" Image="cartesianchart.png" Description="Plot over 20+ chart types with extensive features like data label, trackball and zooming.">
<Control Title="Cartesian Charts" ControlName="SfCartesianChart" StatusTag="Updated" Image="cartesianchart.png" Description="Plot over 20+ chart types with extensive features like data label, trackball and zooming.">
<Category Title="Chart Types">
<SubCategory Title="Column">
<CardLayout>
Expand Down Expand Up @@ -170,6 +170,8 @@

<Sample Title="Annotation" SampleName="ShapeAnnotationSample" Description="This sample showcases the shape annotation support, which includes line, horizontal line, vertical line, rectangle, and ellipse." SearchTags="annotation, chart annotation"/>

<Sample Title="Empty Points" StatusTag="New" SampleName="EmptyPointSupport" SearchTags="empty points, missing data points, missing values, incomplete data, data gaps, incomplete records, blank entries"/>

<Category Title="Plot band">
<Sample Title="Horizontal" SampleName="HorizontalPlotBand" Platforms="Android,iOS" SearchTags="horizontal plot, band, plotband"/>
<Sample Title="Horizontal" SampleName="HorizontalPlotBandWindows" Platforms="Windows,MacCatalyst" SearchTags="horizontal plot, band, plot band"/>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8" ?>
<localCore:SampleView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart.EmptyPointSupport"
xmlns:local="clr-namespace:Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart"
xmlns:localCore="clr-namespace:Syncfusion.Maui.ControlsGallery;assembly=Syncfusion.Maui.ControlsGallery"
xmlns:chart="clr-namespace:Syncfusion.Maui.Toolkit.Charts;assembly=Syncfusion.Maui.Toolkit">

<localCore:SampleView.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<local:CartesianChartColorResources/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</localCore:SampleView.Resources>

<localCore:SampleView.Content>
<chart:SfCartesianChart x:Name="Chart" HorizontalOptions="Fill" VerticalOptions="Fill">

<chart:SfCartesianChart.BindingContext>
<local:EmptyPointViewModel x:Name="ViewModel"/>
</chart:SfCartesianChart.BindingContext>

<chart:SfCartesianChart.Title>
<Label Text="Crop Yield Across Climate Zones" Margin="0,0,0,5" HorizontalOptions="Fill" HorizontalTextAlignment="Center" VerticalOptions="Center" FontSize="16"/>
</chart:SfCartesianChart.Title>

<chart:SfCartesianChart.XAxes>
<chart:CategoryAxis IsVisible="True" ShowMajorGridLines="False" EdgeLabelsDrawingMode="Shift" LabelRotation="{OnPlatform Android=-45,iOS=-45}"/>
</chart:SfCartesianChart.XAxes>

<chart:SfCartesianChart.YAxes>
<chart:NumericalAxis ShowMajorGridLines="True" ShowMinorGridLines="False" Minimum="0" Interval="20" Maximum="100">
<chart:NumericalAxis.AxisLineStyle>
<chart:ChartLineStyle StrokeWidth="0" />
</chart:NumericalAxis.AxisLineStyle>
<chart:NumericalAxis.Title>
<chart:ChartAxisTitle Text="Crop Yield (Tons)"/>
</chart:NumericalAxis.Title>
</chart:NumericalAxis>
</chart:SfCartesianChart.YAxes>

<chart:SfCartesianChart.Legend>
<chart:ChartLegend/>
</chart:SfCartesianChart.Legend>

<chart:AreaSeries ItemsSource="{Binding EmptyPointData}"
XBindingPath="Name"
YBindingPath="Value"
EnableAnimation="{Binding EnableAnimation}"
Stroke="{AppThemeBinding Light={StaticResource series3Light}, Dark={StaticResource series3Dark}}"
Fill="{AppThemeBinding Light={StaticResource series3Light30}, Dark={StaticResource series3Dark30}}"
StrokeWidth="2"
ShowMarkers="True"
EmptyPointMode="{Binding EmptyPointMode}"
Label="Wheat"
LegendIcon="SeriesType"
EnableTooltip="True">
<chart:AreaSeries.MarkerSettings>
<chart:ChartMarkerSettings Fill="{AppThemeBinding Default={StaticResource ContentBackground}}" Stroke="{AppThemeBinding Light={StaticResource series3Light}, Dark={StaticResource series3Dark}}" StrokeWidth="1.5"/>
</chart:AreaSeries.MarkerSettings>
</chart:AreaSeries>

<chart:AreaSeries ItemsSource="{Binding EmptyPointData}"
XBindingPath="Name"
YBindingPath="High"
EnableAnimation="{Binding EnableAnimation}"
Stroke="{AppThemeBinding Light={StaticResource series2Light}, Dark={StaticResource series2Dark}}"
Fill="{AppThemeBinding Light={StaticResource series2Light30}, Dark={StaticResource series2Dark30}}"
StrokeWidth="2"
ShowMarkers="True"
EmptyPointMode="{Binding EmptyPointMode}"
Label="Corn"
LegendIcon="SeriesType"
EnableTooltip="True">
<chart:AreaSeries.MarkerSettings>
<chart:ChartMarkerSettings Fill="{AppThemeBinding Default={StaticResource ContentBackground}}" Stroke="{AppThemeBinding Light={StaticResource series2Light}, Dark={StaticResource series2Dark}}" StrokeWidth="1.5"/>
</chart:AreaSeries.MarkerSettings>
</chart:AreaSeries>

<chart:AreaSeries ItemsSource="{Binding EmptyPointData}"
XBindingPath="Name"
YBindingPath="Low"
EnableAnimation="{Binding EnableAnimation}"
Stroke="{AppThemeBinding Light={StaticResource series1Light}, Dark={StaticResource series1Dark}}"
Fill="{AppThemeBinding Light={StaticResource series1Light30}, Dark={StaticResource series1Dark30}}"
StrokeWidth="2"
ShowMarkers="True"
EmptyPointMode="{Binding EmptyPointMode}"
Label="Rice"
LegendIcon="SeriesType"
EnableTooltip="True">
<chart:AreaSeries.MarkerSettings>
<chart:ChartMarkerSettings Fill="{AppThemeBinding Default={StaticResource ContentBackground}}" Stroke="{AppThemeBinding Light={StaticResource series1Light}, Dark={StaticResource series1Dark}}" StrokeWidth="1.5"/>
</chart:AreaSeries.MarkerSettings>
</chart:AreaSeries>

</chart:SfCartesianChart>
</localCore:SampleView.Content>

<localCore:SampleView.OptionView>
<Grid>
<VerticalStackLayout Spacing="15">
<HorizontalStackLayout Spacing="5">
<Label Text="Empty Point Mode: " VerticalOptions="Start" HorizontalOptions="Center" Padding="5" FontSize="17"/>
<Picker WidthRequest="{OnPlatform MacCatalyst=70, iOS=70}" ItemsSource="{Binding Source={x:Reference ViewModel},Path=EmptyPointModeValues}"
SelectedItem="{Binding Source={x:Reference ViewModel}, Path=EmptyPointModeValues[0]}"
VerticalOptions="Start" HorizontalOptions="Fill"
x:Name="picker"
BackgroundColor="{AppThemeBinding Light={StaticResource BackgroundLight}, Dark={StaticResource BackgroundDark}}"
TextColor="{AppThemeBinding Light={StaticResource TextColourLight}, Dark={StaticResource TextColourDark}}"
SelectedIndex="0"
SelectedIndexChanged="picker_SelectedIndexChanged">
</Picker>
</HorizontalStackLayout>
</VerticalStackLayout>
</Grid>
</localCore:SampleView.OptionView>

</localCore:SampleView>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

using Syncfusion.Maui.Toolkit.Charts;

namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
{
public partial class EmptyPointSupport : SampleView
{
public EmptyPointSupport()
{
InitializeComponent();
}

private void picker_SelectedIndexChanged(object sender, EventArgs e)
{
var picker = (Picker)sender;
int selectedIndex = picker.SelectedIndex;
switch (selectedIndex)
{
case 1:
ViewModel.EmptyPointMode = EmptyPointMode.Zero;
break;

case 2:
ViewModel.EmptyPointMode = EmptyPointMode.Average;
break;

default:
ViewModel.EmptyPointMode = EmptyPointMode.None;
break;
}
}

public override void OnDisappearing()
{
base.OnDisappearing();
Chart.Handler?.DisconnectHandler();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

using System.Collections.ObjectModel;
using Syncfusion.Maui.Toolkit.Charts;

namespace Syncfusion.Maui.ControlsGallery.CartesianChart.SfCartesianChart
{
public class EmptyPointViewModel : BaseViewModel
{
private EmptyPointMode emptypointMode;
public EmptyPointMode EmptyPointMode
{
get => emptypointMode;
set
{
if (emptypointMode != value)
{
emptypointMode = value;
OnPropertyChanged(nameof(EmptyPointMode));
}
}
}

public string[] EmptyPointModeValues => ["None", "Zero", "Average"];

public ObservableCollection<ChartDataModel> EmptyPointData { get; set; }

public EmptyPointViewModel()
{

EmptyPointData =
[
new ChartDataModel("Tropical", 85, 70, 50),
new ChartDataModel("Continental", 80, 65, 40),
new ChartDataModel("Mediterranean", 82, 60, 30),
new ChartDataModel("Arid", double.NaN, double.NaN, double.NaN),
new ChartDataModel("Polar", double.NaN, double.NaN, double.NaN),
new ChartDataModel("Temperate", 75, 50, 40),
new ChartDataModel("Oceanic", 90, 65, 40),
new ChartDataModel("Highland", 95, 60, 30),
];
}
}
}
9 changes: 9 additions & 0 deletions maui/src/Charts/Area/Partial/CartesianChartArea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,15 @@ internal void UpdateStackingSeries()
{
if (series is StackingSeriesBase stackingSeries && stackingSeries.IsVisible)
{

if (stackingSeries.RequiredEmptyPointReset)
{
stackingSeries.ResetEmptyPointIndexes();
stackingSeries.RequiredEmptyPointReset = false;
}

stackingSeries.ValidateYValues();

var stackingGroup = stackingSeries.GroupingLabel;
var stackingXAxis = stackingSeries.ActualXAxis;
var stackingYAxis = stackingSeries.ActualYAxis;
Expand Down
10 changes: 10 additions & 0 deletions maui/src/Charts/Axis/Layouts/CartesianAxisLayout.cs
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,16 @@ void UpdateSeriesRange(ReadOnlyObservableCollection<ChartSeries> visibleSeries)
{
foreach (CartesianSeries series in visibleSeries.Cast<CartesianSeries>())
{
if (!series.IsStacking)
{
if (series.RequiredEmptyPointReset)
{
series.ResetEmptyPointIndexes();
series.RequiredEmptyPointReset = false;
}

series.ValidateYValues();
}

if (!series.SegmentsCreated) //creates segment if segmentsCreated is false.
{
Expand Down
2 changes: 1 addition & 1 deletion maui/src/Charts/DataLabel/ChartDataLabelSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ internal string GetLabelContent(double value)
}
else
{
labelContent = value.ToString("#.##");
labelContent = value == 0 ? value.ToString("0.##") : value.ToString("#.##");
}

return labelContent;
Expand Down
1 change: 1 addition & 0 deletions maui/src/Charts/Layouts/ChartSeriesView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ internal void InternalCreateSegments()
_series.OldSegments = null;
}

_series.UpdateEmptyPointSettings();
_series.SegmentsCreated = true;
}
}
Expand Down
13 changes: 11 additions & 2 deletions maui/src/Charts/Segment/CartesianSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
/// </summary>
public abstract class CartesianSegment : ChartSegment
{
#region Property

/// <summary>
/// Get the bool value to identify the empty point segment.
/// </summary>
public bool IsEmpty { get; internal set; }

#endregion

#region Methods

#region Animation Methods
Expand Down Expand Up @@ -53,7 +62,7 @@ internal void CalculateDataLabelPosition(double xValue, double yValue, double ac
return;
}

IsEmpty = double.IsNaN(yValue);
IsZero = double.IsNaN(yValue);

double x = xValue, y = xyDataSeries.GetDataLabelPositionAtIndex(Index);

Expand Down Expand Up @@ -81,7 +90,7 @@ internal override void UpdateDataLabels()
dataLabel.Item = Item;
dataLabel.Label = LabelContent ?? string.Empty;

LabelPositionPoint = InVisibleRange && !IsEmpty ? CartesianDataLabelSettings.CalculateDataLabelPoint(series, this, new PointF((float)DataLabelXPosition, (float)DataLabelYPosition), dataLabelSettings.LabelStyle) : new PointF(float.NaN, float.NaN);
LabelPositionPoint = InVisibleRange && !IsZero ? CartesianDataLabelSettings.CalculateDataLabelPoint(series, this, new PointF((float)DataLabelXPosition, (float)DataLabelYPosition), dataLabelSettings.LabelStyle) : new PointF(float.NaN, float.NaN);

dataLabel.XPosition = LabelPositionPoint.X;
dataLabel.YPosition = LabelPositionPoint.Y;
Expand Down
2 changes: 1 addition & 1 deletion maui/src/Charts/Segment/ChartSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ internal bool HasStroke

internal PointF LabelPositionPoint { get; set; }

internal bool IsEmpty { get; set; }
internal bool IsZero { get; set; }

internal SeriesView? SeriesView { get; set; }

Expand Down
2 changes: 1 addition & 1 deletion maui/src/Charts/Segment/FastLineSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,7 @@ internal override void OnDataLabelLayout()
dataLabel.Item = xyDataSeries.ActualData?[i];
dataLabel.Label = LabelContent;

if (!InVisibleRange || IsEmpty)
if (!InVisibleRange || IsZero)
{
LabelPositionPoint = new PointF(float.NaN, float.NaN);
}
Expand Down
2 changes: 1 addition & 1 deletion maui/src/Charts/Segment/HiLoOpenCloseSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ void UpdateDataLabels(PointF highPoint, PointF lowPoint, PointF openPoint, Point

void CalculateDataLabelPositions(double xValue, double high, double low, double open, double close, FinancialSeriesBase series)
{
IsEmpty = double.IsNaN(high) && double.IsNaN(low);
IsZero = double.IsNaN(high) && double.IsNaN(low);
InVisibleRange = series.IsDataInVisibleRange(xValue, high) && series.IsDataInVisibleRange(xValue, low);
PointF highPoint = GetDataLabelPosition(xValue, high, series);
PointF lowPoint = GetDataLabelPosition(xValue, low, series);
Expand Down
2 changes: 1 addition & 1 deletion maui/src/Charts/Segment/PieSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,7 @@ internal override void OnDataLabelLayout()
}

var dataLabelSettings = pieSeries.DataLabelSettings;
IsEmpty = double.IsNaN(YValue) || YValue == 0;
IsZero = double.IsNaN(YValue) || YValue == 0;
float segmentRadius = pieSeries.GetDataLabelRadius();
segmentRadius = Index == pieSeries.ExplodeIndex ? segmentRadius + (float)pieSeries.ExplodeRadius : segmentRadius;
PointF center = pieSeries.Center;
Expand Down
4 changes: 2 additions & 2 deletions maui/src/Charts/Segment/RangeAreaSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ internal override void OnDataLabelLayout()
dataLabel.Item = series.ActualData[i];
dataLabel.Label = LabelContent ?? string.Empty;

if (!InVisibleRange || IsEmpty)
if (!InVisibleRange || IsZero)
{
LabelPositionPoint = new PointF(float.NaN, float.NaN);
}
Expand Down Expand Up @@ -195,7 +195,7 @@ internal override void OnDataLabelLayout()
dataLabel.Item = series.ActualData[i];
dataLabel.Label = LabelContent ?? string.Empty;

if (!InVisibleRange || IsEmpty)
if (!InVisibleRange || IsZero)
{
LabelPositionPoint = new PointF(float.NaN, float.NaN);
}
Expand Down
2 changes: 1 addition & 1 deletion maui/src/Charts/Segment/RangeColumnSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ void LayoutSegment()

void CalculateDataLabelsPosition(double xValue, double high, double low, RangeColumnSeries series)
{
IsEmpty = double.IsNaN(high) && double.IsNaN(low);
IsZero = double.IsNaN(high) && double.IsNaN(low);
InVisibleRange = series.IsDataInVisibleRange(xValue, high) && series.IsDataInVisibleRange(xValue, low);
double x = xValue, x1 = xValue, y = series.GetDataLabelPositionAtIndex(Index, high), y1 = series.GetDataLabelPositionAtIndex(Index, low);
series.CalculateDataPointPosition(Index, ref x, ref y);
Expand Down
4 changes: 2 additions & 2 deletions maui/src/Charts/Segment/SplineRangeAreaSegment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ internal override void OnDataLabelLayout()
dataLabel.Item = series.ActualData[i];
dataLabel.Label = LabelContent ?? string.Empty;

if (!InVisibleRange || IsEmpty)
if (!InVisibleRange || IsZero)
{
LabelPositionPoint = new PointF(float.NaN, float.NaN);
}
Expand Down Expand Up @@ -173,7 +173,7 @@ internal override void OnDataLabelLayout()
dataLabel.Item = series.ActualData[i];
dataLabel.Label = LabelContent ?? string.Empty;

if (!InVisibleRange || IsEmpty)
if (!InVisibleRange || IsZero)
{
LabelPositionPoint = new PointF(float.NaN, float.NaN);
}
Expand Down
2 changes: 1 addition & 1 deletion maui/src/Charts/Series/AreaSeries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public partial class AreaSeries : XYDataSeries, IDrawCustomLegendIcon, IMarkerDe
#region Fields

bool _needToAnimateMarker;

internal override bool IsFillEmptyPoint { get { return false; } }
#endregion

#region Bindable Properties
Expand Down
Loading