i have a image and when ever i pinch to zoom it, i should be able to move the image with fingers(pan gesture) with the same level of zoomed.
i tried some mouseoverevents and im able to do separately pinch to zoom and pan gesture,but together am facing some issues in maui blazor application.please resolve it. i have tried the following code
using Xamarin.Forms;
namespace YourNamespace
{
public class ZoomPanContentView : ContentView
{
private double startScale = 1;
private double currentScale = 1;
private double xOffset = 0;
private double yOffset = 0;
public ZoomPanContentView()
{
var pinchGesture = new PinchGestureRecognizer();
pinchGesture.PinchUpdated += OnPinchUpdated;
GestureRecognizers.Add(pinchGesture);
var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += OnPanUpdated;
GestureRecognizers.Add(panGesture);
}
private void OnPinchUpdated(object sender, PinchGestureUpdatedEventArgs e)
{
if (e.Status == GestureStatus.Started)
{
startScale = Content.Scale;
Content.AnchorX = 0;
Content.AnchorY = 0;
}
else if (e.Status == GestureStatus.Running)
{
currentScale += (e.Scale - 1) * startScale;
currentScale = Math.Max(1, currentScale);
currentScale = Math.Min(currentScale, 5);
var renderedX = Content.X + xOffset;
var deltaX = renderedX / Width;
var deltaWidth = Width / (Content.Width * startScale);
var originX = (e.ScaleOrigin.X - deltaX) * deltaWidth;
var renderedY = Content.Y + yOffset;
var deltaY = renderedY / Height;
var deltaHeight = Height / (Content.Height * startScale);
var originY = (e.ScaleOrigin.Y - deltaY) * deltaHeight;
var targetX = xOffset - (originX * Content.Width) * (currentScale - startScale);
var targetY = yOffset - (originY * Content.Height) * (currentScale - startScale);
var transX = targetX.Clamp(-Content.Width * (currentScale - 1), 0);
var transY = targetY.Clamp(-Content.Height * (currentScale - 1), 0);
Content.Scale = currentScale;
Content.TranslateTo(transX, transY, 0);
}
}
private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
{
if (currentScale == 1)
return;
switch (e.StatusType)
{
case GestureStatus.Running:
var xTrans = xOffset + e.TotalX;
var yTrans = yOffset + e.TotalY;
Content.TranslateTo(xTrans, yTrans, 0);
break;
case GestureStatus.Completed:
xOffset = Content.TranslationX;
yOffset = Content.TranslationY;
var maxTransX = Math.Min(0, Content.Width * (currentScale - 1));
var maxTransY = Math.Min(0, Content.Height * (currentScale - 1));
xOffset = Math.Max(maxTransX, xOffset);
yOffset = Math.Max(maxTransY, yOffset);
var minTransX = Math.Max(Width - Content.Width * currentScale, 0);
var minTransY = Math.Max(Height - Content.Height * currentScale, 0);
xOffset = Math.Min(minTransX, xOffset);
yOffset = Math.Min(minTransY, yOffset);
Content.TranslateTo(xOffset, yOffset, 500, Easing.BounceOut);
break;
}
}
}
}
The issue what you are facing can be resolved using the JS Hammer library. Below is the snippet for pinch-to-zoom with pan gestures on an image.
Add the CDN
<script src="https://cdn.jsdelivr.net/npm/hammerjs"></script>
Add the JavaScript file:
function hammerIt(elm) {
var hammertime = new Hammer(elm, {});
hammertime.get('pinch').set({ enable: true });
var posX = 0,
posY = 0,
scale = 1,
last_scale = 1,
last_posX = 0,
last_posY = 0,
max_pos_x = 0,
max_pos_y = 0,
transform = "",
el = elm;
hammertime.on('doubletap pan pinch panend pinchend', function (ev) {
if (ev.type == "doubletap") {
transform = "translate3d(0, 0, 0) scale3d(2, 2, 1)";
scale = 2;
last_scale = 2;
if (window.getComputedStyle(el, null).getPropertyValue('-webkit-transform').toString() != "matrix(1, 0, 0, 1, 0, 0)") {
transform = "translate3d(0, 0, 0) scale3d(1, 1, 1)";
scale = 1;
last_scale = 1;
}
el.style.webkitTransform = transform;
transform = "";
}
// Pan
if (scale != 1) {
posX = last_posX + ev.deltaX;
posY = last_posY + ev.deltaY;
max_pos_x = Math.ceil((scale - 1) * el.clientWidth / 2);
max_pos_y = Math.ceil((scale - 1) * el.clientHeight / 2);
if (posX > max_pos_x) {
posX = max_pos_x;
}
if (posX < -max_pos_x) {
posX = -max_pos_x;
}
if (posY > max_pos_y) {
posY = max_pos_y;
}
if (posY < -max_pos_y) {
posY = -max_pos_y;
}
}
if (ev.type == "pinch") {
scale = Math.max(.999, Math.min(last_scale * ev.scale, 4));
}
if (ev.type == "pinchend") {
last_scale = scale;
}
// Panend
if (ev.type == "panend") {
last_posX = posX < max_pos_x ? posX : max_pos_x;
last_posY = posY < max_pos_y ? posY : max_pos_y;
}
if (scale != 1) {
transform = "translate3d(" + posX + "px, " + posY + "px, 0) scale3d(" + scale + ", " + scale + ", 1)";
}
if (transform) {
el.style.webkitTransform = transform;
}
});
}
And invoke it from your Razor page:
@inject IJSRuntime JS;
@page "/zoom-pan-pinch"
<h3>Zoom</h3>
<img id="myImage" @ref="imageRef" src="./Nature.jpg" alt="Image" />
@code {
private ElementReference imageRef;
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.InvokeVoidAsync("hammerIt", imageRef);
}
}
}
I have tested it and it worked fine for me. Please test and revert.