locked
How to a make an element partially fill an ellipse

    Question

  • Hello everybody, as you can see in the image below I have to make an animation in which an element go up from the bottom of a circle to arrive nearly at the center of it?

    What's the best way to achieve this effect?

    Thanks in advance for the help!

    Thursday, July 03, 2014 7:33 PM

Answers

  • Hi g,

    there are different ways to achieve that. One way is to overlay two ellipse-objects - a green and a red one - and to use an opacity mask for one to display only a part of it.

    Here's a sample with a data binding that shows the effect you want. Just past the snippet into your windows store application:

      <StackPanel Margin="50">
                <Slider x:Name="sli" Maximum="300" Value="300" IsDirectionReversed="True"/>
    
                <Grid Width="300" Height="300">
                    <Ellipse Fill="Green"/>
                    <Ellipse Fill="Red">
                        <Ellipse.Clip>
                            <RectangleGeometry Rect="0 0 300 300">
                                <RectangleGeometry.Transform>
                                    <TranslateTransform Y="{Binding ElementName=sli,Path=Value}"/>
                                </RectangleGeometry.Transform>
                            </RectangleGeometry>
                        </Ellipse.Clip>
                    </Ellipse>
                </Grid>
            </StackPanel>

    Instead of manipulating the Y-Property of the TranslateTransform-object with a data binding, you could of course also manipulate it with an animation


    Thomas Claudius Huber

    "If you can't make your app run faster, make it at least look & feel extremly fast"

    My latest app: The "Womanizer" :-)
    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com
    author of: ultimate Windows Store Apps handbook | ultimate WPF handbook | ultimate Silverlight handbook


    Thursday, July 03, 2014 8:41 PM
  • + gradient brush

    One more solution from my side; Use gradient brush. See this.

    <Ellipse Height="100" Width="100">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF07CB45" Offset="0"/>
                        <GradientStop Color="#FF07CB45" Offset="0.442"/>
                        <GradientStop Color="#FFFF3F00" Offset="0.442"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <Ellipse Height="100" Width="100">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF07CB45" Offset="0"/>
                        <GradientStop Color="#FF07CB45" Offset="0.25"/>
                        <GradientStop Color="#FFFF3F00" Offset="0.25"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <Ellipse Height="100" Width="100">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF07CB45" Offset="0"/>
                        <GradientStop Color="#FF07CB45" Offset="0.75"/>
                        <GradientStop Color="#FFFF3F00" Offset="0.75"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
    Here the trick is that I have used two gradient stops to get two solid shades in ellipse. This will actually divide ellipse in 3 sections but visually it has only 2 sections.


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!

    Friday, July 04, 2014 7:35 AM
  • While I really did not understand why do you want to place items inside shaded red area while in most case they will not be clickable here is what you need

    <Page
        x:Class="MsdnSample04072014.BlankPage1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MsdnSample04072014"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:common="using:MsdnSample04072014.Common"
        mc:Ignorable="d">
        <Page.Resources>
            <common:StarConverter x:Key="StarConverter"/>
            <common:StarInverseConverter x:Key="StarInverseConverter"/>
            <x:Double x:Key="Height">0.55</x:Double>
        </Page.Resources>
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Grid Height="200" Width="200">
                <Grid.RowDefinitions>
                    <RowDefinition Height="{Binding Converter={StaticResource StarConverter}, Mode=OneWay, Source={StaticResource Height}}"/>
                    <RowDefinition Height="{Binding Converter={StaticResource StarInverseConverter}, Mode=OneWay, Source={StaticResource Height}}"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <!-- This ellipse is used to show background shade -->
                <Ellipse Grid.RowSpan="2" Grid.ColumnSpan="2" IsHitTestVisible="False">
                    <Ellipse.Fill>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FF07CB45" Offset="0"/>
                            <GradientStop Color="#FF07CB45" Offset="{StaticResource Height}"/>
                            <GradientStop Color="#FFFF3F00" Offset="{StaticResource Height}"/>
                        </LinearGradientBrush>
                    </Ellipse.Fill>
                </Ellipse>
                <Button Grid.Row="1" Grid.Column="0" Content="Button" VerticalAlignment="Top" Margin="0,10,0,0"/>
                <Image Grid.Row="1" Grid.Column="1" Source="Assets/Logo.png" VerticalAlignment="Top" Margin="0,10,0,0"/>
                <!-- This path is used to draw a clipping area, it uses  ApplicationPageBackgroundThemeBrush to mix with application background color-->
                <Path Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}" Grid.RowSpan="2" Stretch="Fill" StrokeThickness="1" UseLayoutRounding="False" Grid.ColumnSpan="2" Data="M200,100 L200,200 L100,200 C155.228,200 200,155.228 200,100 z M100,0 L200,0 L200,100 C200,45.6344 156.616,1.40166 102.581,0.032657 z M0,0 L99.9998,0 L97.419,0.032657 C43.3833,1.40166 2E-06,45.6344 3E-06,100 C2E-06,155.228 44.7715,200 100,200 L0,200 z" />
            </Grid>
        </Grid>
    </Page>


    In above XAML Height controls the shaded portion and placement of button & image. Here are the converters that  I have used

    using System;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Data;
    
    namespace MsdnSample04072014.Common
    {
        public class StarConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, string language)
            {
                GridLength length = new GridLength();
    
                double ratio;
    
                if (value != null && double.TryParse(value.ToString(), out ratio))
                {
                    length = new GridLength(ratio > 1 ? 1 : ratio, GridUnitType.Star);
                }
    
                return length;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, string language)
            {
                throw new NotImplementedException();
            }
        }
    
        public class StarInverseConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, string language)
            {
                GridLength length = new GridLength();
    
                double ratio;
    
                if (value != null && double.TryParse(value.ToString(), out ratio))
                {
                    length = new GridLength(ratio >= 1 ? 0 : (1 - ratio), GridUnitType.Star);
                }
    
                return length;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, string language)
            {
                throw new NotImplementedException();
            }
        }
    }

    And by the way if you are thinking how did I create the clipping path then here are the steps that I used in Blend For Visual Studio 2013:

    1) Define a grid with say height and width of 200.

    2) Inside that grid put an Ellipse with no height and width. Use Fill as Yellow

    3) Also put a Rectangle with no height and width in the same grid. Use Fill as Green

    4) Now in Object & Timeline window select ellipse and convert it to path from context menu. Path >> Convert to Path

    5) Similarly in Object & Timeline window select rectangle and convert it to path from context menu. Path >> Convert to Path

    6) Then again in Object & Timeline window first select Circle path and then press control key to select rectangle path. In context menu under combine select subtract. And you are done!


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!





    Sunday, July 06, 2014 2:17 PM

