1 | import { __assign, __extends } from "tslib";
|
2 | import { Component, isEqual, jsx } from '@antv/f-engine';
|
3 | import { updateRange, updateFollow } from './zoomUtil';
|
4 | import { each, isNumberEqual, isArray } from '@antv/util';
|
5 | import { quadraticOut as easeing } from './easing';
|
6 | function lerp(min, max, fraction) {
|
7 | return (max - min) * fraction + min;
|
8 | }
|
9 | function isNumberEqualRange(aRange, bRange) {
|
10 | if (!bRange) return false;
|
11 | for (var i = 0, len = aRange.length; i < len; i++) {
|
12 | if (!isNumberEqual(aRange[i], bRange[i])) return false;
|
13 | }
|
14 | return true;
|
15 | }
|
16 | function isEqualRange(aRange, bRange) {
|
17 | if (!bRange) return false;
|
18 | if (isArray(aRange)) {
|
19 | return isNumberEqualRange(aRange, bRange);
|
20 | }
|
21 |
|
22 | for (var i in aRange) {
|
23 | if (!isNumberEqualRange(aRange[i], bRange[i])) return false;
|
24 | }
|
25 | return true;
|
26 | }
|
27 | function cloneScale(scale, scaleConfig) {
|
28 |
|
29 | return new scale.constructor(__assign(__assign({}, scale.__cfg__), scaleConfig));
|
30 | }
|
31 | export default (function (View) {
|
32 | return function (_super) {
|
33 | __extends(Zoom, _super);
|
34 | function Zoom(props) {
|
35 | var _this = this;
|
36 | var defaultProps = {
|
37 | onPanStart: function onPanStart() {},
|
38 | onPinchStart: function onPinchStart() {},
|
39 | onPan: function onPan() {},
|
40 | onPinch: function onPinch() {},
|
41 | onInit: function onInit() {},
|
42 | onPanEnd: function onPanEnd() {},
|
43 | onPinchEnd: function onPinchEnd() {},
|
44 | minCount: 10
|
45 | };
|
46 | _this = _super.call(this, __assign(__assign({}, defaultProps), props)) || this;
|
47 | _this.scale = {};
|
48 | _this.originScale = {};
|
49 |
|
50 | _this.swipeEnd = {
|
51 | startX: 0,
|
52 | startY: 0,
|
53 | endX: 0,
|
54 | endY: 0
|
55 | };
|
56 | _this.onStart = function () {
|
57 | var state = _this.state;
|
58 | var range = state.range;
|
59 | _this.startRange = range;
|
60 | _this.loop && cancelAnimationFrame(_this.loop);
|
61 | };
|
62 | _this.onPan = function (ev) {
|
63 | var dims = _this.dims;
|
64 | var range = {};
|
65 | each(dims, function (dim) {
|
66 | if (dim === 'x') {
|
67 | range['x'] = _this._doXPan(ev);
|
68 | return;
|
69 | }
|
70 | if (dim === 'y') {
|
71 | range['y'] = _this._doYPan(ev);
|
72 | return;
|
73 | }
|
74 | });
|
75 | _this.renderRange(range);
|
76 | };
|
77 | _this.onSwipe = function (ev) {
|
78 | var _a = _this,
|
79 | props = _a.props,
|
80 | state = _a.state;
|
81 |
|
82 | var velocity = ev.velocity,
|
83 | direction = ev.direction,
|
84 | _b = ev.velocityX,
|
85 | velocityX = _b === void 0 ? 0 : _b,
|
86 | _c = ev.velocityY,
|
87 | velocityY = _c === void 0 ? 0 : _c,
|
88 | points = ev.points;
|
89 | var mode = props.mode,
|
90 | swipe = props.swipe;
|
91 | var range = state.range;
|
92 | if (!swipe || !mode) {
|
93 | return;
|
94 | }
|
95 | if (mode.length === 1) {
|
96 | _this.animateSwipe(mode, range[mode], direction === 'right' || direction === 'down' ? -velocity : velocity);
|
97 | return;
|
98 | }
|
99 | var _d = points[0],
|
100 | x = _d.x,
|
101 | y = _d.y;
|
102 |
|
103 | if (Math.abs((range === null || range === void 0 ? void 0 : range.x[0]) - 0) < 0.0005 && velocityX > 0) return;
|
104 | if (Math.abs((range === null || range === void 0 ? void 0 : range.x[1]) - 1) < 0.0005 && velocityX < 0) return;
|
105 | if (Math.abs((range === null || range === void 0 ? void 0 : range.y[0]) - 0) < 0.0005 && velocityY < 0) return;
|
106 | if (Math.abs((range === null || range === void 0 ? void 0 : range.x[1]) - 1) < 0.0005 && velocityY > 0) return;
|
107 | _this.swipeEnd = {
|
108 | startX: x,
|
109 | startY: y,
|
110 | endX: x + velocityX * 50,
|
111 | endY: y - velocityY * 50
|
112 | };
|
113 | _this.onStart();
|
114 | _this.update();
|
115 | };
|
116 | _this.onPinch = function (ev) {
|
117 | var dims = _this.dims;
|
118 | var range = {};
|
119 | each(dims, function (dim) {
|
120 | if (dim === 'x') {
|
121 | range['x'] = _this._doXPinch(ev);
|
122 | return;
|
123 | }
|
124 | if (dim === 'y') {
|
125 | range['y'] = _this._doYPinch(ev);
|
126 | return;
|
127 | }
|
128 | });
|
129 | _this.renderRange(range);
|
130 | };
|
131 | _this.onEnd = function () {
|
132 | _this.startRange = null;
|
133 | };
|
134 | var mode = props.mode;
|
135 | _this.dims = isArray(mode) ? mode : [mode];
|
136 | return _this;
|
137 | }
|
138 | Zoom.prototype.didMount = function () {
|
139 | var scale = this.scale;
|
140 | var onInit = this.props.onInit;
|
141 | onInit({
|
142 | scale: scale
|
143 | });
|
144 | this._bindEvents();
|
145 | };
|
146 | Zoom.prototype.willReceiveProps = function (nextProps) {
|
147 | var nextRange = nextProps.range;
|
148 | var lastRange = this.props.range;
|
149 | if (!isEqual(nextRange, lastRange)) {
|
150 | var cacheRange_1 = {};
|
151 | each(this.dims, function (dim) {
|
152 | cacheRange_1[dim] = nextRange;
|
153 | });
|
154 | this.state = {
|
155 | range: cacheRange_1
|
156 | };
|
157 | }
|
158 | };
|
159 | Zoom.prototype.willMount = function () {
|
160 | var _this = this;
|
161 | var _a = this,
|
162 | props = _a.props,
|
163 | dims = _a.dims;
|
164 | var minCount = props.minCount,
|
165 | range = props.range;
|
166 | var valueLength = Number.MIN_VALUE;
|
167 | var cacheRange = {};
|
168 | each(dims, function (dim) {
|
169 | var scale = _this._getScale(dim);
|
170 | var values = scale.values;
|
171 | valueLength = values.length > valueLength ? values.length : valueLength;
|
172 | _this.scale[dim] = scale;
|
173 | _this.originScale[dim] = cloneScale(scale);
|
174 | _this.updateRange(range, dim);
|
175 | cacheRange[dim] = range;
|
176 | });
|
177 |
|
178 | this.minScale = minCount / valueLength;
|
179 | this.renderRange(cacheRange);
|
180 | };
|
181 | Zoom.prototype.willUpdate = function () {
|
182 | var _this = this;
|
183 | var _a = this,
|
184 | props = _a.props,
|
185 | state = _a.state,
|
186 | dims = _a.dims;
|
187 | var minCount = props.minCount,
|
188 | range = props.range;
|
189 | var valueLength = Number.MIN_VALUE;
|
190 | var cacheRange = {};
|
191 | each(dims, function (dim) {
|
192 | var scale = _this._getScale(dim);
|
193 |
|
194 | if (scale === _this.scale[dim]) {
|
195 | return;
|
196 | }
|
197 | var values = scale.values;
|
198 | valueLength = values.length > valueLength ? values.length : valueLength;
|
199 | _this.scale[dim] = scale;
|
200 | _this.originScale[dim] = cloneScale(scale);
|
201 |
|
202 | _this.state.range[dim] = [0, 1];
|
203 | _this.updateRange(range, dim);
|
204 | cacheRange[dim] = range;
|
205 | });
|
206 |
|
207 | if (Object.keys(cacheRange).length > 0) {
|
208 | this.minScale = minCount / valueLength;
|
209 | var newRange = __assign(__assign({}, state.range), cacheRange);
|
210 | this.renderRange(newRange);
|
211 | }
|
212 | };
|
213 | Zoom.prototype.didUnmount = function () {
|
214 | this.loop && cancelAnimationFrame(this.loop);
|
215 | };
|
216 | Zoom.prototype._bindEvents = function () {
|
217 | var _this = this;
|
218 | var scale = this.scale;
|
219 | var _a = this.props,
|
220 | chart = _a.chart,
|
221 | onPinchStart = _a.onPinchStart,
|
222 | onPanStart = _a.onPanStart,
|
223 | onPanEnd = _a.onPanEnd,
|
224 | pan = _a.pan,
|
225 | pinch = _a.pinch,
|
226 | swipe = _a.swipe,
|
227 | onPan = _a.onPan,
|
228 | onPinch = _a.onPinch,
|
229 | onPinchEnd = _a.onPinchEnd;
|
230 |
|
231 | if (pan !== false) {
|
232 | chart.on('panstart', function () {
|
233 | _this.onStart();
|
234 | onPanStart({
|
235 | scale: scale
|
236 | });
|
237 | });
|
238 | chart.on('pan', function (ev) {
|
239 | _this.onPan(ev);
|
240 | onPan(ev);
|
241 | });
|
242 | chart.on('panend', function () {
|
243 | _this.onEnd();
|
244 | onPanEnd({
|
245 | scale: scale
|
246 | });
|
247 | });
|
248 | }
|
249 | if (pinch !== false) {
|
250 | chart.on('pinchstart', function () {
|
251 | _this.onStart();
|
252 | onPinchStart();
|
253 | });
|
254 | chart.on('pinch', function (ev) {
|
255 | _this.onPinch(ev);
|
256 | onPinch(ev);
|
257 | });
|
258 | chart.on('pinchend', function () {
|
259 | _this.onEnd();
|
260 | onPinchEnd({
|
261 | scale: scale
|
262 | });
|
263 | });
|
264 | }
|
265 | if (swipe !== false) {
|
266 | chart.on('swipe', this.onSwipe);
|
267 | }
|
268 | };
|
269 | Zoom.prototype.update = function () {
|
270 | var _this = this;
|
271 | var _a = this.swipeEnd,
|
272 | startX = _a.startX,
|
273 | startY = _a.startY,
|
274 | endX = _a.endX,
|
275 | endY = _a.endY;
|
276 | var x = lerp(startX, endX, 0.05);
|
277 | var y = lerp(startY, endY, 0.05);
|
278 | this.swipeEnd = {
|
279 | startX: x,
|
280 | startY: y,
|
281 | endX: endX,
|
282 | endY: endY
|
283 | };
|
284 | var props = this.props;
|
285 | var coord = props.coord;
|
286 | var coordWidth = coord.width,
|
287 | coordHeight = coord.height;
|
288 | var range = {};
|
289 | range['x'] = this._doPan((x - startX) / coordWidth, 'x');
|
290 | range['y'] = this._doPan((y - startY) / coordHeight, 'y');
|
291 | this.renderRange(range);
|
292 | this.startRange = range;
|
293 | this.loop = requestAnimationFrame(function () {
|
294 | return _this.update();
|
295 | });
|
296 | if (Math.abs(x - endX) < 0.0005 && Math.abs(y - endY) < 0.0005) {
|
297 | this.onEnd();
|
298 | cancelAnimationFrame(this.loop);
|
299 | }
|
300 | };
|
301 | Zoom.prototype.animateSwipe = function (dim, dimRange, velocity) {
|
302 | var _this = this;
|
303 | var _a = this,
|
304 | context = _a.context,
|
305 | props = _a.props;
|
306 | var requestAnimationFrame = context.canvas.requestAnimationFrame;
|
307 | var _b = props.swipeDuration,
|
308 | swipeDuration = _b === void 0 ? 1000 : _b;
|
309 | var diff = (dimRange[1] - dimRange[0]) * velocity;
|
310 | var startTime = Date.now();
|
311 | var updateRange = function updateRange(t) {
|
312 | var newDimRange = [dimRange[0] + diff * t, dimRange[1] + diff * t];
|
313 | var newRange = _this.updateRange(newDimRange, dim);
|
314 | _this.renderRange({
|
315 | x: newRange
|
316 | });
|
317 | };
|
318 |
|
319 | var update = function update() {
|
320 |
|
321 | var currentTime = Date.now() - startTime;
|
322 |
|
323 | if (currentTime >= swipeDuration) {
|
324 | updateRange(1);
|
325 | return;
|
326 | }
|
327 |
|
328 | var progress = currentTime / swipeDuration;
|
329 | var easedProgress = easeing(progress);
|
330 | updateRange(easedProgress);
|
331 | requestAnimationFrame(function () {
|
332 | update();
|
333 | });
|
334 | };
|
335 | update();
|
336 | };
|
337 | Zoom.prototype._doXPan = function (ev) {
|
338 | var direction = ev.direction,
|
339 | deltaX = ev.deltaX;
|
340 | if (this.props.mode.length === 1 && (direction === 'up' || direction === 'down')) {
|
341 | return this.state.range['x'];
|
342 | }
|
343 | ev.preventDefault && ev.preventDefault();
|
344 | var props = this.props;
|
345 | var coord = props.coord,
|
346 | _a = props.panSensitive,
|
347 | panSensitive = _a === void 0 ? 1 : _a;
|
348 | var coordWidth = coord.width;
|
349 | var ratio = deltaX / coordWidth * panSensitive;
|
350 | var newRange = this._doPan(ratio, 'x');
|
351 | return newRange;
|
352 | };
|
353 | Zoom.prototype._doYPan = function (ev) {
|
354 | var direction = ev.direction,
|
355 | deltaY = ev.deltaY;
|
356 | if (this.props.mode.length === 1 && (direction === 'left' || direction === 'right')) {
|
357 | return this.state.range['y'];
|
358 | }
|
359 | ev.preventDefault && ev.preventDefault();
|
360 | var props = this.props;
|
361 | var coord = props.coord,
|
362 | _a = props.panSensitive,
|
363 | panSensitive = _a === void 0 ? 1 : _a;
|
364 | var coordHeight = coord.height;
|
365 | var ratio = -deltaY / coordHeight * panSensitive;
|
366 | var newRange = this._doPan(ratio, 'y');
|
367 | return newRange;
|
368 | };
|
369 | Zoom.prototype._doPan = function (ratio, dim) {
|
370 | var startRange = this.startRange;
|
371 | var _a = startRange[dim],
|
372 | start = _a[0],
|
373 | end = _a[1];
|
374 | var rangeLen = end - start;
|
375 | var rangeOffset = rangeLen * ratio;
|
376 | var newStart = start - rangeOffset;
|
377 | var newEnd = end - rangeOffset;
|
378 | var newRange = this.updateRange([newStart, newEnd], dim);
|
379 | return newRange;
|
380 | };
|
381 | Zoom.prototype._doXPinch = function (ev) {
|
382 | ev.preventDefault && ev.preventDefault();
|
383 | var zoom = ev.zoom,
|
384 | center = ev.center;
|
385 | var props = this.props;
|
386 | var coord = props.coord;
|
387 | var coordWidth = coord.width,
|
388 | left = coord.left,
|
389 | right = coord.right;
|
390 | var leftLen = Math.abs(center.x - left);
|
391 | var rightLen = Math.abs(right - center.x);
|
392 |
|
393 | var leftZoom = leftLen / coordWidth;
|
394 | var rightZoom = rightLen / coordWidth;
|
395 | var newRange = this._doPinch(leftZoom, rightZoom, zoom, 'x');
|
396 | return newRange;
|
397 | };
|
398 | Zoom.prototype._doYPinch = function (ev) {
|
399 | ev.preventDefault && ev.preventDefault();
|
400 | var zoom = ev.zoom,
|
401 | center = ev.center;
|
402 | var props = this.props;
|
403 | var coord = props.coord;
|
404 | var coordHeight = coord.height,
|
405 | top = coord.top,
|
406 | bottom = coord.bottom;
|
407 | var topLen = Math.abs(center.y - top);
|
408 | var bottomLen = Math.abs(bottom - center.y);
|
409 |
|
410 | var topZoom = topLen / coordHeight;
|
411 | var bottomZoom = bottomLen / coordHeight;
|
412 | var newRange = this._doPinch(topZoom, bottomZoom, zoom, 'y');
|
413 | return newRange;
|
414 | };
|
415 | Zoom.prototype._doPinch = function (startRatio, endRatio, zoom, dim) {
|
416 | var _a = this,
|
417 | startRange = _a.startRange,
|
418 | minScale = _a.minScale,
|
419 | props = _a.props;
|
420 | var _b = props.pinchSensitive,
|
421 | pinchSensitive = _b === void 0 ? 1 : _b;
|
422 | var _c = startRange[dim],
|
423 | start = _c[0],
|
424 | end = _c[1];
|
425 | var zoomOffset = zoom < 1 ? (1 / zoom - 1) * pinchSensitive : (1 - zoom) * pinchSensitive;
|
426 | var rangeLen = end - start;
|
427 | var rangeOffset = rangeLen * zoomOffset;
|
428 | var startOffset = rangeOffset * startRatio;
|
429 | var endOffset = rangeOffset * endRatio;
|
430 | var newStart = Math.max(0, start - startOffset);
|
431 | var newEnd = Math.min(1, end + endOffset);
|
432 | var newRange = [newStart, newEnd];
|
433 |
|
434 | if (newEnd - newStart < minScale) {
|
435 | return this.state.range[dim];
|
436 | }
|
437 | return this.updateRange(newRange, dim);
|
438 | };
|
439 | Zoom.prototype.updateRange = function (originalRange, dim) {
|
440 | if (!originalRange) return;
|
441 | var start = originalRange[0],
|
442 | end = originalRange[1];
|
443 | var rangeLength = end - start;
|
444 |
|
445 | var newRange;
|
446 | if (start < 0) {
|
447 | newRange = [0, rangeLength];
|
448 | } else if (end > 1) {
|
449 | newRange = [1 - rangeLength, 1];
|
450 | } else {
|
451 | newRange = originalRange;
|
452 | }
|
453 | var _a = this,
|
454 | props = _a.props,
|
455 | scale = _a.scale,
|
456 | originScale = _a.originScale,
|
457 | state = _a.state;
|
458 | var data = props.data,
|
459 | autoFit = props.autoFit;
|
460 | var range = state.range;
|
461 | if (range && isEqualRange(newRange, range[dim])) return newRange;
|
462 |
|
463 | updateRange(scale[dim], originScale[dim], newRange);
|
464 | if (autoFit) {
|
465 | var followScale = this._getFollowScales(dim);
|
466 | this.updateFollow(followScale, scale[dim], data);
|
467 | }
|
468 | return newRange;
|
469 | };
|
470 | Zoom.prototype.updateFollow = function (scales, mainScale, data) {
|
471 | updateFollow(scales, mainScale, data);
|
472 | };
|
473 | Zoom.prototype._getScale = function (dim) {
|
474 | var _a = this.props,
|
475 | coord = _a.coord,
|
476 | chart = _a.chart;
|
477 | if (dim === 'x') {
|
478 | return coord.transposed ? chart.getYScales()[0] : chart.getXScales()[0];
|
479 | } else {
|
480 | return coord.transposed ? chart.getXScales()[0] : chart.getYScales()[0];
|
481 | }
|
482 | };
|
483 | Zoom.prototype._getFollowScales = function (dim) {
|
484 | var _a = this.props,
|
485 | coord = _a.coord,
|
486 | chart = _a.chart;
|
487 | if (dim === 'x') {
|
488 | return coord.transposed ? chart.getXScales() : chart.getYScales();
|
489 | }
|
490 | if (dim === 'y') {
|
491 | return coord.transposed ? chart.getYScales() : chart.getXScales();
|
492 | }
|
493 | };
|
494 | Zoom.prototype.renderRange = function (range) {
|
495 | var _a = this,
|
496 | state = _a.state,
|
497 | props = _a.props;
|
498 | if (isEqualRange(range, state.range)) return;
|
499 | var chart = props.chart;
|
500 |
|
501 | var animate = chart.animate;
|
502 | chart.setAnimate(false);
|
503 |
|
504 | state.range = range;
|
505 | chart.forceUpdate(function () {
|
506 | chart.setAnimate(animate);
|
507 | });
|
508 | };
|
509 | Zoom.prototype.render = function () {
|
510 | return jsx(View, __assign({}, this.props, this.state));
|
511 | };
|
512 | return Zoom;
|
513 | }(Component);
|
514 | }); |
\ | No newline at end of file |