easy-magnify
Version:
Everything you need for magnifying images
720 lines (706 loc) • 25.7 kB
JavaScript
;
var React2 = require('react');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var React2__default = /*#__PURE__*/_interopDefault(React2);
function useMouse(options = { resetOnExit: false }) {
const [position, setPosition] = React2.useState({ x: 0, y: 0 });
const ref = React2.useRef(null);
const requestRef = React2.useRef(null);
const positionRef = React2.useRef(position);
const setMousePosition = React2.useCallback((event) => {
if (ref.current) {
const rect = event.currentTarget.getBoundingClientRect();
const x = Math.max(
0,
Math.round(event.pageX - rect.left - (window.pageXOffset || window.scrollX))
);
const y = Math.max(
0,
Math.round(event.pageY - rect.top - (window.pageYOffset || window.scrollY))
);
positionRef.current = { x, y };
} else {
positionRef.current = { x: event.clientX, y: event.clientY };
}
if (requestRef.current === null) {
requestRef.current = requestAnimationFrame(() => {
setPosition(positionRef.current);
requestRef.current = null;
});
}
}, []);
const resetMousePosition = React2.useCallback(() => {
positionRef.current = { x: 0, y: 0 };
setPosition({ x: 0, y: 0 });
}, []);
React2.useEffect(() => {
const element = ref.current || document;
element.addEventListener("mousemove", setMousePosition);
if (options.resetOnExit) element.addEventListener("mouseleave", resetMousePosition);
return () => {
element.removeEventListener("mousemove", setMousePosition);
if (options.resetOnExit) element.removeEventListener("mouseleave", resetMousePosition);
if (requestRef.current !== null) {
cancelAnimationFrame(requestRef.current);
}
};
}, [setMousePosition, resetMousePosition, options.resetOnExit]);
return { ref, ...position };
}
var use_mouse_default = useMouse;
var EasySkeleton = (props) => {
const { height, width, backgroundColor, animation, ...other } = props;
return /* @__PURE__ */ React2__default.default.createElement(
"div",
{
className: "easyPulseSkeleton",
style: {
backgroundColor: backgroundColor ?? "#0000001c",
height: `${height}px`,
width: `${width}px`,
animation: animation ?? "pulse 2s ease-in-out 0.5s infinite"
},
...other
}
);
};
var Skeleton_default = EasySkeleton;
// src/hooks/useStore/use-store.ts
function createStore(initialState) {
const listeners = /* @__PURE__ */ new Set();
let batching = false;
let state = initialState;
let updatedProperties;
const setState = (extraState = {}) => {
updatedProperties = { ...updatedProperties, ...extraState };
flush();
};
const flush = () => {
if (batching) return;
let hasChanged = false;
if (updatedProperties) {
for (const key in updatedProperties) {
if (state[key] !== updatedProperties[key]) {
hasChanged = true;
break;
}
}
}
if (!hasChanged) {
return;
}
state = { ...state, ...updatedProperties };
listeners.forEach((listener) => listener({ state, updatedProperties }));
updatedProperties = void 0;
};
const batch = (cb) => {
batching = true;
cb();
batching = false;
flush();
};
const subscribe = (listener) => {
listeners.add(listener);
return () => {
listeners.delete(listener);
};
};
const cleanup = () => listeners.clear();
const getState = () => state;
return {
subscribe,
cleanup,
getState,
setState,
batch
};
}
// src/core/imageLoader.tsx
var THRESHOLD = 50;
var makeImageLoader = () => {
const createZoomImage = (img, src, store) => {
if (img.src === src) return;
img.src = src;
let complete = false;
img.onload = () => {
complete = true;
store.setState({ zoomedImgStatus: "loaded" });
};
img.onerror = () => {
complete = true;
store.setState({ zoomedImgStatus: "error" });
};
setTimeout(() => {
if (!complete) store.setState({ zoomedImgStatus: "loading" });
}, THRESHOLD);
};
return {
createZoomImage
};
};
var imageLoader = makeImageLoader();
// src/core/clamp.ts
function clamp(value, min, max) {
return Math.max(min, Math.min(max, value));
}
function noop() {
}
function preventDefault(event) {
event.preventDefault();
}
var keySet = /* @__PURE__ */ new Set(["ArrowUp", "ArrowRight", "ArrowDown", "ArrowLeft"]);
function preventDefaultForScrollKeys(event) {
if (keySet.has(event.key)) {
preventDefault(event);
return false;
}
}
var controller;
function disableScroll() {
controller = new AbortController();
const { signal } = controller;
window.addEventListener("DOMMouseScroll", preventDefault, { signal });
window.addEventListener("wheel", preventDefault, { passive: false, signal });
window.addEventListener("touchmove", preventDefault, { passive: false, signal });
window.addEventListener("keydown", preventDefaultForScrollKeys, { signal });
}
function enableScroll() {
controller?.abort();
}
function getSourceImage(container) {
if (!container) {
throw new Error("Please specify a container for the zoom image");
}
const sourceImgElement = container.querySelector("img");
if (!sourceImgElement) {
throw new Error("Please place an image inside the container");
}
return sourceImgElement;
}
function getPointersCenter(first, second) {
return {
x: (first.x + second.x) / 2,
y: (first.y + second.y) / 2
};
}
function computeZoomGesture(prev, curr) {
const prevCenter = getPointersCenter(prev[0], prev[1]);
const currCenter = getPointersCenter(curr[0], curr[1]);
const centerDist = { x: currCenter.x - prevCenter.x, y: currCenter.y - prevCenter.y };
const prevDistance = Math.hypot(prev[0].x - prev[1].x, prev[0].y - prev[1].y);
const currDistance = Math.hypot(curr[0].x - curr[1].x, curr[0].y - curr[1].y);
let scale = currDistance / prevDistance;
const eps = 1e-5;
if (Math.abs(scale - 1) < eps) {
scale = 1 + eps;
}
return {
scale,
center: {
// We shift the zoom center away such that the translation part of the gesture
// is also captured by the zoom operation.
x: prevCenter.x + centerDist.x / (1 - scale),
y: prevCenter.y + centerDist.y / (1 - scale)
}
};
}
function makeMaybeCallFunction(predicateFn, fn) {
return (arg) => {
if (predicateFn()) {
fn(arg);
}
};
}
var scaleLinear = ({
domainStart,
domainStop,
rangeStart,
rangeStop
}) => (value) => rangeStart + (rangeStop - rangeStart) * ((value - domainStart) / (domainStop - domainStart));
// src/core/createZoomImageHover.tsx
function createZoomImageHover(container, options) {
const controller2 = new AbortController();
const { signal } = controller2;
const sourceImgElement = getSourceImage(container);
const zoomedImgWrapper = document.createElement("div");
zoomedImgWrapper.style.overflow = "hidden";
const zoomedImg = zoomedImgWrapper.appendChild(document.createElement("img"));
zoomedImg.alt = options.zoomImageProps?.alt || "";
zoomedImg.style.maxWidth = "none";
zoomedImg.style.display = "none";
const zoomLens = container.appendChild(document.createElement("div"));
zoomLens.style.display = "none";
zoomedImg.id = "meroZoomedImg";
let sourceImageElementWidth = 0;
let sourceImageElementHeight = 0;
const finalOptions = {
zoomImageSource: options.zoomImageSource || sourceImgElement.src,
zoomLensClass: options.zoomLensClass || "",
zoomTargetClass: options.zoomTargetClass || "",
customZoom: options.customZoom,
scale: options.scale || 2,
zoomTarget: options.zoomTarget,
zoomLensScale: options.zoomLensScale || 1,
disableScrollLock: options.disableScrollLock || false
};
const {
scale,
zoomImageSource,
customZoom,
zoomLensClass,
zoomTarget,
zoomLensScale,
zoomTargetClass,
disableScrollLock
} = finalOptions;
const store = createStore({
zoomedImgStatus: "idle",
enabled: true
});
let offset = getOffset(sourceImgElement);
function getOffset(element) {
const elRect = element.getBoundingClientRect();
return { left: elRect.left, top: elRect.top };
}
function getLimitX(value) {
return sourceImageElementWidth - value;
}
function getLimitY(value) {
return sourceImageElementHeight - value;
}
function zoomLensLeft(left) {
const minX = zoomLens.clientWidth / 2;
return clamp(left, minX, getLimitX(minX)) - minX;
}
function zoomLensTop(top) {
const minY = zoomLens.clientHeight / 2;
return clamp(top, minY, getLimitY(minY)) - minY;
}
function processZoom(event) {
let offsetX;
let offsetY;
let backgroundX;
let backgroundY;
if (offset) {
offsetX = zoomLensLeft(event.clientX - offset.left);
offsetY = zoomLensTop(event.clientY - offset.top);
backgroundX = offsetX * scale / zoomLensScale;
backgroundY = offsetY * scale / zoomLensScale;
zoomedImg.style.transform = "translate(" + -backgroundX + "px," + -backgroundY + "px)";
zoomLens.style.cssText += "transform:translate(" + offsetX + "px," + offsetY + "px);";
}
}
async function handlePointerEnter() {
imageLoader.createZoomImage(zoomedImg, zoomImageSource, store);
zoomedImg.style.display = "block";
zoomLens.style.display = "block";
if (zoomTargetClass) {
const classes = zoomTargetClass.split(" ");
classes.forEach((className) => zoomTarget.classList.add(className));
}
if (!disableScrollLock) disableScroll();
}
function handlePointerLeave() {
zoomedImg.style.display = "none";
zoomLens.style.display = "none";
if (zoomTargetClass) {
const classes = zoomTargetClass.split(" ");
classes.forEach((className) => zoomTarget.classList.remove(className));
}
if (!disableScrollLock) enableScroll();
}
function handleScroll() {
offset = getOffset(sourceImgElement);
}
async function setup() {
if (zoomLensClass) {
zoomLens.className = zoomLensClass;
} else {
zoomLens.style.backgroundImage = "url(data:image/gif;base64,R0lGODlhZABkAPABAHOf4fj48yH5BAEAAAEALAAAAABkAGQAAAL+jI+py+0PowOB2oqvznz7Dn5iSI7SiabqWrbj68bwTLL2jUv0Lvf8X8sJhzmg0Yc8mojM5kmZjEKPzqp1MZVqs7Cr98rdisOXr7lJHquz57YwDV8j3XRb/C7v1vcovD8PwicY8VcISDGY2GDIKKf4mNAoKQZZeXg5aQk5yRml+dgZ2vOpKGraQpp4uhqYKsgKi+H6iln7N8sXG4u7p2s7ykvnyxos/DuMWtyGfKq8fAwd5nzGHN067VUtiv2lbV3GDfY9DhQu7p1pXoU+rr5ODk/j7sSePk9Ub33PlN+4jx8v4JJ/RQQa3EDwzcGFiBLi6AfN4UOGCyXegGjIoh0fisQ0rsD4y+NHjgZFqgB5y2Qfks1UPmEZ0OVLlIcKAAA7)";
zoomLens.style.cursor = "pointer";
}
container.addEventListener("pointerdown", processZoom, { signal });
container.addEventListener("pointermove", processZoom, { signal });
container.addEventListener("pointerenter", handlePointerEnter, { signal });
container.addEventListener("pointerleave", handlePointerLeave, { signal });
window.addEventListener("scroll", handleScroll, { signal });
zoomTarget.appendChild(zoomedImgWrapper);
await new Promise((resolve) => setTimeout(resolve, 1));
const containerRect = container.getBoundingClientRect();
sourceImageElementWidth = containerRect.width;
sourceImageElementHeight = containerRect.height;
if (customZoom) {
zoomedImgWrapper.style.maxWidth = customZoom.width + "px";
zoomedImgWrapper.style.height = customZoom.height + "px";
} else {
zoomedImgWrapper.style.width = sourceImageElementWidth + "px";
zoomedImgWrapper.style.height = sourceImageElementHeight + "px";
}
zoomedImg.width = sourceImageElementWidth * scale / zoomLensScale;
zoomedImg.height = sourceImageElementHeight * scale / zoomLensScale;
const sourceImageRect = sourceImgElement.getBoundingClientRect();
const fromLeft = sourceImageRect.left - containerRect.left;
const fromTop = sourceImageRect.top - containerRect.top;
zoomTarget.style.pointerEvents = "none";
zoomLens.style.position = "absolute";
zoomLens.style.left = fromLeft + "px";
zoomLens.style.top = fromTop + "px";
zoomLens.style.width = customZoom.width / scale * zoomLensScale + "px";
zoomLens.style.height = customZoom.height / scale * zoomLensScale + "px";
}
setup();
return {
cleanup: () => {
controller2.abort();
container.contains(zoomLens) && container.removeChild(zoomLens);
if (zoomTarget && zoomTarget.contains(zoomedImgWrapper)) {
zoomTarget.removeChild(zoomedImgWrapper);
return;
}
container.contains(zoomedImgWrapper) && container.removeChild(zoomedImgWrapper);
},
subscribe: store.subscribe,
getState: store.getState,
setState: (newState) => {
store.setState(newState);
}
};
}
// src/utils/useZoomImageHover.ts
function useZoomImageHover() {
const result = React2.useRef();
const [zoomImageState, updateZoomImageState] = React2.useState({
enabled: false,
zoomedImgStatus: "idle"
});
const createZoomImage = React2.useCallback((...arg) => {
result.current?.cleanup();
result.current = createZoomImageHover(...arg);
updateZoomImageState(result.current.getState());
result.current.subscribe(({ state }) => {
updateZoomImageState(state);
});
}, []);
React2.useEffect(() => {
return () => {
result.current?.cleanup();
};
}, []);
return {
createZoomImage,
zoomImageState,
setZoomImageState: result.current?.setState ?? (() => {
})
};
}
// src/core/cropImage.tsx
var cropImage = async ({ image, positionX, positionY, currentZoom, rotation = 0 }) => {
const canvas = document.createElement("canvas");
const scale = image.naturalWidth / (image.clientWidth * currentZoom);
const normalizedRotation = rotation % 360;
const croppedImageWidth = image.clientWidth * scale;
const croppedImageHeight = image.clientHeight * scale;
canvas.width = croppedImageWidth;
canvas.height = croppedImageHeight;
const canvasContext = canvas.getContext("2d");
const sx = Math.max(0, Math.abs(positionX) * scale);
const sy = Math.max(0, Math.abs(positionY) * scale);
canvasContext.drawImage(
image,
sx,
sy,
croppedImageWidth,
croppedImageHeight,
0,
0,
croppedImageWidth,
croppedImageHeight
);
const originalImage = new Image();
originalImage.src = canvas.toDataURL();
await new Promise((resolve) => setTimeout(resolve, 0));
const rotatedCanvas = document.createElement("canvas");
const rotatedCanvasContext = rotatedCanvas.getContext("2d");
if (normalizedRotation === 90 || normalizedRotation === 270) {
rotatedCanvas.width = originalImage.naturalHeight;
rotatedCanvas.height = originalImage.naturalWidth;
} else {
rotatedCanvas.width = originalImage.naturalWidth;
rotatedCanvas.height = originalImage.naturalHeight;
}
rotatedCanvasContext.clearRect(0, 0, canvas.width, canvas.height);
if (normalizedRotation === 90 || normalizedRotation === 270) {
rotatedCanvasContext.translate(originalImage.height / 2, originalImage.width / 2);
} else {
rotatedCanvasContext.translate(originalImage.width / 2, originalImage.height / 2);
}
rotatedCanvasContext.rotate(normalizedRotation * Math.PI / 180);
rotatedCanvasContext.drawImage(originalImage, -originalImage.width / 2, -originalImage.height / 2);
return rotatedCanvas.toDataURL();
};
var cropImage_default = cropImage;
// src/core/createZoomImageMove.tsx
function createZoomImageMove(container, options = {}) {
const sourceImgElement = getSourceImage(container);
const finalOptions = {
zoomFactor: options.zoomFactor ?? 4,
zoomImageSource: options.zoomImageSource ?? sourceImgElement.src,
disableScrollLock: options.disableScrollLock ?? false
};
const { disableScrollLock, zoomFactor, zoomImageSource } = finalOptions;
const store = createStore({
zoomedImgStatus: "idle"
});
const zoomedImg = container.appendChild(document.createElement("img"));
zoomedImg.alt = options.zoomImageProps?.alt || "";
zoomedImg.style.maxWidth = "none";
zoomedImg.style.position = "absolute";
zoomedImg.style.top = "0";
zoomedImg.style.left = "0";
function handlePointerEnter(event) {
zoomedImg.style.display = "block";
const zoomedImgWidth = sourceImgElement.clientWidth * zoomFactor;
const zoomedImgHeight = sourceImgElement.clientHeight * zoomFactor;
zoomedImg.style.width = `${zoomedImgWidth}px`;
zoomedImg.style.height = `${zoomedImgHeight}px`;
imageLoader.createZoomImage(zoomedImg, zoomImageSource, store);
processZoom(event);
if (!disableScrollLock) disableScroll();
}
function handlePointerMove(event) {
processZoom(event);
}
function handlePointerLeave() {
zoomedImg.style.display = "none";
zoomedImg.style.transform = "none";
if (!disableScrollLock) enableScroll();
}
const calculatePositionX = (newPositionX) => {
const width = container.clientWidth;
if (newPositionX > 0) return 0;
if (newPositionX + width * zoomFactor < width) return -width * (zoomFactor - 1);
return newPositionX;
};
const calculatePositionY = (newPositionY) => {
const height = container.clientHeight;
if (newPositionY > 0) return 0;
if (newPositionY + height * zoomFactor < height) return -height * (zoomFactor - 1);
return newPositionY;
};
function processZoom(event) {
zoomedImg.style.display = "block";
const containerRect = container.getBoundingClientRect();
const zoomPointX = event.clientX - containerRect.left;
const zoomPointY = event.clientY - containerRect.top;
const currentPositionX = calculatePositionX(-zoomPointX * zoomFactor + zoomPointX);
const currentPositionY = calculatePositionY(-zoomPointY * zoomFactor + zoomPointY);
zoomedImg.style.transform = `translate(${currentPositionX}px, ${currentPositionY}px)`;
}
const controller2 = new AbortController();
const { signal } = controller2;
container.addEventListener("pointerenter", handlePointerEnter, { signal });
container.addEventListener("pointermove", handlePointerMove, { signal });
container.addEventListener("pointerleave", handlePointerLeave, { signal });
return {
cleanup: () => {
controller2.abort();
container.contains(zoomedImg) && container.removeChild(zoomedImg);
container.style.width = "100%";
container.style.height = "100%";
store.cleanup();
},
subscribe: store.subscribe,
getState: store.getState
};
}
// src/utils/useZoomImageMove.ts
function useZoomImageMove() {
const result = React2.useRef();
const [zoomImageState, updateZoomImageState] = React2.useState({
zoomedImgStatus: "idle"
});
const createZoomImage = React2.useCallback((...arg) => {
result.current?.cleanup();
result.current = createZoomImageMove(...arg);
updateZoomImageState(result.current.getState());
result.current.subscribe(({ state }) => {
updateZoomImageState(state);
});
}, []);
React2.useEffect(() => {
return () => {
result.current?.cleanup();
};
}, []);
return {
createZoomImage,
zoomImageState
};
}
// src/EasyZoomOnHover.tsx
var EasyZoomOnHover = React2__default.default.forwardRef(function EasyZoomOnHover2(props, ref) {
const { mainImage, zoomImage, loadingIndicator, delayTimer, distance = 10, zoomContainerWidth } = props;
const { createZoomImage: createZoomImageHover2 } = useZoomImageHover();
const imageHoverContainerRef = React2__default.default.useRef(null);
const zoomTargetRef = React2__default.default.useRef(null);
const imgRef = React2__default.default.useRef(null);
const [imageDimension, setImageDimensions] = React2__default.default.useState({ height: 0, width: 0 });
const [isImageLoaded, setIsImageLoaded] = React2__default.default.useState(false);
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const handleImageLoad = async () => {
if (imgRef.current) {
setImageDimensions({
width: imgRef.current.naturalWidth,
height: imgRef.current.naturalHeight
});
await delay(delayTimer ?? 1600);
setIsImageLoaded(true);
}
};
React2__default.default.useEffect(() => {
if (imageDimension.width > 0 && imageDimension.height > 0) {
const imageContainer = imageHoverContainerRef.current;
const zoomTarget = zoomTargetRef.current;
createZoomImageHover2(
imageContainer,
{
zoomImageSource: zoomImage.src ?? mainImage.src,
customZoom: {
width: props.zoomContainerWidth ?? imageDimension.width ?? 450,
height: props.zoomContainerHeight ?? imageDimension.height ?? 470
},
zoomTarget,
scale: props.zoomLensScale ?? 3
}
);
}
}, [isImageLoaded, imageDimension]);
return /* @__PURE__ */ React2__default.default.createElement(React2__default.default.Fragment, null, !isImageLoaded && (loadingIndicator ?? /* @__PURE__ */ React2__default.default.createElement(
Skeleton_default,
{
height: props.mainImage.height ?? 450,
width: props.mainImage.width ?? 450
}
)), /* @__PURE__ */ React2__default.default.createElement(
"div",
{
ref: imageHoverContainerRef,
className: "EasyZoomImageHoverMainContainer",
style: {
position: "relative",
width: props.mainImage.width ?? imageDimension.width,
height: props.mainImage.height ?? imageDimension.height,
display: isImageLoaded ? "flex" : "none",
justifyItems: "start"
}
},
/* @__PURE__ */ React2__default.default.createElement(
"img",
{
className: "EasyZoomHoverSmallImage",
onLoad: handleImageLoad,
ref: imgRef,
style: { height: "auto", width: "auto" },
alt: mainImage.alt ?? "Small Pic",
src: mainImage.src
}
),
/* @__PURE__ */ React2__default.default.createElement(
"div",
{
ref: zoomTargetRef,
className: "EasyZoomImageZoomHoverContainer",
id: "zoomTargeted",
style: {
position: "absolute",
maxWidth: zoomContainerWidth ?? "450px",
left: `${mainImage.width ? mainImage.width + distance : imageDimension.width + distance}px`
}
}
)
));
});
var EasyZoomOnHover_default = EasyZoomOnHover;
var EasyZoomOnMove = (props) => {
const { mainImage, zoomImage, loadingIndicator, delayTimer } = props;
const [isImageLoaded, setIsImageLoaded] = React2__default.default.useState(false);
const { createZoomImage: createZoomImageMove2 } = useZoomImageMove();
const imageMoveContainerRef = React2__default.default.useRef(null);
const imgRef = React2__default.default.useRef(null);
const [imageDimension, setImageDimensions] = React2__default.default.useState({ height: 0, width: 0 });
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
React2__default.default.useEffect(() => {
if (imageDimension.width > 0 && imageDimension.height > 0) ;
const imageContainer = imageMoveContainerRef.current;
if (imageContainer) {
createZoomImageMove2(imageContainer, {
zoomImageSource: zoomImage.src,
zoomImageProps: { alt: zoomImage.alt }
});
}
}, [zoomImage.src, zoomImage.alt, createZoomImageMove2]);
const handleImageLoad = async () => {
if (imgRef.current) {
setImageDimensions({
width: imgRef.current.naturalWidth,
height: imgRef.current.naturalHeight
});
await delay(delayTimer ?? 1600);
setIsImageLoaded(true);
}
};
return /* @__PURE__ */ React2__default.default.createElement(React2__default.default.Fragment, null, !isImageLoaded && (loadingIndicator ?? /* @__PURE__ */ React2__default.default.createElement(
Skeleton_default,
{
height: props.mainImage.height ?? 450,
width: props.mainImage.width ?? 450
}
)), /* @__PURE__ */ React2__default.default.createElement(
"div",
{
ref: imageMoveContainerRef,
className: "EasyImageZoomOnMoveContainer",
style: {
position: "relative",
maxHeight: mainImage.height ?? imageDimension?.height ?? "auto",
maxWidth: mainImage.width ?? imageDimension?.width,
overflow: "hidden",
cursor: "crosshair",
display: isImageLoaded ? "block" : "none"
}
},
/* @__PURE__ */ React2__default.default.createElement(
"img",
{
className: "EasyImageZoomOnMoveImage",
onLoad: handleImageLoad,
ref: imgRef,
style: { width: "full", height: "full" },
alt: mainImage.alt ?? "Large Pic",
src: mainImage.src
}
)
));
};
var EasyZoomOnMove_default = EasyZoomOnMove;
exports.EasySkeleton = Skeleton_default;
exports.EasyZoomOnHover = EasyZoomOnHover_default;
exports.EasyZoomOnMove = EasyZoomOnMove_default;
exports.clamp = clamp;
exports.computeZoomGesture = computeZoomGesture;
exports.createStore = createStore;
exports.createZoomImageHover = createZoomImageHover;
exports.createZoomImageMove = createZoomImageMove;
exports.cropImage = cropImage_default;
exports.disableScroll = disableScroll;
exports.enableScroll = enableScroll;
exports.getPointersCenter = getPointersCenter;
exports.getSourceImage = getSourceImage;
exports.imageLoader = imageLoader;
exports.makeImageLoader = makeImageLoader;
exports.makeMaybeCallFunction = makeMaybeCallFunction;
exports.noop = noop;
exports.scaleLinear = scaleLinear;
exports.useMouse = use_mouse_default;
//# sourceMappingURL=out.js.map
//# sourceMappingURL=index.js.map