michasaucer
michasaucer

Reputation: 5228

Enlarge part of image where mouse pointing

I have a grid with image label that looks like this:

<Grid Height="180" Width="180" Grid.Column="2">
        <Image Height="180" Width="180" Source="{Binding Result}">
            <Image.LayoutTransform>
                <ScaleTransform x:Name="st2" CenterX="90" CenterY="90" ScaleX="1" ScaleY="1" />
            </Image.LayoutTransform>
            <Image.Triggers>
                <EventTrigger RoutedEvent="Image.MouseEnter">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetName="st2"
                                         Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
                                         To="3.0" Duration="0:0:0" />
                                <DoubleAnimation Storyboard.TargetName="st2"
                                         Storyboard.TargetProperty="(ScaleTransform.ScaleY)"
                                         To="3.0" Duration="0:0:0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
                <EventTrigger RoutedEvent="Image.MouseLeave">
                    <EventTrigger.Actions>
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Storyboard.TargetName="st2"
                                         Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
                                         To="1.0" Duration="0:0:0" />
                                <DoubleAnimation Storyboard.TargetName="st2"
                                         Storyboard.TargetProperty="(ScaleTransform.ScaleY)"
                                         To="1.0" Duration="0:0:0" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger.Actions>
                </EventTrigger>
            </Image.Triggers>
        </Image>
    </Grid>

I presented how it works on this picture:

enter image description here

Anywhere i point my mouse on KMM image, it will enlarge the same part of the image. For example, when i point my mouse bottom of the image, it still enlarge the same, top left part of this image (as i show below):

enter image description here

How to edit my code to enlarge my image anywhere where my mouse point? I can use code behind of my xaml file (xaml.cs). I only want it to work

Upvotes: 0

Views: 68

Answers (1)

dymanoid
dymanoid

Reputation: 15197

While using built-in scaling transform makes the scaling of the target image easier, the mouse position tracking isn't that easy.

I would suggest you to use a viewbox of an ImageBrush to display your zoomed image. You can set the view box of the ImageBrush to show the needed portion of your image.

To make the code reusable, create an attached property. For example, like this one:

public static class ViewBoxTracking
{
    // Source is an UIElement that will provide the mouse input
    // for calculating of the view box bounds.
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.RegisterAttached("Source", typeof(UIElement), typeof(ViewBoxTracking), new PropertyMetadata(null, SourceChanged));

    public static void SetSource(TileBrush brush, UIElement value) => brush.SetValue(SourceProperty, value);

    public static UIElement GetSource(TileBrush brush) => (UIElement)brush.GetValue(SourceProperty);

    private const int ZoomFactor = 3;

    private static void SourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs ea)
    {
        if (ea.NewValue is UIElement source && d is ImageBrush target)
        {
            // When the mouse cursor exits the source element,
            // reset the view box to the 100% zoom;
            // you can remove or change this logic.
            source.MouseLeave += (s, e) => target.Viewbox = new Rect(0, 0, 1, 1);

            // When the mouse hovers over the source object, update the view box.
            source.MouseMove += (s, e) => SourceMouseMove(target, e.GetPosition(source), source.RenderSize);
        }
    }

    private static void SourceMouseMove(ImageBrush target, Point currentPoint, Size sourceSize)
    {
        // The view box width is based on the zoom factor
        double viewBoxWidth = sourceSize.Width / ZoomFactor;
        double viewBoxHeight = sourceSize.Height / ZoomFactor;

        // Calculate the bounds for the view box - at first, in absolute coordinates.
        double x = Math.Max(0, currentPoint.X - viewBoxWidth / 2);
        double y = Math.Max(0, currentPoint.Y - viewBoxHeight / 2);
        if (x + viewBoxWidth > sourceSize.Width)
        {
            x = sourceSize.Width - viewBoxWidth;
        }

        if (y + viewBoxHeight > sourceSize.Height)
        {
            y = sourceSize.Height - viewBoxHeight;
        }

        // Now, make the coordinates relative.
        x /= sourceSize.Width;
        y /= sourceSize.Height;

        // Set the new view box to the target image brush.
        target.Viewbox = new Rect(x, y, 1d / ZoomFactor, 1d / ZoomFactor);
    }
}

And here is an example how to use the new attached property in XAML:

<UniformGrid Columns="2">
    <Grid Height="180" Width="180">
        <Grid.Background>
            <ImageBrush ImageSource="{Binding YourImage}" ViewboxUnits="RelativeToBoundingBox" 
                        local:ViewBoxTracking.Source="{Binding ElementName=MainImage}" />
        </Grid.Background>
    </Grid>

    <Image x:Name="MainImage" Height="180" Width="180" Source="{Binding YourImage}" />

</UniformGrid>

local is the XAML namespace representing your namespace where you place the attached property, something like xmlns:local="clr-namespace:YourNamespace".

Upvotes: 1

Related Questions