All replies

  • Hi g,

    there are different ways to achieve that. One way is to overlay two ellipse-objects - a green and a red one - and to use an opacity mask for one to display only a part of it.

    Here's a sample with a data binding that shows the effect you want. Just past the snippet into your windows store application:

      <StackPanel Margin="50">
                <Slider x:Name="sli" Maximum="300" Value="300" IsDirectionReversed="True"/>
    
                <Grid Width="300" Height="300">
                    <Ellipse Fill="Green"/>
                    <Ellipse Fill="Red">
                        <Ellipse.Clip>
                            <RectangleGeometry Rect="0 0 300 300">
                                <RectangleGeometry.Transform>
                                    <TranslateTransform Y="{Binding ElementName=sli,Path=Value}"/>
                                </RectangleGeometry.Transform>
                            </RectangleGeometry>
                        </Ellipse.Clip>
                    </Ellipse>
                </Grid>
            </StackPanel>

    Instead of manipulating the Y-Property of the TranslateTransform-object with a data binding, you could of course also manipulate it with an animation


    Thomas Claudius Huber

    "If you can't make your app run faster, make it at least look & feel extremly fast"

    My latest app: The "Womanizer" :-)
    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com
    author of: ultimate Windows Store Apps handbook | ultimate WPF handbook | ultimate Silverlight handbook


    Thursday, July 03, 2014 8:41 PM
  • + gradient brush

    One more solution from my side; Use gradient brush. See this.

    <Ellipse Height="100" Width="100">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF07CB45" Offset="0"/>
                        <GradientStop Color="#FF07CB45" Offset="0.442"/>
                        <GradientStop Color="#FFFF3F00" Offset="0.442"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <Ellipse Height="100" Width="100">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF07CB45" Offset="0"/>
                        <GradientStop Color="#FF07CB45" Offset="0.25"/>
                        <GradientStop Color="#FFFF3F00" Offset="0.25"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <Ellipse Height="100" Width="100">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                        <GradientStop Color="#FF07CB45" Offset="0"/>
                        <GradientStop Color="#FF07CB45" Offset="0.75"/>
                        <GradientStop Color="#FFFF3F00" Offset="0.75"/>
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
    Here the trick is that I have used two gradient stops to get two solid shades in ellipse. This will actually divide ellipse in 3 sections but visually it has only 2 sections.


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!

    Friday, July 04, 2014 7:35 AM
  • Ok thanks, it's working. I have two further questions:

    1) How can I manipulate the Y-Property of the TranslateTransform-object in a storyboard?

    2) I need to put some elements (a button and an image) inside the partially filled ellipse, how can i do this?

    Again thanks in advance for all the help ;)

    Friday, July 04, 2014 8:27 AM
  • Hey which approach are you taking?

    1) You can make use of Blend For Visual Studio to do what you need with Animation. Watch this Animation Using Expression Blend: How to create an animation. Since this video is for older version so there are few minor changes. But still you can follow similar steps.

    2) I am not sure how you want to put those elements, post some image to help you.


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!

    Friday, July 04, 2014 4:28 PM
  • Hi Vishal, yes I'm using blend. What I need to is this:

    I need to show dinamically (maybe with an animation) a partial fill region in the Ellipse which contains some UIElements such as a button or an image.

    How can i achieve such a thing?


    Sunday, July 06, 2014 9:32 AM
  • While I really did not understand why do you want to place items inside shaded red area while in most case they will not be clickable here is what you need

    <Page
        x:Class="MsdnSample04072014.BlankPage1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MsdnSample04072014"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:common="using:MsdnSample04072014.Common"
        mc:Ignorable="d">
        <Page.Resources>
            <common:StarConverter x:Key="StarConverter"/>
            <common:StarInverseConverter x:Key="StarInverseConverter"/>
            <x:Double x:Key="Height">0.55</x:Double>
        </Page.Resources>
        <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
            <Grid Height="200" Width="200">
                <Grid.RowDefinitions>
                    <RowDefinition Height="{Binding Converter={StaticResource StarConverter}, Mode=OneWay, Source={StaticResource Height}}"/>
                    <RowDefinition Height="{Binding Converter={StaticResource StarInverseConverter}, Mode=OneWay, Source={StaticResource Height}}"/>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition/>
                    <ColumnDefinition/>
                </Grid.ColumnDefinitions>
                <!-- This ellipse is used to show background shade -->
                <Ellipse Grid.RowSpan="2" Grid.ColumnSpan="2" IsHitTestVisible="False">
                    <Ellipse.Fill>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                            <GradientStop Color="#FF07CB45" Offset="0"/>
                            <GradientStop Color="#FF07CB45" Offset="{StaticResource Height}"/>
                            <GradientStop Color="#FFFF3F00" Offset="{StaticResource Height}"/>
                        </LinearGradientBrush>
                    </Ellipse.Fill>
                </Ellipse>
                <Button Grid.Row="1" Grid.Column="0" Content="Button" VerticalAlignment="Top" Margin="0,10,0,0"/>
                <Image Grid.Row="1" Grid.Column="1" Source="Assets/Logo.png" VerticalAlignment="Top" Margin="0,10,0,0"/>
                <!-- This path is used to draw a clipping area, it uses  ApplicationPageBackgroundThemeBrush to mix with application background color-->
                <Path Fill="{ThemeResource ApplicationPageBackgroundThemeBrush}" Grid.RowSpan="2" Stretch="Fill" StrokeThickness="1" UseLayoutRounding="False" Grid.ColumnSpan="2" Data="M200,100 L200,200 L100,200 C155.228,200 200,155.228 200,100 z M100,0 L200,0 L200,100 C200,45.6344 156.616,1.40166 102.581,0.032657 z M0,0 L99.9998,0 L97.419,0.032657 C43.3833,1.40166 2E-06,45.6344 3E-06,100 C2E-06,155.228 44.7715,200 100,200 L0,200 z" />
            </Grid>
        </Grid>
    </Page>


    In above XAML Height controls the shaded portion and placement of button & image. Here are the converters that  I have used

    using System;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Data;
    
    namespace MsdnSample04072014.Common
    {
        public class StarConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, string language)
            {
                GridLength length = new GridLength();
    
                double ratio;
    
                if (value != null && double.TryParse(value.ToString(), out ratio))
                {
                    length = new GridLength(ratio > 1 ? 1 : ratio, GridUnitType.Star);
                }
    
                return length;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, string language)
            {
                throw new NotImplementedException();
            }
        }
    
        public class StarInverseConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, string language)
            {
                GridLength length = new GridLength();
    
                double ratio;
    
                if (value != null && double.TryParse(value.ToString(), out ratio))
                {
                    length = new GridLength(ratio >= 1 ? 0 : (1 - ratio), GridUnitType.Star);
                }
    
                return length;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, string language)
            {
                throw new NotImplementedException();
            }
        }
    }

    And by the way if you are thinking how did I create the clipping path then here are the steps that I used in Blend For Visual Studio 2013:

    1) Define a grid with say height and width of 200.

    2) Inside that grid put an Ellipse with no height and width. Use Fill as Yellow

    3) Also put a Rectangle with no height and width in the same grid. Use Fill as Green

    4) Now in Object & Timeline window select ellipse and convert it to path from context menu. Path >> Convert to Path

    5) Similarly in Object & Timeline window select rectangle and convert it to path from context menu. Path >> Convert to Path

    6) Then again in Object & Timeline window first select Circle path and then press control key to select rectangle path. In context menu under combine select subtract. And you are done!


    -- Vishal Kaushik --

    Please 'Mark as Answer' if my post answers your question and 'Vote as Helpful' if it helps you. Happy Coding!!!





    Sunday, July 06, 2014 2:17 PM