UNPKG

@openspacelabs/react-native-zoomable-view

Version:

A view component for react-native with pinch to zoom, tap to move and double tap to zoom capability.

124 lines (110 loc) 3.28 kB
import { Size2D, Vec2D, ZoomableViewEvent } from 'src/typings'; export const defaultTransformSubjectData: ZoomableViewEvent = { offsetX: 0, offsetY: 0, zoomLevel: 0, originalWidth: 0, originalHeight: 0, originalPageX: 0, originalPageY: 0, }; /** * Assuming you have an image that's being resized to fit into a container * using the "contain" resize mode. You can use this function to calculate the * size of the image after fitting. * * Since our sheet is resized in this manner, we need this function * for things like pan boundaries and marker placement * * @param imgSize * @param containerSize */ export function applyContainResizeMode( imgSize: Size2D, containerSize: Size2D ): { size: Size2D; scale: number } | { size: null; scale: null } { const { width: imageWidth, height: imageHeight } = imgSize; const { width: areaWidth, height: areaHeight } = containerSize; const imageAspect = imageWidth / imageHeight; const areaAspect = areaWidth / areaHeight; let newSize; if (imageAspect >= areaAspect) { // longest edge is horizontal newSize = { width: areaWidth, height: areaWidth / imageAspect }; } else { // longest edge is vertical newSize = { width: areaHeight * imageAspect, height: areaHeight }; } if (isNaN(newSize.height)) newSize.height = areaHeight; if (isNaN(newSize.width)) newSize.width = areaWidth; const scale = imageWidth ? newSize.width / imageWidth : newSize.height / imageHeight; if (!isFinite(scale)) return { size: null, scale: null }; return { size: newSize, scale, }; } /** * get the coord of image's origin relative to the transformSubject * @param resizedImageSize * @param transformSubject */ export function getImageOriginOnTransformSubject( resizedImageSize: Size2D, transformSubject: ZoomableViewEvent ) { const { offsetX, offsetY, zoomLevel, originalWidth, originalHeight } = transformSubject; return { x: offsetX * zoomLevel + originalWidth / 2 - (resizedImageSize.width / 2) * zoomLevel, y: offsetY * zoomLevel + originalHeight / 2 - (resizedImageSize.height / 2) * zoomLevel, }; } /** * Translates the coord system of a point from the viewport's space to the image's space * * @param pointOnContainer * @param sheetImageSize * @param transformSubject * * @return {Vec2D} returns null if point is out of the sheet's bound */ export function viewportPositionToImagePosition({ viewportPosition, imageSize, zoomableEvent, }: { viewportPosition: Vec2D; imageSize: Size2D; zoomableEvent: ZoomableViewEvent; }): Vec2D | null { const { size: resizedImgSize, scale: resizedImgScale } = applyContainResizeMode(imageSize, { width: zoomableEvent.originalWidth, height: zoomableEvent.originalHeight, }); if (resizedImgScale == null) return null; const sheetOriginOnContainer = getImageOriginOnTransformSubject( resizedImgSize, zoomableEvent ); const pointOnSheet = { x: (viewportPosition.x - sheetOriginOnContainer.x) / zoomableEvent.zoomLevel / resizedImgScale, y: (viewportPosition.y - sheetOriginOnContainer.y) / zoomableEvent.zoomLevel / resizedImgScale, }; return pointOnSheet; }