UNPKG

@antv/f2

Version:

Charts for mobile visualization.

530 lines (528 loc) 17.4 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _createSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/createSuper")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _component = _interopRequireDefault(require("../../base/component")); var _zoomUtil = require("./zoomUtil"); var _util = require("@antv/util"); var _equal = _interopRequireDefault(require("../../base/equal")); function lerp(min, max, fraction) { return (max - min) * fraction + min; } function isEqual(aRange, bRange) { for (var i in aRange) { if (!(0, _util.isNumberEqual)(aRange[i], bRange[i])) return false; } return true; } function cloneScale(scale, scaleConfig) { // @ts-ignore return new scale.constructor((0, _objectSpread2.default)((0, _objectSpread2.default)({}, scale.__cfg__), scaleConfig)); } // 缩放 var Zoom = /*#__PURE__*/function (_Component) { (0, _inherits2.default)(Zoom, _Component); var _super = (0, _createSuper2.default)(Zoom); function Zoom(props) { var _this; (0, _classCallCheck2.default)(this, Zoom); var defaultProps = { onPanStart: function onPanStart() {}, onPinchStart: function onPinchStart() {}, onPan: function onPan() {}, onPinch: function onPinch() {}, onInit: function onInit() {}, onPanEnd: function onPanEnd() {}, onPinchEnd: function onPinchEnd() {}, minCount: 10 }; _this = _super.call(this, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, defaultProps), props)); _this.scale = {}; _this.originScale = {}; //swipe end x y _this.swipeEnd = { startX: 0, startY: 0, endX: 0, endY: 0 }; _this.onStart = function () { var _assertThisInitialize = (0, _assertThisInitialized2.default)(_this), state = _assertThisInitialize.state; var range = state.range; _this.startRange = range; _this.loop && cancelAnimationFrame(_this.loop); }; _this.onPan = function (ev) { var _assertThisInitialize2 = (0, _assertThisInitialized2.default)(_this), dims = _assertThisInitialize2.dims; var range = {}; (0, _util.each)(dims, function (dim) { if (dim === 'x') { range['x'] = _this._doXPan(ev); return; } if (dim === 'y') { range['y'] = _this._doYPan(ev); return; } }); if (isEqual(range, _this.state.range)) return; _this.setState({ range: range }); // console.log('pan range', range); }; _this.onSwipe = function (ev) { var swipe = _this.props.swipe; if (_this.props.mode.length < 2 || !swipe) return; var _ev$velocityX = ev.velocityX, velocityX = _ev$velocityX === void 0 ? 0 : _ev$velocityX, _ev$velocityY = ev.velocityY, velocityY = _ev$velocityY === void 0 ? 0 : _ev$velocityY, points = ev.points; var range = _this.state.range; var _points$ = points[0], x = _points$.x, y = _points$.y; // 边界处理 if (Math.abs((range === null || range === void 0 ? void 0 : range.x[0]) - 0) < 0.0005 && velocityX > 0) return; if (Math.abs((range === null || range === void 0 ? void 0 : range.x[1]) - 1) < 0.0005 && velocityX < 0) return; if (Math.abs((range === null || range === void 0 ? void 0 : range.y[0]) - 0) < 0.0005 && velocityY < 0) return; if (Math.abs((range === null || range === void 0 ? void 0 : range.x[1]) - 1) < 0.0005 && velocityY > 0) return; _this.swipeEnd = { startX: x, startY: y, endX: x + velocityX * 50, endY: y - velocityY * 50 }; _this.onStart(); _this.update(); }; _this.onPinch = function (ev) { var _assertThisInitialize3 = (0, _assertThisInitialized2.default)(_this), dims = _assertThisInitialize3.dims; var range = {}; (0, _util.each)(dims, function (dim) { if (dim === 'x') { range['x'] = _this._doXPinch(ev); return; } if (dim === 'y') { range['y'] = _this._doYPinch(ev); return; } }); if (isEqual(range, _this.state.range)) return; _this.setState({ range: range }); }; _this.onEnd = function () { _this.startRange = null; }; var _props$range = props.range, range = _props$range === void 0 ? [0, 1] : _props$range, mode = props.mode; _this.dims = mode instanceof Array ? mode : [mode]; return _this; } (0, _createClass2.default)(Zoom, [{ key: "didMount", value: function didMount() { this._bindEvents(); } }, { key: "willReceiveProps", value: function willReceiveProps(nextProps) { var nextRange = nextProps.range; var lastRange = this.props.range; if (!(0, _equal.default)(nextRange, lastRange)) { var cacheRange = {}; (0, _util.each)(this.dims, function (dim) { cacheRange[dim] = nextRange; }); this.state = { range: cacheRange }; } } }, { key: "willMount", value: function willMount() { var _this2 = this; var props = this.props, dims = this.dims, state = this.state; var minCount = props.minCount, range = props.range; // const { range } = state; var valueLength = Number.MIN_VALUE; var cacheRange = {}; (0, _util.each)(dims, function (dim) { var scale = _this2._getScale(dim); var values = scale.values; valueLength = values.length > valueLength ? values.length : valueLength; _this2.scale[dim] = scale; _this2.originScale[dim] = cloneScale(scale); _this2.updateRange(range, dim); cacheRange[dim] = range; }); // 图表上最少显示 MIN_COUNT 个数据 this.minScale = minCount / valueLength; this.state = { range: cacheRange }; } }, { key: "didUnmount", value: function didUnmount() { this.loop && cancelAnimationFrame(this.loop); this._clearEvents(); } }, { key: "update", value: function update() { var _this3 = this; var _this$swipeEnd = this.swipeEnd, startX = _this$swipeEnd.startX, startY = _this$swipeEnd.startY, endX = _this$swipeEnd.endX, endY = _this$swipeEnd.endY; var x = lerp(startX, endX, 0.05); var y = lerp(startY, endY, 0.05); this.swipeEnd = { startX: x, startY: y, endX: endX, endY: endY }; var props = this.props; var coord = props.coord; var coordWidth = coord.width, coordHeight = coord.height; var range = {}; range['x'] = this._doPan((x - startX) / coordWidth, 'x'); range['y'] = this._doPan((y - startY) / coordHeight, 'y'); this.setState({ range: range }); this.startRange = range; this.loop = requestAnimationFrame(function () { return _this3.update(); }); if (Math.abs(x - endX) < 0.0005 && Math.abs(y - endY) < 0.0005) { this.onEnd(); cancelAnimationFrame(this.loop); } } }, { key: "_doXPan", value: function _doXPan(ev) { var direction = ev.direction, deltaX = ev.deltaX; if (this.props.mode.length === 1 && (direction === 'up' || direction === 'down')) { return this.state.range['x']; } ev.preventDefault && ev.preventDefault(); var props = this.props; var coord = props.coord, _props$panSensitive = props.panSensitive, panSensitive = _props$panSensitive === void 0 ? 1 : _props$panSensitive; var coordWidth = coord.width; var ratio = deltaX / coordWidth * panSensitive; var newRange = this._doPan(ratio, 'x'); return newRange; } }, { key: "_doYPan", value: function _doYPan(ev) { var direction = ev.direction, deltaY = ev.deltaY; if (this.props.mode.length === 1 && (direction === 'left' || direction === 'right')) { return this.state.range['y']; } ev.preventDefault && ev.preventDefault(); var props = this.props; var coord = props.coord, _props$panSensitive2 = props.panSensitive, panSensitive = _props$panSensitive2 === void 0 ? 1 : _props$panSensitive2; var coordHeight = coord.height; var ratio = -deltaY / coordHeight * panSensitive; var newRange = this._doPan(ratio, 'y'); return newRange; } }, { key: "_doPan", value: function _doPan(ratio, dim) { var startRange = this.startRange; var _startRange$dim = (0, _slicedToArray2.default)(startRange[dim], 2), start = _startRange$dim[0], end = _startRange$dim[1]; var rangeLen = end - start; var rangeOffset = rangeLen * ratio; var newStart = start - rangeOffset; var newEnd = end - rangeOffset; var newRange = this.updateRange([newStart, newEnd], dim); return newRange; } }, { key: "_doXPinch", value: function _doXPinch(ev) { ev.preventDefault && ev.preventDefault(); var zoom = ev.zoom, center = ev.center; var props = this.props; var coord = props.coord; var coordWidth = coord.width, left = coord.left, right = coord.right; var leftLen = Math.abs(center.x - left); var rightLen = Math.abs(right - center.x); // 计算左右缩放的比例 var leftZoom = leftLen / coordWidth; var rightZoom = rightLen / coordWidth; var newRange = this._doPinch(leftZoom, rightZoom, zoom, 'x'); return newRange; } }, { key: "_doYPinch", value: function _doYPinch(ev) { ev.preventDefault && ev.preventDefault(); var zoom = ev.zoom, center = ev.center; var props = this.props; var coord = props.coord; var coordHeight = coord.height, top = coord.top, bottom = coord.bottom; var topLen = Math.abs(center.y - top); var bottomLen = Math.abs(bottom - center.y); // 计算左右缩放的比例 var topZoom = topLen / coordHeight; var bottomZoom = bottomLen / coordHeight; var newRange = this._doPinch(topZoom, bottomZoom, zoom, 'y'); return newRange; } }, { key: "_doPinch", value: function _doPinch(startRatio, endRatio, zoom, dim) { var startRange = this.startRange, minScale = this.minScale, props = this.props; var _props$pinchSensitive = props.pinchSensitive, pinchSensitive = _props$pinchSensitive === void 0 ? 1 : _props$pinchSensitive; var _startRange$dim2 = (0, _slicedToArray2.default)(startRange[dim], 2), start = _startRange$dim2[0], end = _startRange$dim2[1]; var zoomOffset = zoom < 1 ? (1 / zoom - 1) * pinchSensitive : (1 - zoom) * pinchSensitive; var rangeLen = end - start; var rangeOffset = rangeLen * zoomOffset; var startOffset = rangeOffset * startRatio; var endOffset = rangeOffset * endRatio; var newStart = Math.max(0, start - startOffset); var newEnd = Math.min(1, end + endOffset); var newRange = [newStart, newEnd]; // 如果已经到了最小比例,则不能再继续再放大 if (newEnd - newStart < minScale) { return this.state.range[dim]; } return this.updateRange(newRange, dim); } }, { key: "updateRange", value: function updateRange(originalRange, dim) { if (!originalRange) return; var _originalRange = (0, _slicedToArray2.default)(originalRange, 2), start = _originalRange[0], end = _originalRange[1]; var rangeLength = end - start; // 处理边界值 var newRange; if (start < 0) { newRange = [0, rangeLength]; } else if (end > 1) { newRange = [1 - rangeLength, 1]; } else { newRange = originalRange; } var props = this.props, scale = this.scale, originScale = this.originScale, state = this.state; var chart = props.chart, data = props.data, autoFit = props.autoFit; var range = state.range; if (range && isEqual(newRange, range[dim])) return newRange; // 更新主 scale (0, _zoomUtil.updateRange)(scale[dim], originScale[dim], newRange); if (autoFit) { var followScale = this._getFollowScales(dim); this.updateFollow(followScale, scale[dim], data); } // 手势变化不执行动画 var animate = chart.animate; chart.setAnimate(false); chart.forceUpdate(function () { chart.setAnimate(animate); }); return newRange; } }, { key: "updateFollow", value: function updateFollow(scales, mainScale, data) { (0, _zoomUtil.updateFollow)(scales, mainScale, data); } }, { key: "_getScale", value: function _getScale(dim) { var _this$props = this.props, coord = _this$props.coord, chart = _this$props.chart; if (dim === 'x') { return coord.transposed ? chart.getYScales()[0] : chart.getXScales()[0]; } else { return coord.transposed ? chart.getXScales()[0] : chart.getYScales()[0]; } } }, { key: "_getFollowScales", value: function _getFollowScales(dim) { var _this$props2 = this.props, coord = _this$props2.coord, chart = _this$props2.chart; if (dim === 'x') { return coord.transposed ? chart.getXScales() : chart.getYScales(); } if (dim === 'y') { return coord.transposed ? chart.getYScales() : chart.getXScales(); } } }, { key: "_bindEvents", value: function _bindEvents() { var _this4 = this; var context = this.context, props = this.props, scale = this.scale; var canvas = context.canvas; var onPinchStart = props.onPinchStart, onPanStart = props.onPanStart, onPanEnd = props.onPanEnd, pan = props.pan, pinch = props.pinch, swipe = props.swipe, onInit = props.onInit, onPan = props.onPan, onPinch = props.onPinch, onPinchEnd = props.onPinchEnd; // 统一绑定事件 if (pan !== false) { canvas.on('panstart', function () { _this4.onStart(); onPanStart({ scale: scale }); }); canvas.on('pan', function (ev) { _this4.onPan(ev); onPan(ev); }); canvas.on('panend', function () { _this4.onEnd(); onPanEnd({ scale: scale }); }); } if (pinch !== false) { canvas.on('pinchstart', function () { _this4.onStart(); onPinchStart(); }); canvas.on('pinch', function (ev) { _this4.onPinch(ev); onPinch(ev); }); canvas.on('pinchend', function () { _this4.onEnd(); onPinchEnd({ scale: scale }); }); } if (swipe !== false) { canvas.on('swipe', this.onSwipe); } onInit({ scale: scale }); } }, { key: "_clearEvents", value: function _clearEvents() { var _this5 = this; var context = this.context, props = this.props, scale = this.scale; var canvas = context.canvas; var onPinchEnd = props.onPinchEnd, onPanEnd = props.onPanEnd, onPinchStart = props.onPinchStart, pan = props.pan, pinch = props.pinch, onPan = props.onPan, onPinch = props.onPinch, swipe = props.swipe; // 统一解绑事件 if (pan !== false) { canvas.off('panstart', function () { _this5.onStart(); onPinchStart(); }); canvas.off('pan', function (ev) { _this5.onPan(ev); onPan(ev); }); canvas.off('panend', function () { _this5.onEnd(); onPanEnd({ scale: scale }); }); } if (pinch !== false) { canvas.off('pinchstart', function () { _this5.onStart(); onPinchStart(); }); canvas.off('pinch', function (ev) { _this5.onPinch(ev); onPinch(ev); }); canvas.off('pinchend', function () { _this5.onEnd(); onPinchEnd({ scale: scale }); }); } if (swipe !== false) { canvas.off('swipe', this.onSwipe); } } }]); return Zoom; }(_component.default); var _default = Zoom; exports.default = _default;