Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Animate circle's fill using sine-wave

Tags:

c#

animation

wpf

I'm trying to make a circle animate it's fill using a sinewave. Here's an example image I made:

Example image.

So the black is the circle, and as you can see it's cut off in a sine-wave-like way. Can you do this while the sine-wave is "traveling" in a horizontal direction and deciding where the wave should be placed by an Y value of the circles full height? (to make it look like there's water in the circle creating waves on top and being able to decide how much "water" is in the circle)

Are there a way to do this? Maybe there's some place to read up on these kinds of animations at?

One thing to note is that the grey background represents transparency so the "cut off" part of the circle should be transparent.

like image 744
Tokfrans Avatar asked Feb 26 '14 14:02

Tokfrans


1 Answers

The main feature to do something like this is an OpacityMask. The example below uses a VisualBrush set to Tile for the mask and uses the transform property of the brush to do the motion you described.

<Window
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="WpfApplication1.MainWindow"
        Title="MainWindow" Height="447" Width="569">
    <Window.Resources>
        <Storyboard x:Key="Wave">
            <DoubleAnimation Storyboard.TargetProperty="(UIElement.OpacityMask).(Brush.RelativeTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="ellipse" RepeatBehavior="Forever" From="0" To="1" Duration="0:0:1" />
        </Storyboard>
    </Window.Resources>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource Wave}"/>
        </EventTrigger>
    </Window.Triggers>
    <Canvas>
        <Ellipse x:Name="ellipse" Fill="#FF82C6FF" Height="160" Canvas.Left="320" Canvas.Top="80" Width="160">
            <Ellipse.OpacityMask>
                <VisualBrush Visual="{Binding ElementName=wave}" TileMode="Tile" Viewport="0,-1,1,3" Stretch="None"  >
                    <VisualBrush.RelativeTransform>
                        <TransformGroup>
                            <ScaleTransform />
                            <SkewTransform/>
                            <RotateTransform/>
                            <TranslateTransform Y="{Binding Value,ElementName=y}"  />
                        </TransformGroup>
                    </VisualBrush.RelativeTransform>
                </VisualBrush>
            </Ellipse.OpacityMask>

            </Ellipse>
        <Grid x:Name="wave" Height="377" Canvas.Left="80" Canvas.Top="23" Width="160" Background="#00000000">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="{Binding Value,ElementName=amplitude}"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <Path Fill="#FF82C6FF" Data="M12.5,1.6925709 C31.25,1.6925709 31.25,18.615654 50,18.615654 68.75,18.615654 68.75,1.6925709 87.5,1.6925709 87.499909,27.077196 87.5,27.077107 87.5,27.077107 63.28125,27.077136 12.5,27.077196 12.5,27.077196 12.5,27.077196 12.500094,27.077196 12.5,1.6925709 z" Stretch="Fill" Grid.Row="1"/>
            <Rectangle Fill="#FF82C6FF" Grid.Row="2" Margin="0,-1,0,0" />
        </Grid>
        <Slider x:Name="y" Width="200" Minimum="-0.6" Maximum="1" Value="0"/>
        <Slider x:Name="amplitude" Width="200" Minimum="1" Maximum="100" Value="20" Canvas.Top="23"/>
    </Canvas>
</Window>

To hide the mask you could place it directly inside VisualBrush instead of a binding like above. You may also want to look at other types of brushes and their transforms and viewport/viewbox.

Update: The mask is now in two pieces so the wave amplitude can be adjusted separately. You can also adjust ScaleTransform.ScaleX to alter the frequency but you would need to make sure you get the whole wave or the animation stutters, e.g try 0.5,0.25,0.1

like image 90
Kris Avatar answered Oct 22 '22 20:10

Kris