UNPKG

zarm

Version:

基于 React 的移动端UI库

434 lines (357 loc) 13 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _bem = require("@zarm-design/bem"); var _raf = _interopRequireDefault(require("raf")); var _events = _interopRequireDefault(require("../utils/events")); var _configProvider = require("../config-provider"); var _dom = require("../utils/dom"); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) { if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } } return n.default = e, t && t.set(e, n), n; } var getTouches = function getTouches(touches) { return Array.from(touches).map(function (totuch) { return { x: totuch.pageX, y: totuch.pageY }; }); }; var getDistance = function getDistance(a, b) { if (!b) return 0; return Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2)); }; var calculateScale = function calculateScale(startTouches, endTouches) { var startDistance = getDistance(startTouches[0], startTouches[1]); var endDistance = getDistance(endTouches[0], endTouches[1]); return endDistance / startDistance; }; var range = function range(min, max, num) { return Math.min(Math.max(num, min), max); }; var sum = function sum(a, b) { return a + b; }; var getTouchCenter = function getTouchCenter(point) { return { x: point.map(function (_ref) { var x = _ref.x; return x; }).reduce(sum, 0) / point.length, y: point.map(function (_ref2) { var y = _ref2.y; return y; }).reduce(sum, 0) / point.length }; }; var cancelEvent = function cancelEvent(event) { event.stopPropagation(); if (!_events.default.supportsPassiveEvents) { event.preventDefault(); } }; var PinchZoom = /*#__PURE__*/_react.default.forwardRef(function (props, ref) { var container = ref || /*#__PURE__*/_react.default.createRef(); var _React$useContext = _react.default.useContext(_configProvider.ConfigContext), prefixCls = _React$useContext.prefixCls; var bem = (0, _bem.createBEM)('pinch-zoom', { prefixCls: prefixCls }); var children = props.children, className = props.className, maxScale = props.maxScale, minScale = props.minScale, onPinchZoom = props.onPinchZoom, style = props.style; var currentScale = 1; var lastScale = 1; var firstMove = false; var offset = (0, _react.useRef)({ x: 0, y: 0 }); var initOffset = (0, _react.useRef)({ x: 0, y: 0 }); var fingers = 0; var startTouches; var nthZoom = 0; var lastScaleCenter; var lastDragPosition; var wheelTimeOut; var rafId = (0, _react.useRef)(); var update = (0, _react.useCallback)(function () { var updateFrame = function updateFrame() { var _container$current, _container$current2, _container$current3; var x = -offset.current.x / currentScale; var y = -offset.current.y / currentScale; container === null || container === void 0 ? void 0 : (_container$current = container.current) === null || _container$current === void 0 ? void 0 : _container$current.style.setProperty('--x', "".concat(x, "px")); container === null || container === void 0 ? void 0 : (_container$current2 = container.current) === null || _container$current2 === void 0 ? void 0 : _container$current2.style.setProperty('--y', "".concat(y, "px")); container === null || container === void 0 ? void 0 : (_container$current3 = container.current) === null || _container$current3 === void 0 ? void 0 : _container$current3.style.setProperty('--scale', currentScale); if (typeof onPinchZoom === 'function') { onPinchZoom(currentScale, x, y); } }; if (rafId) { _raf.default.cancel(rafId.current); } rafId.current = (0, _raf.default)(updateFrame); }, [currentScale, container, onPinchZoom]); var alignCenter = function alignCenter() { var _container$current4, _container$current5; var node = (_container$current4 = container.current) === null || _container$current4 === void 0 ? void 0 : _container$current4.firstElementChild; initOffset.current = { x: 0, y: 0 }; var rect = (_container$current5 = container.current) === null || _container$current5 === void 0 ? void 0 : _container$current5.getBoundingClientRect(); var _getElementSize = (0, _dom.getElementSize)(node), width = _getElementSize.width, height = _getElementSize.height; if (width <= (rect === null || rect === void 0 ? void 0 : rect.width)) { initOffset.current = { x: -((rect === null || rect === void 0 ? void 0 : rect.width) - width) / 2, y: 0 }; } if (height <= (rect === null || rect === void 0 ? void 0 : rect.height)) { initOffset.current = { x: initOffset.current.x, y: -((rect === null || rect === void 0 ? void 0 : rect.height) - height) / 2 }; } offset.current = initOffset === null || initOffset === void 0 ? void 0 : initOffset.current; update(); }; (0, _react.useEffect)(function () { alignCenter(); }, [initOffset, offset, container, update]); var calculateOffset = function calculateOffset(newOffset) { offset.current = { x: offset.current.x + newOffset.x, y: offset.current.y + newOffset.y }; }; var calculateOffsetBoundary = function calculateOffsetBoundary(currentOffset) { var _container$current6; var rect = (0, _dom.getElementSize)(container.current); var _getElementSize2 = (0, _dom.getElementSize)((_container$current6 = container.current) === null || _container$current6 === void 0 ? void 0 : _container$current6.firstElementChild), width = _getElementSize2.width, height = _getElementSize2.height; var elWidth = width * currentScale; var elHeight = height * currentScale; var maxX = elWidth - rect.width; var maxY = elHeight - rect.height; var maxOffsetX = Math.max(maxX, 0); var maxOffsetY = Math.max(maxY, 0); var minOffsetX = Math.min(maxX, 0); var minOffsetY = Math.min(maxY, 0); return { x: range(minOffsetX, maxOffsetX, currentOffset.x), y: range(minOffsetY, maxOffsetY, currentOffset.y) }; }; var doScale = function doScale(scale, touchCenter) { var originScale = currentScale; currentScale *= scale; currentScale = range(minScale / 2, maxScale, currentScale); var newScale = currentScale / originScale; calculateOffset({ x: (newScale - 1) * (touchCenter.x + offset.current.x), y: (newScale - 1) * (touchCenter.y + offset.current.y) }); }; var getCurrentZoomCenter = function getCurrentZoomCenter() { var _offset$current = offset.current, x = _offset$current.x, y = _offset$current.y; var offsetLeft = x - initOffset.current.x; var offsetTop = y - initOffset.current.y; return { x: -1 * x - offsetLeft / (1 / currentScale - 1), y: -1 * y - offsetTop / (1 / currentScale - 1) }; }; var fixedScale = function fixedScale() { if (currentScale >= 1) { return false; } var center = getCurrentZoomCenter(); doScale(1 / currentScale, center); offset.current = initOffset.current; }; var end = function end() { fixedScale(); update(); }; var handleZoomEnd = function handleZoomEnd() { end(); }; var handleDragEnd = function handleDragEnd() { end(); }; var handleZoomStart = function handleZoomStart() { lastScale = 1; lastScaleCenter = null; nthZoom = 0; }; var doDrag = function doDrag(center, lastCenter) { if (lastCenter) { calculateOffset({ x: -(center.x - lastCenter.x), y: -(center.y - lastCenter.y) }); } }; var getTouchesOffset = function getTouchesOffset(touches) { var rect = container.current.getBoundingClientRect(); var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; var posTop = rect.top + scrollTop; var posLeft = rect.left + scrollLeft; return touches.map(function (touch) { return { x: touch.x - posLeft, y: touch.y - posTop }; }); }; var handleZoom = function handleZoom(event, newScale) { var touchCenter = getTouchCenter(getTouchesOffset(getTouches(event.touches))); var scale = newScale / lastScale; lastScale = newScale; nthZoom += 1; if (nthZoom > 3) { doScale(scale, touchCenter); doDrag(touchCenter, lastScaleCenter); } lastScaleCenter = touchCenter; }; var handleDrag = function handleDrag(event) { var touch = getTouches(event.touches)[0]; doDrag(touch, lastDragPosition); offset.current = calculateOffsetBoundary(offset.current); lastDragPosition = touch; }; var handleDragStart = function handleDragStart(event) { lastDragPosition = null; handleDrag(event); }; var touchStart = function touchStart(event) { firstMove = true; fingers = event.touches.length; }; var interaction = ''; var setInteraction = function setInteraction(newInteraction, event) { if (interaction !== newInteraction) { if (interaction && !newInteraction) { switch (interaction) { case 'zoom': handleZoomEnd(); break; case 'drag': handleDragEnd(); break; } } switch (newInteraction) { case 'zoom': handleZoomStart(); break; case 'drag': handleDragStart(event); break; } } interaction = newInteraction; }; var updateInteraction = function updateInteraction(event) { if (fingers === 2) { setInteraction('zoom', event); } else if (fingers === 1 && currentScale !== 1) { setInteraction('drag', event); } else { setInteraction(null, event); } }; var touchMove = function touchMove(event) { if (firstMove) { updateInteraction(event); if (interaction) { cancelEvent(event); } startTouches = getTouches(event.touches); } else { switch (interaction) { case 'zoom': if (startTouches.length === 2 && event.touches.length === 2) { handleZoom(event, calculateScale(startTouches, getTouches(event.touches))); } break; case 'drag': handleDrag(event); break; } if (interaction) { cancelEvent(event); update(); } } firstMove = false; }; var touchEnd = function touchEnd(event) { fingers = event.touches.length; updateInteraction(event); }; var wheel = function wheel(event) { var deltaY = event.deltaY; var ctrlKey = event.ctrlKey, deltaMode = event.deltaMode, pageX = event.pageX, pageY = event.pageY; if (deltaMode === 1) { deltaY *= 15; } var divisor = ctrlKey ? 100 : 300; doScale(1 - deltaY / divisor, getTouchesOffset([{ x: pageX, y: pageY }])[0]); update(); clearTimeout(wheelTimeOut); wheelTimeOut = setTimeout(function () { end(); }, 100); }; var cls = bem([className]); var child = _react.default.Children.map(children, function (element) { return /*#__PURE__*/_react.default.cloneElement(element, { onLoad: function onLoad(e) { var _element$props, _element$props$onLoad; (_element$props = element.props) === null || _element$props === void 0 ? void 0 : (_element$props$onLoad = _element$props.onLoad) === null || _element$props$onLoad === void 0 ? void 0 : _element$props$onLoad.call(_element$props, e); alignCenter(); } }); }); return /*#__PURE__*/_react.default.createElement("div", { onTouchStart: touchStart, onTouchCancel: touchEnd, onTouchEnd: touchEnd, onTouchMove: touchMove, onWheel: wheel, ref: container, className: cls, style: style }, child); }); PinchZoom.defaultProps = { minScale: 1, maxScale: 3 }; var _default = PinchZoom; exports.default = _default;