Enable dragging while pinching (#59)

This commit is contained in:
Manuel Heidrich 2025-06-04 09:10:51 +02:00 committed by GitHub
parent 1ec35a96d5
commit c10b01034a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 77 additions and 25 deletions

View file

@ -62,6 +62,7 @@ For use, put your image inside the <pinch-zoom> container. Please, pay att
| wheelZoomFactor | number | 0.2 | Zoom factor when zoomed in with the mouse wheel. |
| autoHeight | boolean | false | Calculate the height of the container based on the `width` and `height` attributes of the image. By default, the width of the container is 100%, and the height is determined after the image information is loaded - this may cause a delay in determining the height of the container. If you want the container to initially have dimensions corresponding to the dimensions of the image, then specify the attributes `width` and `height` for the `<img>` tag. When setting the property value to `true`, a subscription to the window resize listener will be created. |
| draggableImage | boolean | false | Sets the attribute `draggable` to the `<img>` tag. |
| draggableOnPinch | boolean | false | When set to `true` content can be moved around while touching or pinching with two fingers. |
## Methods

View file

@ -19,4 +19,5 @@ export interface Properties {
autoHeight?: boolean;
wheelZoomFactor?: number;
draggableImage?: boolean;
draggableOnPinch?: boolean;
}

View file

@ -24,6 +24,8 @@ export class IvyPinch {
private initialDistance: number = 0;
public maxScale!: number;
private defaultMaxScale: number = 3;
private initialPinchCenterX = 0;
private initialPinchCenterY = 0;
// Minimum scale at which panning works
get minPanScale(): number {
@ -189,36 +191,82 @@ export class IvyPinch {
private handlePinch = (event: TouchEvent): void => {
event.preventDefault();
if (this.eventType === undefined || this.eventType === 'pinch') {
const touches = event.touches;
if (!this.properties.draggableOnPinch) {
if (this.eventType === undefined || this.eventType === 'pinch') {
const touches = event.touches;
if (!this.eventType) {
this.initialDistance = this.getDistance(touches);
if (!this.eventType) {
this.initialDistance = this.getDistance(touches);
const moveLeft0 = this.moveLeft(event, 0);
const moveLeft1 = this.moveLeft(event, 1);
const moveTop0 = this.moveTop(event, 0);
const moveTop1 = this.moveTop(event, 1);
const moveLeft0 = this.moveLeft(event, 0);
const moveLeft1 = this.moveLeft(event, 1);
const moveTop0 = this.moveTop(event, 0);
const moveTop1 = this.moveTop(event, 1);
this.moveXC = (moveLeft0 + moveLeft1) / 2 - this.initialMoveX;
this.moveYC = (moveTop0 + moveTop1) / 2 - this.initialMoveY;
this.moveXC = (moveLeft0 + moveLeft1) / 2 - this.initialMoveX;
this.moveYC = (moveTop0 + moveTop1) / 2 - this.initialMoveY;
}
this.eventType = 'pinch';
this.distance = this.getDistance(touches);
this.scale = this.initialScale * (this.distance / this.initialDistance);
this.moveX = this.initialMoveX - ((this.distance / this.initialDistance) * this.moveXC - this.moveXC);
this.moveY = this.initialMoveY - ((this.distance / this.initialDistance) * this.moveYC - this.moveYC);
this.handleLimitZoom();
if (this.properties.limitPan) {
this.limitPanY();
this.limitPanX();
}
this.transformElement(0);
}
this.eventType = 'pinch';
this.distance = this.getDistance(touches);
this.scale = this.initialScale * (this.distance / this.initialDistance);
this.moveX = this.initialMoveX - ((this.distance / this.initialDistance) * this.moveXC - this.moveXC);
this.moveY = this.initialMoveY - ((this.distance / this.initialDistance) * this.moveYC - this.moveYC);
this.handleLimitZoom();
if (this.properties.limitPan) {
this.limitPanY();
this.limitPanX();
}
this.transformElement(0);
return;
}
const touches = event.touches;
if (!this.eventType) {
this.eventType = 'pinch';
this.initialDistance = this.getDistance(touches);
const lx0 = this.moveLeft(event, 0),
lx1 = this.moveLeft(event, 1),
ty0 = this.moveTop(event, 0),
ty1 = this.moveTop(event, 1);
this.initialPinchCenterX = (lx0 + lx1) / 2;
this.initialPinchCenterY = (ty0 + ty1) / 2;
this.moveXC = this.initialPinchCenterX - this.initialMoveX;
this.moveYC = this.initialPinchCenterY - this.initialMoveY;
}
this.eventType = 'pinch';
this.distance = this.getDistance(touches);
const scaleRatio = this.distance / this.initialDistance;
this.scale = this.initialScale * scaleRatio;
const curLX0 = this.moveLeft(event, 0),
curLX1 = this.moveLeft(event, 1),
curTY0 = this.moveTop(event, 0),
curTY1 = this.moveTop(event, 1);
const currentCenterX = (curLX0 + curLX1) / 2;
const currentCenterY = (curTY0 + curTY1) / 2;
const deltaX = currentCenterX - this.initialPinchCenterX;
const deltaY = currentCenterY - this.initialPinchCenterY;
const scaleTransX = (scaleRatio - 1) * this.moveXC;
const scaleTransY = (scaleRatio - 1) * this.moveYC;
this.moveX = this.initialMoveX + deltaX - scaleTransX;
this.moveY = this.initialMoveY + deltaY - scaleTransY;
this.handleLimitZoom();
if (this.properties.limitPan) {
this.limitPanY();
this.limitPanX();
}
this.transformElement(0);
};
private handleWheel = (event: WheelEvent): void => {

View file

@ -3,7 +3,7 @@ import { Component, ElementRef, HostBinding, Input, OnChanges, OnDestroy, OnInit
import { Properties } from './interfaces';
import { defaultProperties, backwardCompatibilityProperties } from './properties';
import { IvyPinch } from './ivypinch';
import {CommonModule} from "@angular/common";
import { CommonModule } from "@angular/common";
interface ComponentProperties extends Properties {
disabled?: boolean;
@ -145,6 +145,7 @@ export class PinchZoomComponent implements OnInit, OnDestroy, OnChanges {
@Input() autoHeight!: boolean;
@Input() wheelZoomFactor!: number;
@Input() draggableImage!: boolean;
@Input() draggableOnPinch!: boolean;
@HostBinding('style.overflow')
get hostOverflow(): 'hidden' | 'visible' {

View file

@ -13,6 +13,7 @@ export const defaultProperties: Properties = {
wheel: true,
wheelZoomFactor: 0.2,
draggableImage: false,
draggableOnPinch: false,
};
export const backwardCompatibilityProperties = {