繁体   English   中英

如何在 Blazor 中使用鼠标滚轮放大和缩小图像?

[英]How to make image zoom in & out with mouse wheel in Blazor?

我想在 asp.net 上的 blazor 中放大和缩小图像。

当我用于谷歌地图时,我想通过用鼠标滚轮缩放和拖动图像来移动图像位置。(我想使用图像文件,而不是谷歌地图。)

使用示例

有没有办法在 blazor 中放大、缩小和拖动特定图像?

笔记:

此组件可让您通过按放大shiftmouse wheel向上(缩小)或mouse wheel向下(放大)并通过按下移动图像mouse button 1向下移动时。 它比拖动更平移

Blazor 中的限制:(在撰写本文时

  • 目前最大的问题是没有获得鼠标OffsetXOffsetY作为HTML元素中这里描述也在这里,所以图像的运动必须只使用CSS来实现。
  • 我使用Shift进行滚动的原因是因为即使使用@onscroll:stopPropagation@onwheel:stopPropagation@onmousewheel:stopPropagation和/或@onscroll:preventDefault@onwheel:preventDefault@onmousewheel:preventDefault ,也不会像这里描述的那样阻止或禁用滚动@onmousewheel:preventDefault在父mainImageContainer元素上设置。 如果内容比可见页面宽,屏幕仍会左右滚动。

解决方案:

缩放部分非常简单,您需要做的就是设置transform:scale(n); @onmousewheel事件中的属性。

图像的移动有点复杂,因为没有参考鼠标指针相对于图像或元素边界的位置。 ( OffsetXOffsetY )

我们唯一可以确定的是是否按下了鼠标按钮,然后计算鼠标leftrightupdown移动的方向。

然后的想法是通过将topleft CSS 值设置为百分比来移动元素与图像的位置。

此组件代码:

@using System.Text;

<div id="mainImageContainer" style="display: block;width:@($"{ImageWidthInPx}px");height:@($"{ImageHeightInPx}px");overflow: hidden;">
    <div id="imageMover"
         @onmousewheel="MouseWheelZooming"
         style="@MoveImageStyle">
        <div id="imageContainer"
             @onmousemove="MouseMoving"
             style="@ZoomImageStyle">
            @*this div is used just for moving around when zoomed*@
        </div>
    </div>
</div>
@if (ShowResetButton)
{
    <div style="display:block">
        <button @onclick="ResetImgage">Reset</button>
    </div>
}

@code{

    /// <summary>
    /// The path or url of the image
    /// </summary>
    [Parameter]
    public string ImageUrlPath { get; set; }

    /// <summary>
    /// The width of the image
    /// </summary>
    [Parameter]
    public int ImageWidthInPx { get; set; }

    /// <summary>
    /// The height of the image
    /// </summary>
    [Parameter]
    public int ImageHeightInPx { get; set; }

    /// <summary>
    /// Set to true to show the reset button
    /// </summary>
    [Parameter]
    public bool ShowResetButton { get; set; }

    /// <summary>
    /// Set the amount the image is scaled by, default is 0.1f
    /// </summary>
    [Parameter]
    public double DefaultScaleBy { get; set; } = 0.1f;

    /// <summary>
    /// The Maximum the image can scale to, default = 5f
    /// </summary>
    [Parameter]
    public double ScaleToMaximum { get; set; } = 5f;

    /// <summary>
    /// Set the speed at which the image is moved by, default 2.
    /// 2 or 3 seems to work best.
    /// </summary>
    [Parameter]
    public double DefaultMoveBy { get; set; } = 2;

    //defaults
    double _CurrentScale = 1.0f;
    double _PositionLeft = 0;
    double _PositionTop = 0;
    double _OldClientX = 0;
    double _OldClientY = 0;
    double _DefaultMinPosition = 0;//to the top and left
    double _DefaultMaxPosition = 0;//to the right and down

    //the default settings used to display the image in the child div
    private Dictionary<string, string> _ImageContainerStyles;
    Dictionary<string, string> ImageContainerStyles
    {
        get
        {
            if (_ImageContainerStyles == null)
            {
                _ImageContainerStyles = new Dictionary<string, string>();
                _ImageContainerStyles.Add("width", "100%");
                _ImageContainerStyles.Add("height", "100%");
                _ImageContainerStyles.Add("position", "relative");
                _ImageContainerStyles.Add("background-size", "contain");
                _ImageContainerStyles.Add("background-repeat", "no-repeat");
                _ImageContainerStyles.Add("background-position", "50% 50%");
                _ImageContainerStyles.Add("background-image", $"URL({ImageUrlPath})");
            }
            return _ImageContainerStyles;
        }
    }

    private Dictionary<string, string> _MovingContainerStyles;
    Dictionary<string, string> MovingContainerStyles
    {
        get
        {
            if (_MovingContainerStyles == null)
            {
                InvokeAsync(ResetImgage);
            }
            return _MovingContainerStyles;
        }
    }

    protected async Task ResetImgage()
    {
        _PositionLeft = 0;
        _PositionTop = 0;
        _DefaultMinPosition = 0;
        _DefaultMaxPosition = 0;
        _CurrentScale = 1.0f;

        _MovingContainerStyles = new Dictionary<string, string>();
        _MovingContainerStyles.Add("width", "100%");
        _MovingContainerStyles.Add("height", "100%");
        _MovingContainerStyles.Add("position", "relative");
        _MovingContainerStyles.Add("left", $"{_PositionLeft}%");
        _MovingContainerStyles.TryAdd("top", $"{_PositionTop}%");
    
        await InvokeAsync(StateHasChanged);
    }

    string ZoomImageStyle { get => DictionaryToCss(ImageContainerStyles); }
    string MoveImageStyle { get => DictionaryToCss(MovingContainerStyles); }


    private string DictionaryToCss(Dictionary<string, string> styleDictionary)
    {
        StringBuilder sb = new StringBuilder();
        foreach (var kvp in styleDictionary.AsEnumerable())
        {
            sb.AppendFormat("{0}:{1};", kvp.Key, kvp.Value);
        }
        return sb.ToString();
    }


    protected async void MouseMoving(MouseEventArgs e)
    {
        //if the mouse button 1 is not down exit the function
        if (e.Buttons != 1)
        {
            _OldClientX = e.ClientX;
            _OldClientY = e.ClientY;
            return;
        }

        //get the % of the current scale to move by at least the default move speed plus any scaled changes
        //basically the bigger the image the faster it moves..
        double scaleFrac = (_CurrentScale / ScaleToMaximum);
        double scaleMove = (DefaultMoveBy * (DefaultMoveBy * scaleFrac));

        //moving mouse right
        if (_OldClientX < e.ClientX)
        {
            if ((_PositionLeft - DefaultMoveBy) <= _DefaultMaxPosition)
            {
                _PositionLeft += scaleMove;
            }
        }

        //moving mouse left
        if (_OldClientX > e.ClientX)
        {
            //if (_DefaultMinPosition < (_PositionLeft - DefaultMoveBy))
            if ((_PositionLeft + DefaultMoveBy) >= _DefaultMinPosition)
            {
                _PositionLeft -= scaleMove;
            }
        }

        //moving mouse down
        if (_OldClientY < e.ClientY)
        {
            //if ((_PositionTop + DefaultMoveBy) <= _DefaultMaxPosition)
            if ((_PositionTop - DefaultMoveBy) <= _DefaultMaxPosition)
            {
                _PositionTop += scaleMove;
            }
        }

        //moving mouse up
        if (_OldClientY > e.ClientY)
        {
            //if ((_PositionTop - DefaultMoveBy) > _DefaultMinPosition)
            if ((_PositionTop + DefaultMoveBy) >= _DefaultMinPosition)
            {
                _PositionTop -= scaleMove;
            }
        }

        _OldClientX = e.ClientX;
        _OldClientY = e.ClientY;

        await UpdateScaleAndPosition();
    }

    async Task<double> IncreaseScale()
    {
        return await Task.Run(() =>
        {
            //increase the scale first then calculate the max and min positions
            _CurrentScale += DefaultScaleBy;
            double scaleFrac = (_CurrentScale / ScaleToMaximum);
            double scaleDiff = (DefaultMoveBy + (DefaultMoveBy * scaleFrac));
            double scaleChange = DefaultMoveBy + scaleDiff;
            _DefaultMaxPosition += scaleChange;
            _DefaultMinPosition -= scaleChange;

            return _CurrentScale;
        });
    }

    async Task<double> DecreaseScale()
    {
        return await Task.Run(() =>
        {
            _CurrentScale -= DefaultScaleBy;
           
            double scaleFrac = (_CurrentScale / ScaleToMaximum);
            double scaleDiff = (DefaultMoveBy + (DefaultMoveBy * scaleFrac));
            double scaleChange = DefaultMoveBy + scaleDiff;
            _DefaultMaxPosition -= scaleChange;
            _DefaultMinPosition += scaleChange;//DefaultMoveBy;

            //fix descaling, move the image back into view when descaling (zoomin out)
            if (_CurrentScale <= 1)
            {
                _PositionLeft = 0;
                _PositionTop = 0;
            }
            else
            {
                //left can not be more than max position
                _PositionLeft = (_DefaultMaxPosition < _PositionLeft) ? _DefaultMaxPosition : _PositionLeft;

                //top can not be more than max position
                _PositionTop = (_DefaultMaxPosition < _PositionTop) ? _DefaultMaxPosition : _PositionTop;

                //left can not be less than min position
                _PositionLeft = (_DefaultMinPosition > _PositionLeft) ? _DefaultMinPosition : _PositionLeft;

                //top can not be less than min position
                _PositionTop = (_DefaultMinPosition > _PositionTop) ? _DefaultMinPosition : _PositionTop;
            }
            return _CurrentScale;
        });
    }

    protected async void MouseWheelZooming(WheelEventArgs e)
    {
        //holding shift stops the page from scrolling
        if (e.ShiftKey == true)
        {
            if (e.DeltaY > 0)
            {
                _CurrentScale = ((_CurrentScale + DefaultScaleBy) >= 5) ? _CurrentScale = 5f : await IncreaseScale();
            }
            if (e.DeltaY < 0)
            {
                _CurrentScale = ((_CurrentScale - DefaultScaleBy) <= 0) ? _CurrentScale = DefaultScaleBy : await DecreaseScale();
            }

            await UpdateScaleAndPosition();
        }
    }

    /// <summary>
    /// Refresh the values in the moving style dictionary that is used to position the image.
    /// </summary>    
    async Task UpdateScaleAndPosition()
    {
        await Task.Run(() =>
        {
            if (!MovingContainerStyles.TryAdd("transform", $"scale({_CurrentScale})"))
            {
                MovingContainerStyles["transform"] = $"scale({_CurrentScale})";
            }

            if (!MovingContainerStyles.TryAdd("left", $"{_PositionLeft}%"))
            {
                MovingContainerStyles["left"] = $"{_PositionLeft}%";
            }

            if (!MovingContainerStyles.TryAdd("top", $"{_PositionTop}%"))
            {
                MovingContainerStyles["top"] = $"{_PositionTop}%";
            }
        });
    }

}

这是用法:

@page "/"
@using BlazorWasmApp.Components
Welcome to your new app.

<ZoomableImageComponent ImageUrlPath="images/Capricorn.png"
                        ImageWidthInPx=400
                        ImageHeightInPx=300
                        ShowResetButton=true
                        DefaultScaleBy=0.1f />

这是结果:

在此处输入图片说明

我只在没有触摸输入的台式电脑上用 chrome 测试过这个。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM