Articles in this section
Category / Section

How to create the neumorphic ui chart using .NET MAUI Chart (SfCartesianChart)?

10 mins read

This article delves into the creation of visually stunning Neumorphism UI charts using Syncfusion® .NET MAUI Column Chart. Follow this step-by-step tutorial that utilizes a custom class inheriting from IDrawable and Graphics view. This approach ensures a seamless integration of design and data representation within your application.

Step 1: Implementing SfShadowDrawer Class

The SfShadowDrawer class is a base class that implements the IDrawable interface. It serves as a foundation for creating drawable elements with shadow effects. This class provides properties and methods to control shadow properties, such as offset, blur, color, and opacity.

Step 2: Implement a Method to Draw and Apply Shadow

Implement the Draw method for the IDrawable interface in the custom SfShadowDrawer class. This method is responsible for drawing the shadow by applying the shadow effect and filling the rounded rectangle. Applies the shadow effect to the canvas based on the provided parameters.

[SfShadowDrawer]

public void Draw(ICanvas canvas, RectF dirtyRect)
{
    double radius = CornerRadius > dirtyRect.Width / 2 ? dirtyRect.Width / 2 : CornerRadius;

    canvas.SaveState();
    canvas.ClipPath(GetDrawPath(dirtyRect, (float)radius));
    DrawShadow(canvas, dirtyRect);
    canvas.RestoreState();
}

internal void ApplyShadow(ICanvas canvas, RectF dirtyRect, SizeF offset, Color shadowColor, float opacity, double cornerRadius)
{
    canvas.SaveState();
    canvas.FillColor = BackgroundColor;
    canvas.SetShadow(offset, Blur, shadowColor.WithAlpha(opacity));
    canvas.FillRoundedRectangle(dirtyRect, cornerRadius);
    canvas.RestoreState();
}

Step 3: Implementing SfNeumorphismDrawer Class

The SfNeumorphismDrawer class is a custom drawable class that extends SfShadowDrawer. It is specifically designed for creating a neumorphic (soft shadow) effect in user interfaces. This class provides properties and methods to control various aspects of the neumorphic shadow, such as color, offset, and opacity.

It overrides the DrawShadow method from the base class SfShadowDrawer to implement the neumorphic shadow drawing logic. The shadow is drawn based on the pressed state, adjusting the offset and shadow positions accordingly.

[SfNeumorphismDrawer]

protected override void DrawShadow(ICanvas canvas, RectF dirtyRect)
{
    if (IsPressedState)
    {
        double radius = CornerRadius > dirtyRect.Width / 2 ? dirtyRect.Width / 2 : CornerRadius;
        if (dirtyRect.Width / 3 < radius)
        {
            ApplyShadow(canvas, new RectF(dirtyRect.Left, dirtyRect.Top, -dirtyRect.Width, dirtyRect.Height), Offset, ShadowColor, Opacity, radius);
            ApplyShadow(canvas, new RectF(dirtyRect.Right, dirtyRect.Top, dirtyRect.Width, dirtyRect.Height), LightOffSet, lightShadowColor, LightOpacity, radius);
        }

        else
        {
            ApplyShadow(canvas, new RectF(dirtyRect.Left, dirtyRect.Top, -dirtyRect.Width, dirtyRect.Height), Offset, ShadowColor, Opacity, radius);
            ApplyShadow(canvas, new RectF(dirtyRect.Left - 10, dirtyRect.Top, dirtyRect.Width + 10, -dirtyRect.Height), Offset, ShadowColor, Opacity, radius);
            ApplyShadow(canvas, new RectF(dirtyRect.Right, dirtyRect.Top, dirtyRect.Width, dirtyRect.Height), LightOffSet, lightShadowColor, LightOpacity, radius);
            ApplyShadow(canvas, new RectF(dirtyRect.Left, dirtyRect.Bottom, dirtyRect.Width, dirtyRect.Height), LightOffSet, lightShadowColor, LightOpacity, radius);
        }
    }
    else
    {

        var paddingRect = new RectF() { Left = dirtyRect.Left + Padding, Top = dirtyRect.Top + Padding, Right = dirtyRect.Right - Padding, Bottom = dirtyRect.Bottom - Padding };
        double radius = CornerRadius > paddingRect.Width / 2 ? paddingRect.Width / 2 : CornerRadius;
        ApplyShadow(canvas, paddingRect, Offset, ShadowColor, Opacity, radius);
        ApplyShadow(canvas, paddingRect, LightOffSet, lightShadowColor, LightOpacity, radius);
    }
}

