UNPKG

antd-mobile

Version:
247 lines (246 loc) 9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Slide = void 0; var _react = _interopRequireWildcard(require("react")); var _web = require("@react-spring/web"); var _ahooks = require("ahooks"); var _rubberband = require("../../utils/rubberband"); var _useDragAndPinch = require("../../utils/use-drag-and-pinch"); var _bound = require("../../utils/bound"); var mat = _interopRequireWildcard(require("../../utils/matrix")); function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } const classPrefix = `adm-image-viewer`; const Slide = props => { const { dragLockRef, maxZoom } = props; const initialMartix = (0, _react.useRef)([]); const controlRef = (0, _react.useRef)(null); const imgRef = (0, _react.useRef)(null); const [{ matrix }, api] = (0, _web.useSpring)(() => ({ matrix: mat.create(), config: { tension: 200 } })); const controlSize = (0, _ahooks.useSize)(controlRef); const imgSize = (0, _ahooks.useSize)(imgRef); const pinchLockRef = (0, _react.useRef)(false); /** * Calculate the min and max value of x and y */ const getMinAndMax = nextMatrix => { if (!controlSize || !imgSize) return { x: { position: 0, minX: 0, maxX: 0 }, y: { position: 0, minY: 0, maxY: 0 } }; const controlLeft = -controlSize.width / 2; const controlTop = -controlSize.height / 2; const imgLeft = -imgSize.width / 2; const imgTop = -imgSize.height / 2; const zoom = mat.getScaleX(nextMatrix); const scaledImgWidth = zoom * imgSize.width; const scaledImgHeight = zoom * imgSize.height; const minX = controlLeft - (scaledImgWidth - controlSize.width); const maxX = controlLeft; const minY = controlTop - (scaledImgHeight - controlSize.height); const maxY = controlTop; const [x, y] = mat.apply(nextMatrix, [imgLeft, imgTop]); return { x: { position: x, minX, maxX }, y: { position: y, minY, maxY } }; }; /** * Check if is reach the bound */ const getReachBound = (position, min, max, buffer = 0) => { return [position <= min - buffer, position >= max + buffer]; }; /** * Limit the matrix in the bound */ const boundMatrix = (nextMatrix, type, last = false) => { if (!controlSize || !imgSize) return nextMatrix; const zoom = mat.getScaleX(nextMatrix); const scaledImgWidth = zoom * imgSize.width; const scaledImgHeight = zoom * imgSize.height; const { x: { position: x, minX, maxX }, y: { position: y, minY, maxY } } = getMinAndMax(nextMatrix); if (type === 'translate') { let boundedX = x; let boundedY = y; if (scaledImgWidth > controlSize.width) { boundedX = last ? (0, _bound.bound)(x, minX, maxX) : (0, _rubberband.rubberbandIfOutOfBounds)(x, minX, maxX, zoom * 50); } else { boundedX = -scaledImgWidth / 2; } if (scaledImgHeight > controlSize.height) { boundedY = last ? (0, _bound.bound)(y, minY, maxY) : (0, _rubberband.rubberbandIfOutOfBounds)(y, minY, maxY, zoom * 50); } else { boundedY = -scaledImgHeight / 2; } return mat.translate(nextMatrix, boundedX - x, boundedY - y); } if (type === 'scale' && last) { const [boundedX, boundedY] = [scaledImgWidth > controlSize.width ? (0, _bound.bound)(x, minX, maxX) : -scaledImgWidth / 2, scaledImgHeight > controlSize.height ? (0, _bound.bound)(y, minY, maxY) : -scaledImgHeight / 2]; return mat.translate(nextMatrix, boundedX - x, boundedY - y); } return nextMatrix; }; (0, _useDragAndPinch.useDragAndPinch)({ onDrag: state => { var _a; if (state.first) { const { x: { position: x, minX, maxX } } = getMinAndMax(matrix.get()); initialMartix.current = getReachBound(x, minX, maxX); return; } if (state.pinching) return state.cancel(); if (state.tap && state.elapsedTime > 0 && state.elapsedTime < 1000) { // 判断点击时间>0是为了过滤掉非正常操作,例如用户长按选择图片之后的取消操作(也是一次点击) (_a = props.onTap) === null || _a === void 0 ? void 0 : _a.call(props); return; } const currentZoom = mat.getScaleX(matrix.get()); if (dragLockRef) { dragLockRef.current = currentZoom !== 1; } if (!pinchLockRef.current && currentZoom <= 1) { api.start({ matrix: mat.create() }); } else { const currentMatrix = matrix.get(); const offset = [state.offset[0] - mat.getTranslateX(currentMatrix), state.offset[1] - mat.getTranslateY(currentMatrix)]; const nextMatrix = mat.translate(currentMatrix, ...(state.last ? [offset[0] + state.velocity[0] * state.direction[0] * 200, offset[1] + state.velocity[1] * state.direction[1] * 200] : offset)); api.start({ matrix: boundMatrix(nextMatrix, 'translate', state.last), immediate: !state.last }); const { x: { position: x, minX, maxX } } = getMinAndMax(nextMatrix); if (state.last && initialMartix.current.some(i => i) && getReachBound(x, minX, maxX).some(i => i)) { if (dragLockRef) { dragLockRef.current = false; } api.start({ matrix: mat.create() }); } } }, onPinch: state => { var _a; pinchLockRef.current = !state.last; const [d] = state.offset; if (d < 0) return; let mergedMaxZoom; if (maxZoom === 'auto') { mergedMaxZoom = controlSize && imgSize ? Math.max(controlSize.height / imgSize.height, controlSize.width / imgSize.width) : 1; } else { mergedMaxZoom = maxZoom; } const nextZoom = state.last ? (0, _bound.bound)(d, 1, mergedMaxZoom) : d; (_a = props.onZoomChange) === null || _a === void 0 ? void 0 : _a.call(props, nextZoom); if (state.last && nextZoom <= 1) { api.start({ matrix: mat.create() }); if (dragLockRef) { dragLockRef.current = false; } } else { if (!controlSize) return; const currentMatrix = matrix.get(); const currentZoom = mat.getScaleX(currentMatrix); const originOffsetX = state.origin[0] - controlSize.width / 2; const originOffsetY = state.origin[1] - controlSize.height / 2; let nextMatrix = mat.translate(currentMatrix, -originOffsetX, -originOffsetY); nextMatrix = mat.scale(nextMatrix, nextZoom / currentZoom); nextMatrix = mat.translate(nextMatrix, originOffsetX, originOffsetY); api.start({ matrix: boundMatrix(nextMatrix, 'scale', state.last), immediate: !state.last }); if (dragLockRef) { dragLockRef.current = true; } } } }, { target: controlRef, drag: { from: () => [mat.getTranslateX(matrix.get()), mat.getTranslateY(matrix.get())], pointer: { touch: true } }, pinch: { from: () => [mat.getScaleX(matrix.get()), 0], pointer: { touch: true } } }); return _react.default.createElement("div", { className: `${classPrefix}-slide` }, _react.default.createElement("div", { className: `${classPrefix}-control`, ref: controlRef }, _react.default.createElement(_web.animated.div, { className: `${classPrefix}-image-wrapper`, style: { matrix } }, _react.default.createElement("img", { ref: imgRef, src: props.image, draggable: false, alt: props.image })))); }; exports.Slide = Slide;