Skip to content

Commit

Permalink
handle pinch and zoom
Browse files Browse the repository at this point in the history
  • Loading branch information
theKashey committed Oct 17, 2019
1 parent 810676b commit 6d39ac9
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 21 deletions.
62 changes: 41 additions & 21 deletions src/SideEffect.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import * as React from 'react';
import { TouchEvent } from 'react';
import { RemoveScrollBar } from 'react-remove-scroll-bar';
import { styleSingleton } from 'react-style-singleton';
import { handleScroll, locationCouldBeScrolled } from './handleScroll';
import { nonPassive } from './aggresiveCapture';
import { Axis, IRemoveScrollEffectProps } from './types';
import {TouchEvent, useRef} from 'react';
import {RemoveScrollBar} from 'react-remove-scroll-bar';
import {styleSingleton} from 'react-style-singleton';
import {handleScroll, locationCouldBeScrolled} from './handleScroll';
import {nonPassive} from './aggresiveCapture';
import {Axis, IRemoveScrollEffectProps} from './types';
import {pinchOrZoom} from "./pinchAndZoom";

export const getTouchXY = (event: TouchEvent) =>
event.changedTouches
Expand All @@ -28,9 +29,7 @@ let idCounter = 0;
let lockStack: any[] = [];

export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {
const shouldPreventQueue = React.useRef<
Array<{ name: string; delta: number[]; target: any; should: boolean }>
>([]);
const shouldPreventQueue = React.useRef<Array<{ name: string; delta: number[]; target: any; should: boolean }>>([]);
const touchStartRef = React.useRef([0, 0]);
const activeAxis = React.useRef<Axis | undefined>();
const [id] = React.useState(idCounter++);
Expand Down Expand Up @@ -67,14 +66,28 @@ export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {
[props.inert, props.lockRef.current, props.shards]
);

const touchCache = useRef({});

const shouldCancelEvent = React.useCallback(
(event: any, parent: HTMLElement) => {
const touch = getTouchXY(event);
const touchHandler = pinchOrZoom(event, touchCache.current);
if (touchHandler){
if(touchHandler.action === 'zoom') {
console.log('allow zoom');
return false;
}
if(touchHandler.action === 'pinch') {
console.log('disallow pinch');
return true;
}
}

console.log(touchHandler);

const touch = touchHandler && touchHandler.coords;
const touchStart = touchStartRef.current;
const deltaX =
'deltaX' in event ? event.deltaX : touchStart[0] - touch[0];
const deltaY =
'deltaY' in event ? event.deltaY : touchStart[1] - touch[1];
const deltaX = touch ? touchStart[0] - touch[0] : event.deltaX;
const deltaY = touch ? touchStart[1] - touch[1] : event.deltaY;

let currentAxis: Axis | undefined;
let target: HTMLElement = event.target as any;
Expand Down Expand Up @@ -127,7 +140,9 @@ export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {
[]
);

const shouldPrevent = React.useCallback((event: any) => {
const shouldPrevent = React.useCallback((_event: Event) => {
const event: WheelEvent | TouchEvent = _event as any;

if (!lockStack.length || lockStack[lockStack.length - 1] !== Style) {
// not the last active
return;
Expand All @@ -149,7 +164,7 @@ export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {
const shardNodes = (lastProps.current.shards || [])
.map(extractRef)
.filter(Boolean)
.filter(node => node.contains(event.target));
.filter(node => node.contains(event.target as any));

const shouldStop =
shardNodes.length > 0
Expand All @@ -164,7 +179,7 @@ export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {

const shouldCancel = React.useCallback(
(name: string, delta: number[], target: any, should: boolean) => {
const event = { name, delta, target, should };
const event = {name, delta, target, should};
shouldPreventQueue.current.push(event);
setTimeout(() => {
shouldPreventQueue.current = shouldPreventQueue.current.filter(
Expand All @@ -178,6 +193,7 @@ export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {
const scrollTouchStart = React.useCallback((event: any) => {
touchStartRef.current = getTouchXY(event);
activeAxis.current = undefined;
touchCache.current = {};
}, []);

const scrollWheel = React.useCallback((event: WheelEvent) => {
Expand Down Expand Up @@ -216,7 +232,11 @@ export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {
return () => {
lockStack = lockStack.filter(inst => inst !== Style);

document.removeEventListener('wheel', shouldPrevent, nonPassive as any);
document.removeEventListener(
'wheel',
shouldPrevent,
nonPassive as any
);
document.removeEventListener(
'touchmove',
shouldPrevent,
Expand All @@ -230,12 +250,12 @@ export function RemoveScrollSideCar(props: IRemoveScrollEffectProps) {
};
}, []);

const { removeScrollBar, inert } = props;
const {removeScrollBar, inert} = props;

return (
<React.Fragment>
{inert ? <Style styles={generateStyle(id)} /> : null}
{removeScrollBar ? <RemoveScrollBar gapMode="margin" /> : null}
{inert ? <Style styles={generateStyle(id)}/> : null}
{removeScrollBar ? <RemoveScrollBar gapMode="margin"/> : null}
</React.Fragment>
);
}
64 changes: 64 additions & 0 deletions src/pinchAndZoom.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {Touch} from "react";

const ds = (ab: number[]) => (
(ab[0] <= 0 && ab[1] >= 0) || (ab[0] >= 0 && ab[1] <= 0)
);

const sign = (x: number) => x < 0 ? -1 : 1;

export const pinchOrZoom = (event: TouchEvent, cache: Record<number, Touch>) => {
if (!event.changedTouches) {
return false;
}

if (event.touches.length === 2) {
const oldPoints: Touch[] = [
cache[event.touches[0].identifier],
cache[event.touches[1].identifier]
];
const newPoints: Touch[] = [
event.touches[0],
event.touches[1],
];
if (oldPoints[0] && oldPoints[1]) {
// Calculate the difference between the start and move coordinates
const diffx = [
oldPoints[0].clientX - newPoints[0].clientX,
oldPoints[1].clientX - newPoints[1].clientX,
];
const diffy = [
oldPoints[0].clientY - newPoints[0].clientY,
oldPoints[1].clientY - newPoints[1].clientY,
];

console.log(diffx, diffy);

if (ds(diffx) || ds(diffy)) {
return {
action: 'zoom'
}
}

const mx = Math.max(Math.abs(diffx[0]), Math.abs(diffx[1]));
const my = Math.max(Math.abs(diffy[0]), Math.abs(diffy[1]));

return {
action: 'pinch',
coords: [
mx * sign(diffx[0]),
my * sign(diffx[1]),
]
}
}
}

Array.from(event.changedTouches).forEach(touch => cache[touch.identifier] = touch);

return {
action: 'move',
coords: [
event.changedTouches[0].clientX,
event.changedTouches[0].clientY,
],
};
};

0 comments on commit 6d39ac9

Please sign in to comment.