Step 4: Implementing a SfNeumorphismView Class

The SfNeumorphismView class extends ContentView and provides a container for displaying a neumorphic (soft shadow) effect. It includes a Grid and a GraphicsView for rendering the neumorphic shadow based on the provided SfNeumorphismDrawer. Additionally, it exposes properties and methods to manage the drawable content and handle property changes.

[SfNeumorphismView]

public SfNeumorphismView()
{
    Drawable = new SfNeumorphismDrawer();

    grid = new Grid();
    grid.Margin = new Thickness(0);

    graphicsView = new GraphicsView();
    graphicsView.Margin = new Thickness(0);
    graphicsView.BackgroundColor = Colors.Transparent;
    graphicsView.SetBinding(GraphicsView.DrawableProperty, new Binding() { Path = nameof(Drawable), Source = this });

    grid.Children.Add(graphicsView);
    base.Content = grid;
}

Step 5: Implementing the SfNeumorphismColumnSeries and SfNeumorphismColumnSegment Classes

The SfNeumorphismColumnSeries class is a custom implementation of the ColumnSeries in Syncfusion.Maui.Charts library. It introduces a neumorphic (soft shadow) effect to column series by associating an SfNeumorphismDrawer with each column segment.

This class overrides the CreateSegment method to create a custom SfNeumorphismColumnSegment instead of the default ColumnSegment. Associates the Drawable property with the newly created segment.

[SfNeumorphismColumnSeries]

public class SfNeumorphismColumnSeries : ColumnSeries
{
    protected override ChartSegment CreateSegment()
    {
        return new SfNeumorphismColumnSegment(Drawable);
    }
}

The SfNeumorphismColumnSegment class is a custom implementation of the ColumnSegment in Syncfusion.Maui.Charts library. It enhances the default column segment by incorporating a neumorphic shadow effect using the associated SfNeumorphismDrawer.

It overrides the base method to implement custom drawing logic. Draws the neumorphic shadow using the SfNeumorphismDrawer associated with the segment.

[SfNeumorphismColumnSegment]

public class SfNeumorphismColumnSegment : ColumnSegment
{
    protected override void Draw(ICanvas canvas)
    {
        if (Series is ColumnSeries series && series.ActualYAxis is NumericalAxis yAxis)
        {
            var top = yAxis.ValueToPoint(Convert.ToDouble(yAxis.Maximum ?? double.NaN));
    
            var trackRect = new RectF() { Left = Left, Top = top, Right = Right, Bottom = Bottom };
    
            Drawable.Draw(canvas, trackRect);
        }
    }
}

Step 6: Define and Apply styles for the Neumorphic Drawer

Defines styles for neumorphic drawers with varying configurations, such as outer view, normal, and pressed states. These styles are then referenced throughout the UI for consistent appearance.

[XAML]

<ContentPage.Resources>
    <control:SfNeumorphismDrawer BackgroundColor="#F5F5F5" Padding="20" LightOpacity="0.8" CornerRadius="20" x:Key="outerViewDrawable">
    </control:SfNeumorphismDrawer>

    <control:SfNeumorphismDrawer BackgroundColor="#F5F5F5" Padding="8" LightOpacity="1" Offset="3,3" LightOffSet="-4,-4" CornerRadius="{OnPlatform Android='8',iOS='8',WinUI='10',MacCatalyst='10'}" x:Key="drawable"/>

    <control:SfNeumorphismDrawer Blur="40" IsPressedState="True" Opacity="0.3"                   LightOpacity="1" CornerRadius="20" BackgroundColor="#F5F5F5" x:Key="pressedDrawable" />
</ContentPage.Resources>

[XAML]

<control:SfNeumorphismView Drawable="{StaticResource outerViewDrawable}">
    <chart:SfCartesianChart>
        <chart:SfCartesianChart.Series>
            <control:SfNeumorphismColumnSeries Drawable="{StaticResource pressedDrawable}">
            </control:SfNeumorphismColumnSeries>
        </chart:SfCartesianChart.Series>
    </chart:SfCartesianChart>
</control:SfNeumorphismView>

After applying the styles for the content and the series, the chart will look like below.

Styles Defined for content and series

Here applied the ItemsSource to the series and Title for the chart.

[XAML]

