nested.html 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217
  1. <!DOCTYPE html>
  2. <html>
  3. <head lang="en">
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
  6. <meta name="msapplication-tap-highlight" content="no"/>
  7. <link rel="stylesheet" href="assets/style.css">
  8. <title>Hammer.js</title>
  9. <style>
  10. .container {
  11. max-width: 900px;
  12. margin: 0 auto;
  13. }
  14. .panes.wrapper {
  15. max-height: 400px;
  16. max-width: 800px;
  17. background: #666;
  18. margin: 40px auto;
  19. }
  20. .panes {
  21. width: 100%;
  22. height: 100%;
  23. overflow: hidden;
  24. position: relative;
  25. }
  26. .pane {
  27. width: 100%;
  28. height: 100%;
  29. position: absolute;
  30. left: 0;
  31. top: 0;
  32. text-align: center;
  33. font: bold 60px/250px 'Open Sans', Helvetica, Arial, sans-serif;
  34. color: #fff;
  35. }
  36. .panes.animate > .pane {
  37. transition: all .3s;
  38. -webkit-transition: all .3s;
  39. }
  40. </style>
  41. </head>
  42. <body>
  43. <div class="panes wrapper">
  44. <div class="pane bg1">
  45. <div class="panes">
  46. <div class="pane" style="background: rgba(0,0,0,0);">1.1</div>
  47. <div class="pane" style="background: rgba(0,0,0,.2);">1.2</div>
  48. <div class="pane" style="background: rgba(0,0,0,.4);">1.3</div>
  49. <div class="pane" style="background: rgba(0,0,0,.6);">1.4</div>
  50. <div class="pane" style="background: rgba(0,0,0,.8);">1.5</div>
  51. </div>
  52. </div>
  53. <div class="pane bg2">
  54. <div class="panes">
  55. <div class="pane" style="background: rgba(0,0,0,0);">2.1</div>
  56. <div class="pane" style="background: rgba(0,0,0,.2);">2.2</div>
  57. <div class="pane" style="background: rgba(0,0,0,.4);">2.3</div>
  58. <div class="pane" style="background: rgba(0,0,0,.6);">2.4</div>
  59. <div class="pane" style="background: rgba(0,0,0,.8);">2.5</div>
  60. </div>
  61. </div>
  62. <div class="pane bg3">
  63. <div class="panes">
  64. <div class="pane" style="background: rgba(0,0,0,0);">3.1</div>
  65. <div class="pane" style="background: rgba(0,0,0,.2);">3.2</div>
  66. <div class="pane" style="background: rgba(0,0,0,.4);">3.3</div>
  67. <div class="pane" style="background: rgba(0,0,0,.6);">3.4</div>
  68. <div class="pane" style="background: rgba(0,0,0,.8);">3.5</div>
  69. </div>
  70. </div>
  71. <div class="pane bg4">
  72. <div class="panes">
  73. <div class="pane" style="background: rgba(0,0,0,0);">4.1</div>
  74. <div class="pane" style="background: rgba(0,0,0,.2);">4.2</div>
  75. <div class="pane" style="background: rgba(0,0,0,.4);">4.3</div>
  76. <div class="pane" style="background: rgba(0,0,0,.6);">4.4</div>
  77. <div class="pane" style="background: rgba(0,0,0,.8);">4.5</div>
  78. </div>
  79. </div>
  80. <div class="pane bg5">
  81. <div class="panes">
  82. <div class="pane" style="background: rgba(0,0,0,0);">5.1</div>
  83. <div class="pane" style="background: rgba(0,0,0,.2);">5.2</div>
  84. <div class="pane" style="background: rgba(0,0,0,.4);">5.3</div>
  85. <div class="pane" style="background: rgba(0,0,0,.6);">5.4</div>
  86. <div class="pane" style="background: rgba(0,0,0,.8);">5.5</div>
  87. </div>
  88. </div>
  89. </div>
  90. <div class="container">
  91. <h1>Nested Pan recognizers</h1>
  92. <p>Nested recognizers are possible with some threshold and with use of <code>requireFailure()</code>.</p>
  93. </div>
  94. <script src="../../hammer.js"></script>
  95. <script>
  96. var reqAnimationFrame = (function() {
  97. return window[Hammer.prefixed(window, "requestAnimationFrame")] || function(callback) {
  98. setTimeout(callback, 1000 / 60);
  99. }
  100. })();
  101. function dirProp(direction, hProp, vProp) {
  102. return (direction & Hammer.DIRECTION_HORIZONTAL) ? hProp : vProp
  103. }
  104. /**
  105. * Carousel
  106. * @param container
  107. * @param direction
  108. * @constructor
  109. */
  110. function HammerCarousel(container, direction) {
  111. this.container = container;
  112. this.direction = direction;
  113. this.panes = Array.prototype.slice.call(this.container.children, 0);
  114. this.containerSize = this.container[dirProp(direction, 'offsetWidth', 'offsetHeight')];
  115. this.currentIndex = 0;
  116. this.hammer = new Hammer.Manager(this.container);
  117. this.hammer.add(new Hammer.Pan({ direction: this.direction, threshold: 10 }));
  118. this.hammer.on("panstart panmove panend pancancel", Hammer.bindFn(this.onPan, this));
  119. this.show(this.currentIndex);
  120. }
  121. HammerCarousel.prototype = {
  122. /**
  123. * show a pane
  124. * @param {Number} showIndex
  125. * @param {Number} [percent] percentage visible
  126. * @param {Boolean} [animate]
  127. */
  128. show: function(showIndex, percent, animate){
  129. showIndex = Math.max(0, Math.min(showIndex, this.panes.length - 1));
  130. percent = percent || 0;
  131. var className = this.container.className;
  132. if(animate) {
  133. if(className.indexOf('animate') === -1) {
  134. this.container.className += ' animate';
  135. }
  136. } else {
  137. if(className.indexOf('animate') !== -1) {
  138. this.container.className = className.replace('animate', '').trim();
  139. }
  140. }
  141. var paneIndex, pos, translate;
  142. for (paneIndex = 0; paneIndex < this.panes.length; paneIndex++) {
  143. pos = (this.containerSize / 100) * (((paneIndex - showIndex) * 100) + percent);
  144. if(this.direction & Hammer.DIRECTION_HORIZONTAL) {
  145. translate = 'translate3d(' + pos + 'px, 0, 0)';
  146. } else {
  147. translate = 'translate3d(0, ' + pos + 'px, 0)'
  148. }
  149. this.panes[paneIndex].style.transform = translate;
  150. this.panes[paneIndex].style.mozTransform = translate;
  151. this.panes[paneIndex].style.webkitTransform = translate;
  152. }
  153. this.currentIndex = showIndex;
  154. },
  155. /**
  156. * handle pan
  157. * @param {Object} ev
  158. */
  159. onPan : function (ev) {
  160. var delta = dirProp(this.direction, ev.deltaX, ev.deltaY);
  161. var percent = (100 / this.containerSize) * delta;
  162. var animate = false;
  163. if (ev.type == 'panend' || ev.type == 'pancancel') {
  164. if (Math.abs(percent) > 20 && ev.type == 'panend') {
  165. this.currentIndex += (percent < 0) ? 1 : -1;
  166. }
  167. percent = 0;
  168. animate = true;
  169. }
  170. this.show(this.currentIndex, percent, animate);
  171. }
  172. };
  173. // the horizontal pane scroller
  174. var outer = new HammerCarousel(document.querySelector(".panes.wrapper"), Hammer.DIRECTION_HORIZONTAL);
  175. // each pane should contain a vertical pane scroller
  176. Hammer.each(document.querySelectorAll(".pane .panes"), function(container) {
  177. // setup the inner scroller
  178. var inner = new HammerCarousel(container, Hammer.DIRECTION_VERTICAL);
  179. // only recognize the inner pan when the outer is failing.
  180. // they both have a threshold of some px
  181. outer.hammer.get('pan').requireFailure(inner.hammer.get('pan'));
  182. });
  183. </script>
  184. </body>
  185. </html>