UNPKG

hcmobile-sdk

Version:

mobile-sdk

563 lines 27.8 kB
'use strict'; var __extends = (this && this.__extends) || (function () { var extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __assign = (this && this.__assign) || Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; Object.defineProperty(exports, '__esModule', { value: true }); var React = require('react'); var react_native_1 = require('react-native'); var image_zoom_style_1 = require('./image-zoom.style'); var image_zoom_type_1 = require('./image-zoom.type'); var isMobile = function () { if (react_native_1.Platform.OS === 'web') { return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent); } else { return true; } }; // var ImageViewer = /** @class */ (function (_super) { __extends(ImageViewer, _super); function ImageViewer() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = new image_zoom_type_1.State(); // 上次/当前/动画 x 位移 _this.lastPositionX = null; _this.positionX = 0; _this.animatedPositionX = new react_native_1.Animated.Value(0); // 上次/当前/动画 y 位移 _this.lastPositionY = null; _this.positionY = 0; _this.animatedPositionY = new react_native_1.Animated.Value(0); // 缩放大小 _this.scale = 1; _this.animatedScale = new react_native_1.Animated.Value(1); _this.zoomLastDistance = null; _this.zoomCurrentDistance = 0; // 滑动过程中,整体横向过界偏移量 _this.horizontalWholeOuterCounter = 0; // 滑动过程中,x y的总位移 _this.horizontalWholeCounter = 0; _this.verticalWholeCounter = 0; // 两手距离中心点位置 _this.centerDiffX = 0; _this.centerDiffY = 0; // 上一次点击的时间 _this.lastClickTime = 0; // 双击时的位置 _this.doubleClickX = 0; _this.doubleClickY = 0; // 是否双击了 _this.isDoubleClick = false; // 是否是长按 _this.isLongPress = false; _this.panResponderReleaseResolve = function () { if (_this.scale < 1) { // 如果缩放小于1,强制重置为 1 _this.scale = 1; react_native_1.Animated.timing(_this.animatedScale, { toValue: _this.scale, duration: 100 }).start(); } if (_this.props.imageWidth * _this.scale <= _this.props.cropWidth) { // 如果图片宽度小于盒子宽度,横向位置重置 _this.positionX = 0; react_native_1.Animated.timing(_this.animatedPositionX, { toValue: _this.positionX, duration: 100 }).start(); } if (_this.props.imageHeight * _this.scale <= _this.props.cropHeight) { // 如果图片高度小于盒子高度,纵向位置重置 _this.positionY = 0; react_native_1.Animated.timing(_this.animatedPositionY, { toValue: _this.positionY, duration: 100 }).start(); } // 横向肯定不会超出范围,由拖拽时控制 // 如果图片高度大于盒子高度,纵向不能出现黑边 if (_this.props.imageHeight * _this.scale > _this.props.cropHeight) { // 纵向能容忍的绝对值 var verticalMax = (_this.props.imageHeight * _this.scale - _this.props.cropHeight) / 2 / _this.scale; if (_this.positionY < -verticalMax) { _this.positionY = -verticalMax; } else if (_this.positionY > verticalMax) { _this.positionY = verticalMax; } react_native_1.Animated.timing(_this.animatedPositionY, { toValue: _this.positionY, duration: 100 }).start(); } // 拖拽正常结束后,如果没有缩放,直接回到0,0点 if (_this.scale === 1) { _this.positionX = 0; _this.positionY = 0; react_native_1.Animated.timing(_this.animatedPositionX, { toValue: _this.positionX, duration: 100 }).start(); react_native_1.Animated.timing(_this.animatedPositionY, { toValue: _this.positionY, duration: 100 }).start(); } // 水平溢出量置空 _this.horizontalWholeOuterCounter = 0; _this.imageDidMove('onPanResponderRelease'); }; return _this; } ImageViewer.prototype.componentWillMount = function () { var _this = this; var setResponder = isMobile(); this.imagePanResponder = react_native_1.PanResponder.create({ // 要求成为响应者: onStartShouldSetPanResponder: function (evt, gestureState) { return setResponder; }, onPanResponderTerminationRequest: function (evt, gestureState) { return false; }, onPanResponderGrant: function (evt, gestureState) { // 开始手势操作 _this.lastPositionX = null; _this.lastPositionY = null; _this.zoomLastDistance = null; _this.horizontalWholeCounter = 0; _this.verticalWholeCounter = 0; _this.lastTouchStartTime = new Date().getTime(); _this.isDoubleClick = false; _this.isLongPress = false; // 任何手势开始,都清空单击计时器 if (_this.singleClickTimeout) { clearTimeout(_this.singleClickTimeout); } if (evt.nativeEvent.changedTouches.length > 1) { var centerX = (evt.nativeEvent.changedTouches[0].pageX + evt.nativeEvent.changedTouches[1].pageX) / 2; _this.centerDiffX = centerX - _this.props.cropWidth / 2; var centerY = (evt.nativeEvent.changedTouches[0].pageY + evt.nativeEvent.changedTouches[1].pageY) / 2; _this.centerDiffY = centerY - _this.props.cropHeight / 2; } // 计算长按 if (_this.longPressTimeout) { clearTimeout(_this.longPressTimeout); } _this.longPressTimeout = setTimeout(function () { _this.isLongPress = true; if (_this.props.onLongPress) { _this.props.onLongPress(); } }, _this.props.longPressTime); if (evt.nativeEvent.changedTouches.length <= 1) { // 一个手指的情况 if (new Date().getTime() - _this.lastClickTime < (_this.props.doubleClickInterval || 0)) { // 认为触发了双击 _this.lastClickTime = 0; if (_this.props.onDoubleClick) { _this.props.onDoubleClick(); } // 取消长按 clearTimeout(_this.longPressTimeout); // 因为可能触发放大,因此记录双击时的坐标位置 _this.doubleClickX = evt.nativeEvent.changedTouches[0].pageX; _this.doubleClickY = evt.nativeEvent.changedTouches[0].pageY; // 缩放 _this.isDoubleClick = true; if (_this.scale > 1 || _this.scale < 1) { // 回归原位 _this.scale = 1; _this.positionX = 0; _this.positionY = 0; } else { // 开始在位移地点缩放 // 记录之前缩放比例 // 此时 this.scale 一定为 1 var beforeScale = _this.scale; // 开始缩放 _this.scale = 2; // 缩放 diff var diffScale = _this.scale - beforeScale; // 找到两手中心点距离页面中心的位移 // 移动位置 _this.positionX = (_this.props.cropWidth / 2 - _this.doubleClickX) * diffScale / _this.scale; _this.positionY = (_this.props.cropHeight / 2 - _this.doubleClickY) * diffScale / _this.scale; } react_native_1.Animated.parallel([ react_native_1.Animated.timing(_this.animatedScale, { toValue: _this.scale, duration: 100 }), react_native_1.Animated.timing(_this.animatedPositionX, { toValue: _this.positionX, duration: 100 }), react_native_1.Animated.timing(_this.animatedPositionY, { toValue: _this.positionY, duration: 100 }) ]).start(); } else { _this.lastClickTime = new Date().getTime(); } } }, onPanResponderMove: function (evt, gestureState) { if (_this.isDoubleClick) { // 有时双击会被当做位移,这里屏蔽掉 return; } if (evt.nativeEvent.changedTouches.length <= 1) { // x 位移 var diffX = gestureState.dx - (_this.lastPositionX || 0); if (_this.lastPositionX === null) { diffX = 0; } // y 位移 var diffY = gestureState.dy - (_this.lastPositionY || 0); if (_this.lastPositionY === null) { diffY = 0; } // 保留这一次位移作为下次的上一次位移 _this.lastPositionX = gestureState.dx; _this.lastPositionY = gestureState.dy; _this.horizontalWholeCounter += diffX; _this.verticalWholeCounter += diffY; if (Math.abs(_this.horizontalWholeCounter) > 5 || Math.abs(_this.verticalWholeCounter) > 5) { // 如果位移超出手指范围,取消长按监听 clearTimeout(_this.longPressTimeout); } if (_this.props.panToMove) { // diffX > 0 表示手往右滑,图往左移动,反之同理 // horizontalWholeOuterCounter > 0 表示溢出在左侧,反之在右侧,绝对值越大溢出越多 if (_this.props.imageWidth * _this.scale > _this.props.cropWidth) { // 如果图片宽度大图盒子宽度, 可以横向拖拽 // 没有溢出偏移量或者这次位移完全收回了偏移量才能拖拽 if (_this.horizontalWholeOuterCounter > 0) { // 溢出在右侧 if (diffX < 0) { // 从右侧收紧 if (_this.horizontalWholeOuterCounter > Math.abs(diffX)) { // 偏移量还没有用完 _this.horizontalWholeOuterCounter += diffX; diffX = 0; } else { // 溢出量置为0,偏移量减去剩余溢出量,并且可以被拖动 diffX += _this.horizontalWholeOuterCounter; _this.horizontalWholeOuterCounter = 0; if (_this.props.horizontalOuterRangeOffset) { _this.props.horizontalOuterRangeOffset(0); } } } else { // 向右侧扩增 _this.horizontalWholeOuterCounter += diffX; } } else if (_this.horizontalWholeOuterCounter < 0) { // 溢出在左侧 if (diffX > 0) { // 从左侧收紧 if (Math.abs(_this.horizontalWholeOuterCounter) > diffX) { // 偏移量还没有用完 _this.horizontalWholeOuterCounter += diffX; diffX = 0; } else { // 溢出量置为0,偏移量减去剩余溢出量,并且可以被拖动 diffX += _this.horizontalWholeOuterCounter; _this.horizontalWholeOuterCounter = 0; if (_this.props.horizontalOuterRangeOffset) { _this.props.horizontalOuterRangeOffset(0); } } } else { // 向左侧扩增 _this.horizontalWholeOuterCounter += diffX; } } else { // 溢出偏移量为0,正常移动 } // 产生位移 _this.positionX += diffX / _this.scale; // 但是横向不能出现黑边 // 横向能容忍的绝对值 var horizontalMax = (_this.props.imageWidth * _this.scale - _this.props.cropWidth) / 2 / _this.scale; if (_this.positionX < -horizontalMax) { // 超越了左边临界点,还在继续向左移动 _this.positionX = -horizontalMax; // 让其产生细微位移,偏离轨道 _this.horizontalWholeOuterCounter += -1 / 1e10; } else if (_this.positionX > horizontalMax) { // 超越了右侧临界点,还在继续向右移动 _this.positionX = horizontalMax; // 让其产生细微位移,偏离轨道 _this.horizontalWholeOuterCounter += 1 / 1e10; } _this.animatedPositionX.setValue(_this.positionX); } else { // 不能横向拖拽,全部算做溢出偏移量 _this.horizontalWholeOuterCounter += diffX; } // 溢出量不会超过设定界限 if (_this.horizontalWholeOuterCounter > (_this.props.maxOverflow || 0)) { _this.horizontalWholeOuterCounter = _this.props.maxOverflow || 0; } else if (_this.horizontalWholeOuterCounter < -(_this.props.maxOverflow || 0)) { _this.horizontalWholeOuterCounter = -(_this.props.maxOverflow || 0); } if (_this.horizontalWholeOuterCounter !== 0) { // 如果溢出偏移量不是0,执行溢出回调 if (_this.props.horizontalOuterRangeOffset) { _this.props.horizontalOuterRangeOffset(_this.horizontalWholeOuterCounter); } } if (_this.props.imageHeight * _this.scale > _this.props.cropHeight) { // 如果图片高度大图盒子高度, 可以纵向拖拽 _this.positionY += diffY / _this.scale; _this.animatedPositionY.setValue(_this.positionY); } } } else { // 多个手指的情况 // 取消长按状态 if (_this.longPressTimeout) { clearTimeout(_this.longPressTimeout); } if (_this.props.pinchToZoom) { // 找最小的 x 和最大的 x var minX = void 0; var maxX = void 0; if (evt.nativeEvent.changedTouches[0].locationX > evt.nativeEvent.changedTouches[1].locationX) { minX = evt.nativeEvent.changedTouches[1].pageX; maxX = evt.nativeEvent.changedTouches[0].pageX; } else { minX = evt.nativeEvent.changedTouches[0].pageX; maxX = evt.nativeEvent.changedTouches[1].pageX; } var minY = void 0; var maxY = void 0; if (evt.nativeEvent.changedTouches[0].locationY > evt.nativeEvent.changedTouches[1].locationY) { minY = evt.nativeEvent.changedTouches[1].pageY; maxY = evt.nativeEvent.changedTouches[0].pageY; } else { minY = evt.nativeEvent.changedTouches[0].pageY; maxY = evt.nativeEvent.changedTouches[1].pageY; } var widthDistance = maxX - minX; var heightDistance = maxY - minY; var diagonalDistance = Math.sqrt(widthDistance * widthDistance + heightDistance * heightDistance); _this.zoomCurrentDistance = Number(diagonalDistance.toFixed(1)); if (_this.zoomLastDistance !== null) { var distanceDiff = (_this.zoomCurrentDistance - _this.zoomLastDistance) / 200; var zoom = _this.scale + distanceDiff; if (zoom < 0.6) { zoom = 0.6; } if (zoom > 10) { zoom = 10; } // 记录之前缩放比例 var beforeScale = _this.scale; // 开始缩放 _this.scale = zoom; _this.animatedScale.setValue(_this.scale); // 图片要慢慢往两个手指的中心点移动 // 缩放 diff var diffScale = _this.scale - beforeScale; // 找到两手中心点距离页面中心的位移 // 移动位置 _this.positionX -= _this.centerDiffX * diffScale / _this.scale; _this.positionY -= _this.centerDiffY * diffScale / _this.scale; _this.animatedPositionX.setValue(_this.positionX); _this.animatedPositionY.setValue(_this.positionY); } _this.zoomLastDistance = _this.zoomCurrentDistance; } } _this.imageDidMove('onPanResponderMove'); }, onPanResponderRelease: function (evt, gestureState) { // 取消长按 if (_this.longPressTimeout) { clearTimeout(_this.longPressTimeout); } // 双击结束,结束尾判断 if (_this.isDoubleClick) { return; } // 长按结束,结束尾判断 if (_this.isLongPress) { return; } // 如果是单个手指、距离上次按住大于预设秒、滑动距离小于预设值, 则可能是单击(如果后续双击间隔内没有开始手势) var stayTime = new Date().getTime() - _this.lastTouchStartTime; var moveDistance = Math.sqrt(gestureState.dx * gestureState.dx + gestureState.dy * gestureState.dy); if (evt.nativeEvent.changedTouches.length === 1 && moveDistance < (_this.props.clickDistance || 0)) { _this.singleClickTimeout = setTimeout(function () { if (_this.props.onClick) { _this.props.onClick(); } }, _this.props.doubleClickInterval); } else { // 多手势结束,或者滑动结束 if (_this.props.responderRelease) { _this.props.responderRelease(gestureState.vx, _this.scale); } _this.panResponderReleaseResolve(); } }, onPanResponderTerminate: function (evt, gestureState) { // } }); }; ImageViewer.prototype.componentDidMount = function () { if (this.props.centerOn) { this.centerOn(this.props.centerOn); } }; ImageViewer.prototype.componentWillReceiveProps = function (nextProps) { // Either centerOn has never been called, or it is a repeat and we should ignore it if ((nextProps.centerOn && !this.props.centerOn) || (nextProps.centerOn && this.props.centerOn && this.didCenterOnChange(this.props.centerOn, nextProps.centerOn))) { this.centerOn(nextProps.centerOn); } }; ImageViewer.prototype.imageDidMove = function (type) { if (this.props.onMove) { this.props.onMove({ type: type, positionX: this.positionX, positionY: this.positionY, scale: this.scale, zoomCurrentDistance: this.zoomCurrentDistance }); } }; ImageViewer.prototype.didCenterOnChange = function (params, paramsNext) { return (params.x !== paramsNext.x || params.y !== paramsNext.y || params.scale !== paramsNext.scale); }; ImageViewer.prototype.centerOn = function (params) { var _this = this; this.positionX = params.x; this.positionY = params.y; this.scale = params.scale; var duration = params.duration || 300; react_native_1.Animated.parallel([ react_native_1.Animated.timing(this.animatedScale, { toValue: this.scale, duration: duration }), react_native_1.Animated.timing(this.animatedPositionX, { toValue: this.positionX, duration: duration }), react_native_1.Animated.timing(this.animatedPositionY, { toValue: this.positionY, duration: duration }) ]).start(function () { _this.imageDidMove('centerOn'); }); }; /** * 图片区域视图渲染完毕 */ ImageViewer.prototype.handleLayout = function (event) { // this.centerX = event.nativeEvent.layout.x + event.nativeEvent.layout.width / 2 // this.centerY = event.nativeEvent.layout.y + event.nativeEvent.layout.height / 2 if (this.props.layoutChange) { this.props.layoutChange(event); } }; /** * 重置大小和位置 */ ImageViewer.prototype.reset = function () { this.scale = 1; this.animatedScale.setValue(this.scale); this.positionX = 0; this.animatedPositionX.setValue(this.positionX); this.positionY = 0; this.animatedPositionY.setValue(this.positionY); }; ImageViewer.prototype.render = function () { var animateConf = { transform: [ { scale: this.animatedScale }, { translateX: this.animatedPositionX }, { translateY: this.animatedPositionY } ] }; return (<react_native_1.View style={__assign({}, image_zoom_style_1.default.container, this.props.style, { width: this.props.cropWidth, height: this.props.cropHeight })} {...this.imagePanResponder.panHandlers}> <react_native_1.Animated.View style={animateConf}> <react_native_1.View onLayout={this.handleLayout.bind(this)} style={{ width: this.props.imageWidth, height: this.props.imageHeight }}> {this.props.children} </react_native_1.View> </react_native_1.Animated.View> </react_native_1.View>); }; ImageViewer.defaultProps = new image_zoom_type_1.Props(); return ImageViewer; }(React.Component)); exports.default = ImageViewer; //# sourceMappingURL=image-zoom.component.js.map