<control:SfNeumorphismView Drawable="{StaticResource outerViewDrawable}">
        <chart:SfCartesianChart>
            <chart:SfCartesianChart.Title>
                <HorizontalStackLayout HorizontalOptions="Start">
                    </control:SfNeumorphismView>
                    <VerticalStackLayout Margin="10,0,0,0">
                        <Label Text="Year 2020"/>
                        <Label Text="Yearly spending"/>
                    </VerticalStackLayout>
                </HorizontalStackLayout>
            </chart:SfCartesianChart.Title>

            <chart:SfCartesianChart.Series>
                <control:SfNeumorphismColumnSeries Drawable="{StaticResource pressedDrawable}" ItemsSource="{Binding NeumorphismColumnData}" XBindingPath="Month" YBindingPath="Value">
                </control:SfNeumorphismColumnSeries>
            </chart:SfCartesianChart.Series>
        </chart:SfCartesianChart>
    </control:SfNeumorphismView>

Defined the styles for the series and the content view

Applied the styles for the Title.

[XAML]

<control:SfNeumorphismView Drawable="{StaticResource outerViewDrawable}">
        <chart:SfCartesianChart>
            <chart:SfCartesianChart.Title>
                <HorizontalStackLayout HorizontalOptions="Start">
                    <control:SfNeumorphismView 
                        HeightRequest="{OnPlatform Android='50',iOS='50',Default='65'}"
                        WidthRequest="{OnPlatform Android='50',iOS='50',Default='65'}" 
                        HorizontalOptions="Start"
                        Drawable="{StaticResource drawable}">
                        <Path Data="M6.5 0A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5
                          0h-3Zm3 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3Z M4 1.5H3a2 2
                          0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1A2.5 2.5 0 0 1 9.5 5h-3A2.5 2.5 0
                          0 1 4 2.5v-1ZM10 8a1 1 0 1 1 2 0v5a1 1 0 1 1-2 0V8Zm-6 4a1 1 0 1 1 2 0v1a1 1 0 1 1-2 0v-1Zm4-3a1 1 0 0 1 1 1v3a1 1 0 1 1-2 0v-3a1 1 0 0 1 1-1Z"
                          Fill="#6e8aa6" Aspect="Fill" 
                          HorizontalOptions="Center" VerticalOptions="Center" 
                          HeightRequest="{OnPlatform Android='20',iOS='20', Default='30'}" 
                          WidthRequest="{OnPlatform Android='20',iOS='20',Default='30'}" />
                    </control:SfNeumorphismView>
                <VerticalStackLayout Margin="10,0,0,0">
                    <Label Text="Year 2020" FontSize="{OnPlatform Android='12',iOS='12',WinUI='15',MacCatalyst='15'}" 
                       FontFamily="Times" FontAttributes="Bold" TextColor="#8b9eb0" Margin="{OnPlatform Android='0,10,0,3',iOS='0,10,0,3',WinUI='0,15,0,3',MacCatalyst='0,15,0,3'}"/>
                    <Label Text="Yearly spending" FontFamily="Times" FontSize="{OnPlatform Android='9',iOS='9',WinUI='12',MacCatalyst='12'}" TextColor="#8b9eb0"/>
                </VerticalStackLayout>
            </HorizontalStackLayout>
        </chart:SfCartesianChart.Title>
    </chart:SfCartesianChart>
</control:SfNeumorphismView>

Here is the final output of the Syncfusion® .NET MAUI Neumorphic Column Chart.

Final output of Neumorphic UI column chart

Download the complete sample from GitHub.

Conclusion

I hope you enjoyed learning how to create the visually stunning neumorphic UI chart using Syncfusion® .NET MAUI Chart(SfCartesianChart).
You can refer to our .NET MAUI Chart feature tour page to learn about its other groundbreaking feature representations. Explore our .NET MAUI Chart documentation to understand how to present and manipulate data.
For current customers, check out our .NET MAUI from the License and Downloads page. If you are new to Syncfusion®, try our 30-day free trial to check out our .NET MAUI Chart and other .NET MAUI components.
Please let us know in the comments section if you have any queries or require clarification. You can also contact us through our support forums, Direct-Trac, or feedback portal. We are always happy to assist you!

NeumorphismUISample.zip
Did you find this information helpful?
Yes
No
Help us improve this page
Please provide feedback or comments
Comments (0)
Please  to leave a comment
Access denied
Access denied