1 | "use strict";
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | require('./Animate');
|
18 |
|
19 | var Scroller;
|
20 |
|
21 | (function () {
|
22 | var NOOP = function NOOP() {};
|
23 |
|
24 | |
25 |
|
26 |
|
27 | Scroller = function Scroller(callback, options) {
|
28 |
|
29 | this.__callback = callback;
|
30 |
|
31 | this.options = {
|
32 |
|
33 |
|
34 | scrollingX: true,
|
35 |
|
36 |
|
37 | scrollingY: true,
|
38 |
|
39 |
|
40 | animating: true,
|
41 |
|
42 |
|
43 | animationDuration: 250,
|
44 |
|
45 |
|
46 | bouncing: true,
|
47 |
|
48 |
|
49 | locking: true,
|
50 |
|
51 |
|
52 | paging: false,
|
53 |
|
54 |
|
55 | snapping: false,
|
56 |
|
57 |
|
58 | zooming: false,
|
59 |
|
60 |
|
61 | minZoom: 0.5,
|
62 |
|
63 |
|
64 | maxZoom: 3,
|
65 |
|
66 |
|
67 | speedMultiplier: 1,
|
68 |
|
69 | |
70 |
|
71 |
|
72 | scrollingComplete: NOOP,
|
73 |
|
74 |
|
75 | penetrationDeceleration: 0.03,
|
76 |
|
77 |
|
78 | penetrationAcceleration: 0.08
|
79 |
|
80 | };
|
81 |
|
82 | for (var key in options) {
|
83 | this.options[key] = options[key];
|
84 | }
|
85 | };
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | |
91 |
|
92 |
|
93 | var easeOutCubic = function easeOutCubic(pos) {
|
94 | return Math.pow(pos - 1, 3) + 1;
|
95 | };
|
96 |
|
97 | |
98 |
|
99 |
|
100 | var easeInOutCubic = function easeInOutCubic(pos) {
|
101 | if ((pos /= 0.5) < 1) {
|
102 | return 0.5 * Math.pow(pos, 3);
|
103 | }
|
104 |
|
105 | return 0.5 * (Math.pow(pos - 2, 3) + 2);
|
106 | };
|
107 |
|
108 | var members = {
|
109 |
|
110 | |
111 |
|
112 |
|
113 |
|
114 |
|
115 |
|
116 |
|
117 | __isSingleTouch: false,
|
118 |
|
119 |
|
120 | __isTracking: false,
|
121 |
|
122 |
|
123 | __didDecelerationComplete: false,
|
124 |
|
125 | |
126 |
|
127 |
|
128 |
|
129 | __isGesturing: false,
|
130 |
|
131 | |
132 |
|
133 |
|
134 |
|
135 |
|
136 | __isDragging: false,
|
137 |
|
138 | |
139 |
|
140 |
|
141 |
|
142 | __isDecelerating: false,
|
143 |
|
144 | |
145 |
|
146 |
|
147 | __isAnimating: false,
|
148 |
|
149 | |
150 |
|
151 |
|
152 |
|
153 |
|
154 |
|
155 |
|
156 | __clientLeft: 0,
|
157 |
|
158 |
|
159 | __clientTop: 0,
|
160 |
|
161 |
|
162 | __clientWidth: 0,
|
163 |
|
164 |
|
165 | __clientHeight: 0,
|
166 |
|
167 |
|
168 | __contentWidth: 0,
|
169 |
|
170 |
|
171 | __contentHeight: 0,
|
172 |
|
173 |
|
174 | __snapWidth: 100,
|
175 |
|
176 |
|
177 | __snapHeight: 100,
|
178 |
|
179 |
|
180 | __refreshHeight: null,
|
181 |
|
182 |
|
183 | __refreshActive: false,
|
184 |
|
185 |
|
186 | __refreshActivate: null,
|
187 |
|
188 |
|
189 | __refreshDeactivate: null,
|
190 |
|
191 |
|
192 | __refreshStart: null,
|
193 |
|
194 |
|
195 | __zoomLevel: 1,
|
196 |
|
197 |
|
198 | __scrollLeft: 0,
|
199 |
|
200 |
|
201 | __scrollTop: 0,
|
202 |
|
203 |
|
204 | __maxScrollLeft: 0,
|
205 |
|
206 |
|
207 | __maxScrollTop: 0,
|
208 |
|
209 |
|
210 | __scheduledLeft: 0,
|
211 |
|
212 |
|
213 | __scheduledTop: 0,
|
214 |
|
215 |
|
216 | __scheduledZoom: 0,
|
217 |
|
218 | |
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 | __lastTouchLeft: null,
|
226 |
|
227 |
|
228 | __lastTouchTop: null,
|
229 |
|
230 |
|
231 | __lastTouchMove: null,
|
232 |
|
233 |
|
234 | __positions: null,
|
235 |
|
236 | |
237 |
|
238 |
|
239 |
|
240 |
|
241 |
|
242 |
|
243 | __minDecelerationScrollLeft: null,
|
244 |
|
245 |
|
246 | __minDecelerationScrollTop: null,
|
247 |
|
248 |
|
249 | __maxDecelerationScrollLeft: null,
|
250 |
|
251 |
|
252 | __maxDecelerationScrollTop: null,
|
253 |
|
254 |
|
255 | __decelerationVelocityX: null,
|
256 |
|
257 |
|
258 | __decelerationVelocityY: null,
|
259 |
|
260 | |
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 | |
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 |
|
275 |
|
276 | setDimensions: function setDimensions(clientWidth, clientHeight, contentWidth, contentHeight) {
|
277 |
|
278 | var self = this;
|
279 |
|
280 |
|
281 | if (clientWidth === +clientWidth) {
|
282 | self.__clientWidth = clientWidth;
|
283 | }
|
284 |
|
285 | if (clientHeight === +clientHeight) {
|
286 | self.__clientHeight = clientHeight;
|
287 | }
|
288 |
|
289 | if (contentWidth === +contentWidth) {
|
290 | self.__contentWidth = contentWidth;
|
291 | }
|
292 |
|
293 | if (contentHeight === +contentHeight) {
|
294 | self.__contentHeight = contentHeight;
|
295 | }
|
296 |
|
297 |
|
298 | self.__computeScrollMax();
|
299 |
|
300 |
|
301 | self.scrollTo(self.__scrollLeft, self.__scrollTop, true);
|
302 | },
|
303 |
|
304 | |
305 |
|
306 |
|
307 |
|
308 |
|
309 |
|
310 | setPosition: function setPosition(left, top) {
|
311 |
|
312 | var self = this;
|
313 |
|
314 | self.__clientLeft = left || 0;
|
315 | self.__clientTop = top || 0;
|
316 | },
|
317 |
|
318 | |
319 |
|
320 |
|
321 |
|
322 |
|
323 |
|
324 | setSnapSize: function setSnapSize(width, height) {
|
325 |
|
326 | var self = this;
|
327 |
|
328 | self.__snapWidth = width;
|
329 | self.__snapHeight = height;
|
330 | },
|
331 |
|
332 | |
333 |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 |
|
341 |
|
342 | activatePullToRefresh: function activatePullToRefresh(height, activateCallback, deactivateCallback, startCallback) {
|
343 |
|
344 | var self = this;
|
345 |
|
346 | self.__refreshHeight = height;
|
347 | self.__refreshActivate = activateCallback;
|
348 | self.__refreshDeactivate = deactivateCallback;
|
349 | self.__refreshStart = startCallback;
|
350 | },
|
351 |
|
352 | |
353 |
|
354 |
|
355 | triggerPullToRefresh: function triggerPullToRefresh() {
|
356 |
|
357 |
|
358 | this.__publish(this.__scrollLeft, -this.__refreshHeight, this.__zoomLevel, true);
|
359 |
|
360 | if (this.__refreshStart) {
|
361 | this.__refreshStart();
|
362 | }
|
363 | },
|
364 |
|
365 | |
366 |
|
367 |
|
368 | finishPullToRefresh: function finishPullToRefresh() {
|
369 |
|
370 | var self = this;
|
371 |
|
372 | self.__refreshActive = false;
|
373 | if (self.__refreshDeactivate) {
|
374 | self.__refreshDeactivate();
|
375 | }
|
376 |
|
377 | self.scrollTo(self.__scrollLeft, self.__scrollTop, true);
|
378 | },
|
379 |
|
380 | |
381 |
|
382 |
|
383 |
|
384 |
|
385 | getValues: function getValues() {
|
386 |
|
387 | var self = this;
|
388 |
|
389 | return {
|
390 | left: self.__scrollLeft,
|
391 | top: self.__scrollTop,
|
392 | zoom: self.__zoomLevel
|
393 | };
|
394 | },
|
395 |
|
396 | |
397 |
|
398 |
|
399 |
|
400 |
|
401 | getScrollMax: function getScrollMax() {
|
402 |
|
403 | var self = this;
|
404 |
|
405 | return {
|
406 | left: self.__maxScrollLeft,
|
407 | top: self.__maxScrollTop
|
408 | };
|
409 | },
|
410 |
|
411 | |
412 |
|
413 |
|
414 |
|
415 |
|
416 |
|
417 |
|
418 |
|
419 |
|
420 |
|
421 | zoomTo: function zoomTo(level, animate, originLeft, originTop, callback) {
|
422 |
|
423 | var self = this;
|
424 |
|
425 | if (!self.options.zooming) {
|
426 | throw new Error("Zooming is not enabled!");
|
427 | }
|
428 |
|
429 |
|
430 | if (callback) {
|
431 | self.__zoomComplete = callback;
|
432 | }
|
433 |
|
434 |
|
435 | if (self.__isDecelerating) {
|
436 | core.effect.Animate.stop(self.__isDecelerating);
|
437 | self.__isDecelerating = false;
|
438 | }
|
439 |
|
440 | var oldLevel = self.__zoomLevel;
|
441 |
|
442 |
|
443 | if (originLeft == null) {
|
444 | originLeft = self.__clientWidth / 2;
|
445 | }
|
446 |
|
447 | if (originTop == null) {
|
448 | originTop = self.__clientHeight / 2;
|
449 | }
|
450 |
|
451 |
|
452 | level = Math.max(Math.min(level, self.options.maxZoom), self.options.minZoom);
|
453 |
|
454 |
|
455 | self.__computeScrollMax(level);
|
456 |
|
457 |
|
458 | var left = (originLeft + self.__scrollLeft) * level / oldLevel - originLeft;
|
459 | var top = (originTop + self.__scrollTop) * level / oldLevel - originTop;
|
460 |
|
461 |
|
462 | if (left > self.__maxScrollLeft) {
|
463 | left = self.__maxScrollLeft;
|
464 | } else if (left < 0) {
|
465 | left = 0;
|
466 | }
|
467 |
|
468 |
|
469 | if (top > self.__maxScrollTop) {
|
470 | top = self.__maxScrollTop;
|
471 | } else if (top < 0) {
|
472 | top = 0;
|
473 | }
|
474 |
|
475 |
|
476 | self.__publish(left, top, level, animate);
|
477 | },
|
478 |
|
479 | |
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 | zoomBy: function zoomBy(factor, animate, originLeft, originTop, callback) {
|
489 |
|
490 | var self = this;
|
491 |
|
492 | self.zoomTo(self.__zoomLevel * factor, animate, originLeft, originTop, callback);
|
493 | },
|
494 |
|
495 | |
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
502 |
|
503 | scrollTo: function scrollTo(left, top, animate, zoom) {
|
504 |
|
505 | var self = this;
|
506 |
|
507 |
|
508 | if (self.__isDecelerating) {
|
509 | core.effect.Animate.stop(self.__isDecelerating);
|
510 | self.__isDecelerating = false;
|
511 | }
|
512 |
|
513 |
|
514 | if (zoom != null && zoom !== self.__zoomLevel) {
|
515 |
|
516 | if (!self.options.zooming) {
|
517 | throw new Error("Zooming is not enabled!");
|
518 | }
|
519 |
|
520 | left *= zoom;
|
521 | top *= zoom;
|
522 |
|
523 |
|
524 | self.__computeScrollMax(zoom);
|
525 | } else {
|
526 |
|
527 |
|
528 | zoom = self.__zoomLevel;
|
529 | }
|
530 |
|
531 | if (!self.options.scrollingX) {
|
532 |
|
533 | left = self.__scrollLeft;
|
534 | } else {
|
535 |
|
536 | if (self.options.paging) {
|
537 | left = Math.round(left / self.__clientWidth) * self.__clientWidth;
|
538 | } else if (self.options.snapping) {
|
539 | left = Math.round(left / self.__snapWidth) * self.__snapWidth;
|
540 | }
|
541 | }
|
542 |
|
543 | if (!self.options.scrollingY) {
|
544 |
|
545 | top = self.__scrollTop;
|
546 | } else {
|
547 |
|
548 | if (self.options.paging) {
|
549 | top = Math.round(top / self.__clientHeight) * self.__clientHeight;
|
550 | } else if (self.options.snapping) {
|
551 | top = Math.round(top / self.__snapHeight) * self.__snapHeight;
|
552 | }
|
553 | }
|
554 |
|
555 |
|
556 | left = Math.max(Math.min(self.__maxScrollLeft, left), 0);
|
557 | top = Math.max(Math.min(self.__maxScrollTop, top), 0);
|
558 |
|
559 |
|
560 |
|
561 | if (left === self.__scrollLeft && top === self.__scrollTop) {
|
562 | animate = false;
|
563 | }
|
564 |
|
565 |
|
566 | self.__publish(left, top, zoom, animate);
|
567 | },
|
568 |
|
569 | |
570 |
|
571 |
|
572 |
|
573 |
|
574 |
|
575 |
|
576 | scrollBy: function scrollBy(left, top, animate) {
|
577 |
|
578 | var self = this;
|
579 |
|
580 | var startLeft = self.__isAnimating ? self.__scheduledLeft : self.__scrollLeft;
|
581 | var startTop = self.__isAnimating ? self.__scheduledTop : self.__scrollTop;
|
582 |
|
583 | self.scrollTo(startLeft + (left || 0), startTop + (top || 0), animate);
|
584 | },
|
585 |
|
586 | |
587 |
|
588 |
|
589 |
|
590 |
|
591 |
|
592 | |
593 |
|
594 |
|
595 | doMouseZoom: function doMouseZoom(wheelDelta, timeStamp, pageX, pageY) {
|
596 |
|
597 | var self = this;
|
598 | var change = wheelDelta > 0 ? 0.97 : 1.03;
|
599 |
|
600 | return self.zoomTo(self.__zoomLevel * change, false, pageX - self.__clientLeft, pageY - self.__clientTop);
|
601 | },
|
602 |
|
603 | |
604 |
|
605 |
|
606 | doTouchStart: function doTouchStart(touches, timeStamp) {
|
607 |
|
608 |
|
609 | if (touches.length == null) {
|
610 | throw new Error("Invalid touch list: " + touches);
|
611 | }
|
612 |
|
613 | if (timeStamp instanceof Date) {
|
614 | timeStamp = timeStamp.valueOf();
|
615 | }
|
616 | if (typeof timeStamp !== "number") {
|
617 | throw new Error("Invalid timestamp value: " + timeStamp);
|
618 | }
|
619 |
|
620 | var self = this;
|
621 |
|
622 |
|
623 | self.__interruptedAnimation = true;
|
624 |
|
625 |
|
626 | if (self.__isDecelerating) {
|
627 | core.effect.Animate.stop(self.__isDecelerating);
|
628 | self.__isDecelerating = false;
|
629 | self.__interruptedAnimation = true;
|
630 | }
|
631 |
|
632 |
|
633 | if (self.__isAnimating) {
|
634 | core.effect.Animate.stop(self.__isAnimating);
|
635 | self.__isAnimating = false;
|
636 | self.__interruptedAnimation = true;
|
637 | }
|
638 |
|
639 |
|
640 | var currentTouchLeft, currentTouchTop;
|
641 | var isSingleTouch = touches.length === 1;
|
642 | if (isSingleTouch) {
|
643 | currentTouchLeft = touches[0].pageX;
|
644 | currentTouchTop = touches[0].pageY;
|
645 | } else {
|
646 | currentTouchLeft = Math.abs(touches[0].pageX + touches[1].pageX) / 2;
|
647 | currentTouchTop = Math.abs(touches[0].pageY + touches[1].pageY) / 2;
|
648 | }
|
649 |
|
650 |
|
651 | self.__initialTouchLeft = currentTouchLeft;
|
652 | self.__initialTouchTop = currentTouchTop;
|
653 |
|
654 |
|
655 | self.__zoomLevelStart = self.__zoomLevel;
|
656 |
|
657 |
|
658 | self.__lastTouchLeft = currentTouchLeft;
|
659 | self.__lastTouchTop = currentTouchTop;
|
660 |
|
661 |
|
662 | self.__lastTouchMove = timeStamp;
|
663 |
|
664 |
|
665 | self.__lastScale = 1;
|
666 |
|
667 |
|
668 | self.__enableScrollX = !isSingleTouch && self.options.scrollingX;
|
669 | self.__enableScrollY = !isSingleTouch && self.options.scrollingY;
|
670 |
|
671 |
|
672 | self.__isTracking = true;
|
673 |
|
674 |
|
675 | self.__didDecelerationComplete = false;
|
676 |
|
677 |
|
678 | self.__isDragging = !isSingleTouch;
|
679 |
|
680 |
|
681 | self.__isSingleTouch = isSingleTouch;
|
682 |
|
683 |
|
684 | self.__positions = [];
|
685 | },
|
686 |
|
687 | |
688 |
|
689 |
|
690 | doTouchMove: function doTouchMove(touches, timeStamp, scale) {
|
691 |
|
692 | if (touches.length == null) {
|
693 | throw new Error("Invalid touch list: " + touches);
|
694 | }
|
695 |
|
696 | if (timeStamp instanceof Date) {
|
697 | timeStamp = timeStamp.valueOf();
|
698 | }
|
699 | if (typeof timeStamp !== "number") {
|
700 | throw new Error("Invalid timestamp value: " + timeStamp);
|
701 | }
|
702 |
|
703 | var self = this;
|
704 |
|
705 |
|
706 | if (!self.__isTracking) {
|
707 | return;
|
708 | }
|
709 |
|
710 | var currentTouchLeft, currentTouchTop;
|
711 |
|
712 |
|
713 | if (touches.length === 2) {
|
714 | currentTouchLeft = Math.abs(touches[0].pageX + touches[1].pageX) / 2;
|
715 | currentTouchTop = Math.abs(touches[0].pageY + touches[1].pageY) / 2;
|
716 | } else {
|
717 | currentTouchLeft = touches[0].pageX;
|
718 | currentTouchTop = touches[0].pageY;
|
719 | }
|
720 |
|
721 | var positions = self.__positions;
|
722 |
|
723 |
|
724 | if (self.__isDragging) {
|
725 |
|
726 |
|
727 | var moveX = currentTouchLeft - self.__lastTouchLeft;
|
728 | var moveY = currentTouchTop - self.__lastTouchTop;
|
729 |
|
730 |
|
731 | var scrollLeft = self.__scrollLeft;
|
732 | var scrollTop = self.__scrollTop;
|
733 | var level = self.__zoomLevel;
|
734 |
|
735 |
|
736 | if (scale != null && self.options.zooming) {
|
737 |
|
738 | var oldLevel = level;
|
739 |
|
740 |
|
741 | level = level / self.__lastScale * scale;
|
742 |
|
743 |
|
744 | level = Math.max(Math.min(level, self.options.maxZoom), self.options.minZoom);
|
745 |
|
746 |
|
747 | if (oldLevel !== level) {
|
748 |
|
749 |
|
750 | var currentTouchLeftRel = currentTouchLeft - self.__clientLeft;
|
751 | var currentTouchTopRel = currentTouchTop - self.__clientTop;
|
752 |
|
753 |
|
754 | scrollLeft = (currentTouchLeftRel + scrollLeft) * level / oldLevel - currentTouchLeftRel;
|
755 | scrollTop = (currentTouchTopRel + scrollTop) * level / oldLevel - currentTouchTopRel;
|
756 |
|
757 |
|
758 | self.__computeScrollMax(level);
|
759 | }
|
760 | }
|
761 |
|
762 | if (self.__enableScrollX) {
|
763 |
|
764 | scrollLeft -= moveX * this.options.speedMultiplier;
|
765 | var maxScrollLeft = self.__maxScrollLeft;
|
766 |
|
767 | if (scrollLeft > maxScrollLeft || scrollLeft < 0) {
|
768 |
|
769 |
|
770 | if (self.options.bouncing) {
|
771 |
|
772 | scrollLeft += moveX / 2 * this.options.speedMultiplier;
|
773 | } else if (scrollLeft > maxScrollLeft) {
|
774 |
|
775 | scrollLeft = maxScrollLeft;
|
776 | } else {
|
777 |
|
778 | scrollLeft = 0;
|
779 | }
|
780 | }
|
781 | }
|
782 |
|
783 |
|
784 | if (self.__enableScrollY) {
|
785 |
|
786 | scrollTop -= moveY * this.options.speedMultiplier;
|
787 | var maxScrollTop = self.__maxScrollTop;
|
788 |
|
789 | if (scrollTop > maxScrollTop || scrollTop < 0) {
|
790 |
|
791 |
|
792 | if (self.options.bouncing) {
|
793 |
|
794 | scrollTop += moveY / 2 * this.options.speedMultiplier;
|
795 |
|
796 |
|
797 | if (!self.__enableScrollX && self.__refreshHeight != null) {
|
798 |
|
799 | if (!self.__refreshActive && scrollTop <= -self.__refreshHeight) {
|
800 |
|
801 | self.__refreshActive = true;
|
802 | if (self.__refreshActivate) {
|
803 | self.__refreshActivate();
|
804 | }
|
805 | } else if (self.__refreshActive && scrollTop > -self.__refreshHeight) {
|
806 |
|
807 | self.__refreshActive = false;
|
808 | if (self.__refreshDeactivate) {
|
809 | self.__refreshDeactivate();
|
810 | }
|
811 | }
|
812 | }
|
813 | } else if (scrollTop > maxScrollTop) {
|
814 |
|
815 | scrollTop = maxScrollTop;
|
816 | } else {
|
817 |
|
818 | scrollTop = 0;
|
819 | }
|
820 | }
|
821 | }
|
822 |
|
823 |
|
824 | if (positions.length > 60) {
|
825 | positions.splice(0, 30);
|
826 | }
|
827 |
|
828 |
|
829 | positions.push(scrollLeft, scrollTop, timeStamp);
|
830 |
|
831 |
|
832 | self.__publish(scrollLeft, scrollTop, level);
|
833 |
|
834 |
|
835 | } else {
|
836 |
|
837 | var minimumTrackingForScroll = self.options.locking ? 3 : 0;
|
838 | var minimumTrackingForDrag = 5;
|
839 |
|
840 | var distanceX = Math.abs(currentTouchLeft - self.__initialTouchLeft);
|
841 | var distanceY = Math.abs(currentTouchTop - self.__initialTouchTop);
|
842 |
|
843 | self.__enableScrollX = self.options.scrollingX && distanceX >= minimumTrackingForScroll;
|
844 | self.__enableScrollY = self.options.scrollingY && distanceY >= minimumTrackingForScroll;
|
845 |
|
846 | positions.push(self.__scrollLeft, self.__scrollTop, timeStamp);
|
847 |
|
848 | self.__isDragging = (self.__enableScrollX || self.__enableScrollY) && (distanceX >= minimumTrackingForDrag || distanceY >= minimumTrackingForDrag);
|
849 | if (self.__isDragging) {
|
850 | self.__interruptedAnimation = false;
|
851 | }
|
852 | }
|
853 |
|
854 |
|
855 | self.__lastTouchLeft = currentTouchLeft;
|
856 | self.__lastTouchTop = currentTouchTop;
|
857 | self.__lastTouchMove = timeStamp;
|
858 | self.__lastScale = scale;
|
859 | },
|
860 |
|
861 | |
862 |
|
863 |
|
864 | doTouchEnd: function doTouchEnd(timeStamp) {
|
865 |
|
866 | if (timeStamp instanceof Date) {
|
867 | timeStamp = timeStamp.valueOf();
|
868 | }
|
869 | if (typeof timeStamp !== "number") {
|
870 | throw new Error("Invalid timestamp value: " + timeStamp);
|
871 | }
|
872 |
|
873 | var self = this;
|
874 |
|
875 |
|
876 |
|
877 | if (!self.__isTracking) {
|
878 | return;
|
879 | }
|
880 |
|
881 |
|
882 | self.__isTracking = false;
|
883 |
|
884 |
|
885 |
|
886 | if (self.__isDragging) {
|
887 |
|
888 |
|
889 | self.__isDragging = false;
|
890 |
|
891 |
|
892 |
|
893 | if (self.__isSingleTouch && self.options.animating && timeStamp - self.__lastTouchMove <= 100) {
|
894 |
|
895 |
|
896 | var positions = self.__positions;
|
897 | var endPos = positions.length - 1;
|
898 | var startPos = endPos;
|
899 |
|
900 |
|
901 | for (var i = endPos; i > 0 && positions[i] > self.__lastTouchMove - 100; i -= 3) {
|
902 | startPos = i;
|
903 | }
|
904 |
|
905 |
|
906 |
|
907 | if (startPos !== endPos) {
|
908 |
|
909 |
|
910 | var timeOffset = positions[endPos] - positions[startPos];
|
911 | var movedLeft = self.__scrollLeft - positions[startPos - 2];
|
912 | var movedTop = self.__scrollTop - positions[startPos - 1];
|
913 |
|
914 |
|
915 | self.__decelerationVelocityX = movedLeft / timeOffset * (1000 / 60);
|
916 | self.__decelerationVelocityY = movedTop / timeOffset * (1000 / 60);
|
917 |
|
918 |
|
919 | var minVelocityToStartDeceleration = self.options.paging || self.options.snapping ? 4 : 1;
|
920 |
|
921 |
|
922 | if (Math.abs(self.__decelerationVelocityX) > minVelocityToStartDeceleration || Math.abs(self.__decelerationVelocityY) > minVelocityToStartDeceleration) {
|
923 |
|
924 |
|
925 | if (!self.__refreshActive) {
|
926 | self.__startDeceleration(timeStamp);
|
927 | }
|
928 | }
|
929 | } else {
|
930 | self.options.scrollingComplete();
|
931 | }
|
932 | } else if (timeStamp - self.__lastTouchMove > 100) {
|
933 | self.options.scrollingComplete();
|
934 | }
|
935 | }
|
936 |
|
937 |
|
938 |
|
939 |
|
940 |
|
941 |
|
942 | if (!self.__isDecelerating) {
|
943 |
|
944 | if (self.__refreshActive && self.__refreshStart) {
|
945 |
|
946 |
|
947 |
|
948 | self.__publish(self.__scrollLeft, -self.__refreshHeight, self.__zoomLevel, true);
|
949 |
|
950 | if (self.__refreshStart) {
|
951 | self.__refreshStart();
|
952 | }
|
953 | } else {
|
954 |
|
955 | if (self.__interruptedAnimation || self.__isDragging) {
|
956 | self.options.scrollingComplete();
|
957 | }
|
958 | self.scrollTo(self.__scrollLeft, self.__scrollTop, true, self.__zoomLevel);
|
959 |
|
960 |
|
961 | if (self.__refreshActive) {
|
962 |
|
963 | self.__refreshActive = false;
|
964 | if (self.__refreshDeactivate) {
|
965 | self.__refreshDeactivate();
|
966 | }
|
967 | }
|
968 | }
|
969 | }
|
970 |
|
971 |
|
972 | self.__positions.length = 0;
|
973 | },
|
974 |
|
975 | |
976 |
|
977 |
|
978 |
|
979 |
|
980 |
|
981 | |
982 |
|
983 |
|
984 |
|
985 |
|
986 |
|
987 |
|
988 | __publish: function __publish(left, top, zoom, animate) {
|
989 |
|
990 | var self = this;
|
991 |
|
992 |
|
993 | var wasAnimating = self.__isAnimating;
|
994 | if (wasAnimating) {
|
995 | core.effect.Animate.stop(wasAnimating);
|
996 | self.__isAnimating = false;
|
997 | }
|
998 |
|
999 | if (animate && self.options.animating) {
|
1000 |
|
1001 |
|
1002 | self.__scheduledLeft = left;
|
1003 | self.__scheduledTop = top;
|
1004 | self.__scheduledZoom = zoom;
|
1005 |
|
1006 | var oldLeft = self.__scrollLeft;
|
1007 | var oldTop = self.__scrollTop;
|
1008 | var oldZoom = self.__zoomLevel;
|
1009 |
|
1010 | var diffLeft = left - oldLeft;
|
1011 | var diffTop = top - oldTop;
|
1012 | var diffZoom = zoom - oldZoom;
|
1013 |
|
1014 | var step = function step(percent, now, render) {
|
1015 |
|
1016 | if (render) {
|
1017 |
|
1018 | self.__scrollLeft = oldLeft + diffLeft * percent;
|
1019 | self.__scrollTop = oldTop + diffTop * percent;
|
1020 | self.__zoomLevel = oldZoom + diffZoom * percent;
|
1021 |
|
1022 |
|
1023 | if (self.__callback) {
|
1024 | self.__callback(self.__scrollLeft, self.__scrollTop, self.__zoomLevel);
|
1025 | }
|
1026 | }
|
1027 | };
|
1028 |
|
1029 | var verify = function verify(id) {
|
1030 | return self.__isAnimating === id;
|
1031 | };
|
1032 |
|
1033 | var completed = function completed(renderedFramesPerSecond, animationId, wasFinished) {
|
1034 | if (animationId === self.__isAnimating) {
|
1035 | self.__isAnimating = false;
|
1036 | }
|
1037 | if (self.__didDecelerationComplete || wasFinished) {
|
1038 | self.options.scrollingComplete();
|
1039 | }
|
1040 |
|
1041 | if (self.options.zooming) {
|
1042 | self.__computeScrollMax();
|
1043 | if (self.__zoomComplete) {
|
1044 | self.__zoomComplete();
|
1045 | self.__zoomComplete = null;
|
1046 | }
|
1047 | }
|
1048 | };
|
1049 |
|
1050 |
|
1051 | self.__isAnimating = core.effect.Animate.start(step, verify, completed, self.options.animationDuration, wasAnimating ? easeOutCubic : easeInOutCubic);
|
1052 | } else {
|
1053 |
|
1054 | self.__scheduledLeft = self.__scrollLeft = left;
|
1055 | self.__scheduledTop = self.__scrollTop = top;
|
1056 | self.__scheduledZoom = self.__zoomLevel = zoom;
|
1057 |
|
1058 |
|
1059 | if (self.__callback) {
|
1060 | self.__callback(left, top, zoom);
|
1061 | }
|
1062 |
|
1063 |
|
1064 | if (self.options.zooming) {
|
1065 | self.__computeScrollMax();
|
1066 | if (self.__zoomComplete) {
|
1067 | self.__zoomComplete();
|
1068 | self.__zoomComplete = null;
|
1069 | }
|
1070 | }
|
1071 | }
|
1072 | },
|
1073 |
|
1074 | |
1075 |
|
1076 |
|
1077 | __computeScrollMax: function __computeScrollMax(zoomLevel) {
|
1078 |
|
1079 | var self = this;
|
1080 |
|
1081 | if (zoomLevel == null) {
|
1082 | zoomLevel = self.__zoomLevel;
|
1083 | }
|
1084 |
|
1085 | self.__maxScrollLeft = Math.max(self.__contentWidth * zoomLevel - self.__clientWidth, 0);
|
1086 | self.__maxScrollTop = Math.max(self.__contentHeight * zoomLevel - self.__clientHeight, 0);
|
1087 | },
|
1088 |
|
1089 | |
1090 |
|
1091 |
|
1092 |
|
1093 |
|
1094 |
|
1095 | |
1096 |
|
1097 |
|
1098 |
|
1099 | __startDeceleration: function __startDeceleration(timeStamp) {
|
1100 |
|
1101 | var self = this;
|
1102 |
|
1103 | if (self.options.paging) {
|
1104 |
|
1105 | var scrollLeft = Math.max(Math.min(self.__scrollLeft, self.__maxScrollLeft), 0);
|
1106 | var scrollTop = Math.max(Math.min(self.__scrollTop, self.__maxScrollTop), 0);
|
1107 | var clientWidth = self.__clientWidth;
|
1108 | var clientHeight = self.__clientHeight;
|
1109 |
|
1110 |
|
1111 |
|
1112 | self.__minDecelerationScrollLeft = Math.floor(scrollLeft / clientWidth) * clientWidth;
|
1113 | self.__minDecelerationScrollTop = Math.floor(scrollTop / clientHeight) * clientHeight;
|
1114 | self.__maxDecelerationScrollLeft = Math.ceil(scrollLeft / clientWidth) * clientWidth;
|
1115 | self.__maxDecelerationScrollTop = Math.ceil(scrollTop / clientHeight) * clientHeight;
|
1116 | } else {
|
1117 |
|
1118 | self.__minDecelerationScrollLeft = 0;
|
1119 | self.__minDecelerationScrollTop = 0;
|
1120 | self.__maxDecelerationScrollLeft = self.__maxScrollLeft;
|
1121 | self.__maxDecelerationScrollTop = self.__maxScrollTop;
|
1122 | }
|
1123 |
|
1124 |
|
1125 | var step = function step(percent, now, render) {
|
1126 | self.__stepThroughDeceleration(render);
|
1127 | };
|
1128 |
|
1129 |
|
1130 | var minVelocityToKeepDecelerating = self.options.snapping ? 4 : 0.1;
|
1131 |
|
1132 |
|
1133 |
|
1134 | var verify = function verify() {
|
1135 | var shouldContinue = Math.abs(self.__decelerationVelocityX) >= minVelocityToKeepDecelerating || Math.abs(self.__decelerationVelocityY) >= minVelocityToKeepDecelerating;
|
1136 | if (!shouldContinue) {
|
1137 | self.__didDecelerationComplete = true;
|
1138 | }
|
1139 | return shouldContinue;
|
1140 | };
|
1141 |
|
1142 | var completed = function completed(renderedFramesPerSecond, animationId, wasFinished) {
|
1143 | self.__isDecelerating = false;
|
1144 | if (self.__didDecelerationComplete) {
|
1145 | self.options.scrollingComplete();
|
1146 | }
|
1147 |
|
1148 |
|
1149 | self.scrollTo(self.__scrollLeft, self.__scrollTop, self.options.snapping);
|
1150 | };
|
1151 |
|
1152 |
|
1153 | self.__isDecelerating = core.effect.Animate.start(step, verify, completed);
|
1154 | },
|
1155 |
|
1156 | |
1157 |
|
1158 |
|
1159 |
|
1160 |
|
1161 | __stepThroughDeceleration: function __stepThroughDeceleration(render) {
|
1162 |
|
1163 | var self = this;
|
1164 |
|
1165 |
|
1166 |
|
1167 |
|
1168 |
|
1169 |
|
1170 | var scrollLeft = self.__scrollLeft + self.__decelerationVelocityX;
|
1171 | var scrollTop = self.__scrollTop + self.__decelerationVelocityY;
|
1172 |
|
1173 |
|
1174 |
|
1175 |
|
1176 |
|
1177 | if (!self.options.bouncing) {
|
1178 |
|
1179 | var scrollLeftFixed = Math.max(Math.min(self.__maxDecelerationScrollLeft, scrollLeft), self.__minDecelerationScrollLeft);
|
1180 | if (scrollLeftFixed !== scrollLeft) {
|
1181 | scrollLeft = scrollLeftFixed;
|
1182 | self.__decelerationVelocityX = 0;
|
1183 | }
|
1184 |
|
1185 | var scrollTopFixed = Math.max(Math.min(self.__maxDecelerationScrollTop, scrollTop), self.__minDecelerationScrollTop);
|
1186 | if (scrollTopFixed !== scrollTop) {
|
1187 | scrollTop = scrollTopFixed;
|
1188 | self.__decelerationVelocityY = 0;
|
1189 | }
|
1190 | }
|
1191 |
|
1192 |
|
1193 |
|
1194 |
|
1195 |
|
1196 | if (render) {
|
1197 |
|
1198 | self.__publish(scrollLeft, scrollTop, self.__zoomLevel);
|
1199 | } else {
|
1200 |
|
1201 | self.__scrollLeft = scrollLeft;
|
1202 | self.__scrollTop = scrollTop;
|
1203 | }
|
1204 |
|
1205 |
|
1206 |
|
1207 |
|
1208 |
|
1209 |
|
1210 | if (!self.options.paging) {
|
1211 |
|
1212 |
|
1213 |
|
1214 |
|
1215 | var frictionFactor = 0.95;
|
1216 |
|
1217 | self.__decelerationVelocityX *= frictionFactor;
|
1218 | self.__decelerationVelocityY *= frictionFactor;
|
1219 | }
|
1220 |
|
1221 |
|
1222 |
|
1223 |
|
1224 |
|
1225 | if (self.options.bouncing) {
|
1226 |
|
1227 | var scrollOutsideX = 0;
|
1228 | var scrollOutsideY = 0;
|
1229 |
|
1230 |
|
1231 | var penetrationDeceleration = self.options.penetrationDeceleration;
|
1232 | var penetrationAcceleration = self.options.penetrationAcceleration;
|
1233 |
|
1234 |
|
1235 | if (scrollLeft < self.__minDecelerationScrollLeft) {
|
1236 | scrollOutsideX = self.__minDecelerationScrollLeft - scrollLeft;
|
1237 | } else if (scrollLeft > self.__maxDecelerationScrollLeft) {
|
1238 | scrollOutsideX = self.__maxDecelerationScrollLeft - scrollLeft;
|
1239 | }
|
1240 |
|
1241 | if (scrollTop < self.__minDecelerationScrollTop) {
|
1242 | scrollOutsideY = self.__minDecelerationScrollTop - scrollTop;
|
1243 | } else if (scrollTop > self.__maxDecelerationScrollTop) {
|
1244 | scrollOutsideY = self.__maxDecelerationScrollTop - scrollTop;
|
1245 | }
|
1246 |
|
1247 |
|
1248 | if (scrollOutsideX !== 0) {
|
1249 | if (scrollOutsideX * self.__decelerationVelocityX <= 0) {
|
1250 | self.__decelerationVelocityX += scrollOutsideX * penetrationDeceleration;
|
1251 | } else {
|
1252 | self.__decelerationVelocityX = scrollOutsideX * penetrationAcceleration;
|
1253 | }
|
1254 | }
|
1255 |
|
1256 | if (scrollOutsideY !== 0) {
|
1257 | if (scrollOutsideY * self.__decelerationVelocityY <= 0) {
|
1258 | self.__decelerationVelocityY += scrollOutsideY * penetrationDeceleration;
|
1259 | } else {
|
1260 | self.__decelerationVelocityY = scrollOutsideY * penetrationAcceleration;
|
1261 | }
|
1262 | }
|
1263 | }
|
1264 | }
|
1265 | };
|
1266 |
|
1267 |
|
1268 | for (var key in members) {
|
1269 | Scroller.prototype[key] = members[key];
|
1270 | }
|
1271 | })();
|
1272 |
|
1273 | module.exports = Scroller; |
\ | No newline at end of file |