@using System.Text;
@*this div is used just for moving around when zoomed*@
@if (ShowResetButton) {
} @code { /// /// The path or url of the image /// [Parameter] public string ImageUrlPath { get; set; } /// /// The width of the image /// [Parameter] public int ImageWidthInPx { get; set; } /// /// The height of the image /// [Parameter] public int ImageHeightInPx { get; set; } /// /// Set to true to show the reset button /// [Parameter] public bool ShowResetButton { get; set; } /// /// Set the amount the image is scaled by, default is 0.1f /// [Parameter] public double DefaultScaleBy { get; set; } = 0.1f; /// /// The Maximum the image can scale to, default = 5f /// [Parameter] public double ScaleToMaximum { get; set; } = 5f; /// /// Set the speed at which the image is moved by, default 2. /// 2 or 3 seems to work best. /// [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 _ImageContainerStyles; Dictionary ImageContainerStyles { get { if (_ImageContainerStyles == null) { _ImageContainerStyles = new Dictionary(); _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 _MovingContainerStyles; Dictionary 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(); _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 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 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 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(); } } /// /// Refresh the values in the moving style dictionary that is used to position the image. /// 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}%"; } }); } }