zarm
Version:
基于 React 的移动端UI库
434 lines (357 loc) • 13 kB
JavaScript
"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;