Skip to content

Commit

Permalink
Added new util handler ZoomToElement, docs for handlers and many fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
Maciej Pyrc committed Jun 26, 2021
1 parent 992cf22 commit e547f53
Show file tree
Hide file tree
Showing 18 changed files with 479 additions and 182 deletions.
21 changes: 12 additions & 9 deletions .storybook/theme-overrides.css
Expand Up @@ -9,6 +9,10 @@ body {
-moz-osx-font-smoothing: grayscale;
}

body .sbdocs {
max-width: unset;
}

.react-transform-wrapper {
background-color: rgba(0, 0, 0, 0.3);
}
Expand All @@ -26,15 +30,6 @@ body td > pre.prism-code {
text-align: left;
}

.props-table td:nth-child(2),
.props-table td:nth-child(3) {
max-width: 200px;
}

.props-table td:nth-child(4) {
min-width: 250px;
}

.is-object-row td {
background: #d8e2f5;
border-top: 2px solid rgb(173 173 173) !important;
Expand All @@ -44,3 +39,11 @@ body td > pre.prism-code {
max-width: 80vw;
max-height: 80vh;
}

.handlers-table {
width: 100%;
}

.handlers-table th {
text-align: left;
}
25 changes: 1 addition & 24 deletions README.md
Expand Up @@ -20,7 +20,7 @@
- :gem: Mobile gestures, touchpad gestures and desktop mouse events support
- :gift: Powerful context usage, which gives you a lot of freedom
- :wrench: Highly customizable
- :crown: Animations and many options
- :crown: Animations and Utils to create own tools

## Install

Expand Down Expand Up @@ -91,26 +91,3 @@ class Example extends Component {
## License

MIT © [prc5](https://github.com/prc5)

## Contributors ✨

Thanks goes to these wonderful people
([emoji key](https://allcontributors.org/docs/en/emoji-key)):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
<!-- prettier-ignore-start -->
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="http://maciejpyrc.pl"><img src="https://avatars3.githubusercontent.com/u/20928302?v=4" width="80px;" alt=""/><br /><sub><b>Maciej Pyrc</b></sub></a><br /><a href="https://github.com/prc5/react-zoom-pan-pinch/pulls?q=is%3Apr+reviewed-by%3Aprc5" title="Reviewed Pull Requests">👀</a> <a href="https://github.com/prc5/react-zoom-pan-pinch/commits?author=prc5" title="Code">💻</a> <a href="#infra-prc5" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a> <a href="#maintenance-prc5" title="Maintenance">🚧</a> <a href="#example-prc5" title="Examples">💡</a> <a href="#question-prc5" title="Answering Questions">💬</a></td>
</tr>
</table>

<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->

<!-- ALL-CONTRIBUTORS-LIST:END -->

This project follows the
[all-contributors](https://github.com/all-contributors/all-contributors)
specification. Contributions of any kind welcome!
6 changes: 3 additions & 3 deletions src/components/transform-component.tsx
Expand Up @@ -14,8 +14,8 @@ type Props = {

export const TransformComponent: React.FC<Props> = ({
children,
wrapperClass,
contentClass,
wrapperClass = "",
contentClass = "",
wrapperStyle,
contentStyle,
}: Props) => {
Expand All @@ -40,7 +40,7 @@ export const TransformComponent: React.FC<Props> = ({
>
<div
ref={contentRef}
className={`react-transform-content ${styles.content} ${contentClass}`}
className={`react-transform-component ${styles.content} ${contentClass}`}
style={contentStyle}
>
{children}
Expand Down
62 changes: 24 additions & 38 deletions src/components/transform-context.tsx
Expand Up @@ -50,7 +50,7 @@ import {
import {
handleDoubleClick,
isDoubleClickAllowed,
} from "../core/handlers/handlers.utils";
} from "../core/double-click/double-click.logic";
import { centerView } from "../core/handlers/handlers.logic";

type StartCoordsType = { x: number; y: number } | null;
Expand Down Expand Up @@ -86,6 +86,7 @@ class TransformContext extends Component<
public lastDistance: null | number = null;
public pinchStartDistance: null | number = null;
public pinchStartScale: null | number = null;
public pinchMidpoint: null | PositionType = null;
// velocity helpers
public velocity: VelocityType | null = null;
public velocityTime: number | null = null;
Expand Down Expand Up @@ -148,23 +149,17 @@ class TransformContext extends Component<

if (centerOnInit) {
// this has to be redone once the right solution is found
// problem is - we need to execute it after mounting
// it gets fired 3 times to handle all cases found during development
// problem is - we need to execute it after mounted component specify it's height / width
setTimeout(() => {
if (this.mounted) {
centerView(this);
centerView(this)();
}
}, 0);
}, 50);
setTimeout(() => {
if (this.mounted) {
centerView(this);
centerView(this)();
}
}, 15);
setTimeout(() => {
if (this.mounted) {
centerView(this);
}
}, 30);
}, 100);
}
};

Expand All @@ -182,7 +177,7 @@ class TransformContext extends Component<
const keysPressed = this.isPressingKeys(this.setup.wheel.activationKeys);
if (!keysPressed) return;

handleWheelStart(this);
handleWheelStart(this, event);
handleWheelZoom(this, event);
handleWheelStop(this, event);
};
Expand All @@ -202,12 +197,9 @@ class TransformContext extends Component<
const keysPressed = this.isPressingKeys(this.setup.panning.activationKeys);
if (!keysPressed) return;

event.preventDefault();
event.stopPropagation();

handleCancelAnimation(this);
handlePanningStart(this, event);
handleCallback(getContext(this), onPanningStart);
handleCallback(getContext(this), event, onPanningStart);
};

onPanning = (event: MouseEvent): void => {
Expand All @@ -222,19 +214,16 @@ class TransformContext extends Component<
const keysPressed = this.isPressingKeys(this.setup.panning.activationKeys);
if (!keysPressed) return;

event.preventDefault();
event.stopPropagation();

handlePanning(this, event.clientX, event.clientY);
handleCallback(getContext(this), onPanning);
handleCallback(getContext(this), event, onPanning);
};

onPanningStop = (): void => {
onPanningStop = (event: MouseEvent | TouchEvent): void => {
const { onPanningStop } = this.props;

if (this.isPanning) {
handlePanningEnd(this);
handleCallback(getContext(this), onPanningStop);
handleCallback(getContext(this), event, onPanningStop);
}
};

Expand All @@ -251,13 +240,10 @@ class TransformContext extends Component<
const isAllowed = isPinchStartAllowed(this, event);
if (!isAllowed) return;

event.preventDefault();
event.stopPropagation();

handlePinchStart(this, event);
handleCancelAnimation(this);
handleCallback(getContext(this), onPinchingStart);
handleCallback(getContext(this), onZoomStart);
handleCallback(getContext(this), event, onPinchingStart);
handleCallback(getContext(this), event, onZoomStart);
};

onPinch = (event: TouchEvent): void => {
Expand All @@ -273,17 +259,17 @@ class TransformContext extends Component<
event.stopPropagation();

handlePinchZoom(this, event);
handleCallback(getContext(this), onPinching);
handleCallback(getContext(this), onZoom);
handleCallback(getContext(this), event, onPinching);
handleCallback(getContext(this), event, onZoom);
};

onPinchStop = (): void => {
const { onPinchingStop, onZoomStop } = this.props;

if (this.pinchStartScale) {
handlePinchStop(this);
handleCallback(getContext(this), onPinchingStop);
handleCallback(getContext(this), onZoomStop);
handleCallback(getContext(this), event, onPinchingStop);
handleCallback(getContext(this), event, onZoomStop);
}
};

Expand Down Expand Up @@ -311,7 +297,7 @@ class TransformContext extends Component<
if (isPanningAction) {
handleCancelAnimation(this);
handlePanningStart(this, event);
handleCallback(getContext(this), onPanningStart);
handleCallback(getContext(this), event, onPanningStart);
}
if (isPinchAction) {
this.onPinchStart(event);
Expand All @@ -330,14 +316,14 @@ class TransformContext extends Component<

const touch = event.touches[0];
handlePanning(this, touch.clientX, touch.clientY);
handleCallback(getContext(this), onPanning);
handleCallback(getContext(this), event, onPanning);
} else if (event.touches.length > 1) {
this.onPinch(event);
}
};

onTouchPanningStop = (): void => {
this.onPanningStop();
onTouchPanningStop = (event: TouchEvent): void => {
this.onPanningStop(event);
this.onPinchStop();
};

Expand All @@ -359,9 +345,9 @@ class TransformContext extends Component<
// Helpers
//////////

clearPanning = (): void => {
clearPanning = (event: MouseEvent): void => {
if (this.isPanning) {
this.onPanningStop();
this.onPanningStop(event);
}
};

Expand Down
75 changes: 75 additions & 0 deletions src/core/double-click/double-click.logic.ts
@@ -0,0 +1,75 @@
import { ReactZoomPanPinchContext } from "../../models";

import { animate } from "../animations/animations.utils";
import { getMousePosition } from "core/zoom/wheel.utils";
import { handleZoomToPoint } from "core/zoom/zoom.logic";
import { isExcludedNode } from "utils";
import {
handleCalculateButtonZoom,
resetTransformations,
} from "core/handlers/handlers.utils";

export function handleDoubleClick(
contextInstance: ReactZoomPanPinchContext,
event: MouseEvent,
): void {
const {
disabled,
mode,
step,
animationTime,
animationType,
} = contextInstance.setup.doubleClick;

if (disabled) return;

if (mode === "reset") {
return resetTransformations(contextInstance, animationTime, animationType);
}

const { scale } = contextInstance.transformState;
const { contentComponent } = contextInstance;

if (!contentComponent) return console.error("No ContentComponent found");

const delta = mode === "zoomOut" ? -1 : 1;

const newScale = handleCalculateButtonZoom(contextInstance, delta, step);
const mousePosition = getMousePosition(event, contentComponent, scale);
const targetState = handleZoomToPoint(
contextInstance,
newScale,
mousePosition.x,
mousePosition.y,
);

if (!targetState) {
return console.error(
"Error during zoom event. New transformation state was not calculated.",
);
}

animate(contextInstance, targetState, animationTime, animationType);
}

export const isDoubleClickAllowed = (
contextInstance: ReactZoomPanPinchContext,
event: MouseEvent,
): boolean => {
const { isInitialized, setup, wrapperComponent } = contextInstance;
const { disabled, excluded } = setup.doubleClick;

const target = event.target as HTMLElement;
const isWrapperChild = wrapperComponent?.contains(target);
const isAllowed = isInitialized && target && isWrapperChild && !disabled;

if (!isAllowed) return false;

const isExcluded = isExcludedNode(target, excluded);

if (isExcluded) return false;

if (!isAllowed) return false;

return true;
};
32 changes: 28 additions & 4 deletions src/core/handlers/handlers.logic.ts
@@ -1,7 +1,11 @@
import { ReactZoomPanPinchContext } from "../../models";
import { handleZoomToViewCenter, resetTransformations } from "./handlers.utils";
import {
calculateZoomToNode,
handleZoomToViewCenter,
resetTransformations,
} from "./handlers.utils";
import { animations } from "../animations/animations.constants";
import { animate } from "../animations/animations.utils";
import { animate, handleCancelAnimation } from "../animations/animations.utils";
import { getCenteredTransformStyles } from "../../utils";

export const zoomIn = (contextInstance: ReactZoomPanPinchContext) => (
Expand Down Expand Up @@ -36,7 +40,7 @@ export const setTransform = (contextInstance: ReactZoomPanPinchContext) => (
newPositionX: number,
newPositionY: number,
newScale: number,
animationTime = 200,
animationTime = 300,
animationType: keyof typeof animations = "easeOut",
): void => {
const { positionX, positionY, scale } = contextInstance.transformState;
Expand All @@ -61,7 +65,9 @@ export const resetTransform = (contextInstance: ReactZoomPanPinchContext) => (
resetTransformations(contextInstance, animationTime, animationType);
};

export const centerView = (contextInstance: ReactZoomPanPinchContext): void => {
export const centerView = (
contextInstance: ReactZoomPanPinchContext,
) => (): void => {
const { initialPositionX, initialPositionY } = contextInstance.props;
const {
transformState,
Expand All @@ -83,3 +89,21 @@ export const centerView = (contextInstance: ReactZoomPanPinchContext): void => {
};
}
};

export const zoomToElement = (contextInstance: ReactZoomPanPinchContext) => (
node: HTMLElement | string,
animationTime = 600,
animationName: keyof typeof animations = "easeOut",
): void => {
handleCancelAnimation(contextInstance);

const { wrapperComponent } = contextInstance;

const target: HTMLElement | null =
typeof node === "string" ? document.getElementById(node) : node;

if (wrapperComponent && target && wrapperComponent.contains(target)) {
const targetState = calculateZoomToNode(contextInstance, target);
animate(contextInstance, targetState, animationTime, animationName);
}
};

0 comments on commit e547f53

Please sign in to comment.