From 755d3c7316c3c16d5f78c8e4f805bf4f9209c7ef Mon Sep 17 00:00:00 2001 From: Julien Bouquillon Date: Mon, 13 Oct 2014 04:52:02 +0200 Subject: [PATCH] refactor(carousel): transitions refactor : - single slide based transitions - externalize some services - use shifty.js for transitions - fix bunch of issues --- README.md | 39 +- TODO | 38 - bower.json | 2 +- demo/demo.css | 120 +- dist/angular-carousel.css | 97 +- dist/angular-carousel.js | 2298 +++++++++++++++++----- dist/angular-carousel.min.css | 2 +- dist/angular-carousel.min.js | 4 +- index.html | 267 +-- package.json | 2 +- src/angular-carousel.js | 3 +- src/css/angular-carousel.scss | 103 +- src/directives/rn-carousel-controls.js | 30 - src/directives/rn-carousel-indicators.js | 19 +- src/directives/rn-carousel.js | 866 ++++---- src/directives/shifty.js | 1383 +++++++++++++ 16 files changed, 3943 insertions(+), 1330 deletions(-) delete mode 100644 TODO delete mode 100755 src/directives/rn-carousel-controls.js create mode 100644 src/directives/shifty.js diff --git a/README.md b/README.md index f42df8e..c1b1af1 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,6 @@ Comments and contributions welcome :) Proudly brought to you by the [@revolunet](http://twitter.com/revolunet) team. -**NOTE :** if you use IE<=9, iOS<7 or Android<4 please include the [requestAnimationFrame polyfill](https://github.com/darius/requestAnimationFrame/blob/master/requestAnimationFrame.js) in your application. ## Usage : @@ -28,7 +27,7 @@ angular.module('MyApp', ['angular-carousel']); - Add a `rn-carousel` attribute to your ` ``` +## Directive options : + - `rn-carousel-index` two way binding to control the carousel position (0-indexed) + - `rn-carousel-buffered` add this attribute to enable the carousel buffering, good to minimize the DOM (5 slides) + - `rn-carousel-controls` add this attribute to enable builtin prev/next buttons (you can override by CSS) + - `rn-carousel-auto-slide` add this attribute to make the carousel slide automatically after given seconds (default=3) + - `rn-carousel-transition` : transition type, can be one of `slide,zoom,hexagon,none,slideAndFade`. (default=slide) +## Indicators -## Features : - - Mobile friendly, tested on webkit+firefox - - Use CSS 3D transformations and `requestAnimationFrame`. (fallback to CSS 2D if 3D support not available) - - DOM buffering - - Index data-binding - - Optional indicators +You can add position indicators by adding this directive where you want : +```html +
+``` + - `slides` is the same collection you use in the carousel ng-repeat + - `carouselIndex` is the same index you've defined for the carousel -### Regular carousel : - - `rn-carousel-index` two way binding to control the carousel position. - - `rn-carousel-indicator` boolean value to enable the indicator, see demo page. - - `rn-carousel-buffered` boolean value to enable the carousel buffering, good to minimize the DOM, defaults to 5 slides. (works only with arrays) - - `rn-carousel-swipe` boolean value to enable/disable swiping (default true) - - `rn-carousel-control` boolean value to enable builtin prev/next buttons (you can override by CSS) - - `rn-carousel-auto-slide` integer value will make the slider automatically change the visible slide after given seconds - - `rn-carousel-pause-on-hover="true"` prevent auto-slide on hover - - `rn-carousel-prevent-animation="true"` if you dont want animations +## Notes : + - if you use IE<=9, iOS<7 or Android<4 please include the [requestAnimationFrame polyfill](https://github.com/darius/requestAnimationFrame/blob/master/requestAnimationFrame.js) in your application. + - don't set any style attribute to your li's. they would be overwritten by the carousel (use classes instead). + - angular-carousel use the great [shifty.js](https://github.com/jeremyckahn/shifty) for the animations ## Todo : - - see the [TODO file](./TODO) + - customisable transitions + - more transition types + - infinite loop support ## Contributing - Please follow [AngularJS GIT conventions](https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit#) diff --git a/TODO b/TODO deleted file mode 100644 index e95331f..0000000 --- a/TODO +++ /dev/null @@ -1,38 +0,0 @@ - - -Carousel v2: - Base features: - ✔ basic ngRepeat @done (14-01-04 20:22) - ✔ ngRepeat with filter @done (14-01-04 20:54) - ✔ ngRepeat with filter and track by @done (14-01-04 20:59) - ✔ template based only @done (14-01-04 20:22) - Bindings: - ✔ should have a carousel-index binding @done (14-01-04 20:22) - Buffering: - ✔ should optionnaly buffer the carousel DOM @done (14-01-04 20:22) - Indicators: - ✔ should have optional indicators @done (14-01-05 01:56) - ✔ indicators should be clickable @done (14-01-05 01:56) - ☐ indicators should be customizable - Animations: - ☐ should have some builtin animations - ☐ should be able to customise animations - ☐ animation should occur on individual slides instead of container - ☐ use % instead of pixels - Bugs: - ✔ bug when rn-carousel-index change while animation from outside @done (14-01-05 02:19) - ☐ handle touch cancel - ✔ initial index position not respected @done (14-01-07 23:51) - Advanced: - ☐ optional loop - ☐ infinite carousels with slide generators (prev/next+load) - ✔ optional auto-slide @done (14-07-24 23:35) - Tests: - ✔ setup karma @done (14-01-05 00:15) - Tooling: - ✔ update grunt @done (14-01-04 22:09) - ✔ add autoprefixer @done (14-01-04 22:09) - ☐ template with code samples for the demo page - ☐ automate version bump - Docs: - ✔ README update @done (14-01-05 02:19) diff --git a/bower.json b/bower.json index ed277db..0215d2e 100644 --- a/bower.json +++ b/bower.json @@ -1,7 +1,7 @@ { "name": "angular-carousel", "description": "Angular Carousel - Mobile friendly touch carousel for AngularJS", - "version": "0.2.5", + "version": "0.3.0", "homepage": "http://revolunet.github.com/angular-carousel", "author": "Julien Bouquillon ", "repository": { diff --git a/demo/demo.css b/demo/demo.css index 16cb5a4..58c3766 100644 --- a/demo/demo.css +++ b/demo/demo.css @@ -22,110 +22,42 @@ h3 { font-size:30px; margin: 30px 0 10px 0; } -.my-slider { - width: 450px; - height: 300px; - font-size:0; -} -.my-slider li { - box-sizing: border-box; - font-size:30px; - position:relative; + +.center { + text-align: center; } -.my-slider li div.debug { - box-sizing: border-box; - position:absolute; - bottom:0; - height:50px; - background:rgba(0,0,0,0.7); +.bgimage { + text-align:right; color:white; - font-size:12px; - width:100%; - padding:5px; + background-size:cover; + height: 100%; } -.my-slider.standard li { - text-align:center; - padding:20px; - font-size:20px; + +ul[rn-carousel] { + width:400px; + height:200px; + margin: 0 auto; } -.big { - margin-top:30px; + +.carousel5 li { width:100%; + height:100%; font-size:30px; + background-color: #ccc; } -.controls { - margin-top:5px; - width:450px; + +div.carousel-demo { + margin-top:20px; + display:inline-block; text-align: center; } -.ng-cloak { - display:none; -} -.center { - text-align:center; -} -.thumbs { - width:450px; + +input.tiny { + width:50px; text-align:center; } -.thumb { - display: inline-block; - background-size:cover; - border:1px solid transparent; - margin:2px 4px; - width:60px; - height:40px; - transition: border 0.2s ease-in; -} -.is-active { - border:1px solid red; -} -.details { - color:white; - font-size:12px; - margin-bottom:10px; -} -.button{ - display: inline-block; - text-decoration: none; - font: bold 12px/12px HelveticaNeue, Arial; - padding: 8px 11px; - color: #555; - border: 1px solid #dedede; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - cursor:pointer; -} -.button:disabled { - cursor: default !important; - color: #aaa !important; -} -.button.grey{ - background: #bdbdbd; - background: -webkit-gradient(linear, left top, left bottom, from(#cacaca), to(#aeaeae)); /* WebKit */ - background: -moz-linear-gradient(top, #cacaca, #aeaeae); - border-color: #b5b5b5 #a1a1a1 #8f8f8f; - color: #555; - text-shadow: 0 1px 0 #d4d4d4; -} -.button.grey:hover{ - background: #c2c2c2; - background: -webkit-gradient(linear, left top, left bottom, from(#bcbcbc), to(#c2c2c2)); /* WebKit */ - background: -moz-linear-gradient(top, #bcbcbc, #c2c2c2); - border-color: #989898 #8e8e8e #878787; - text-shadow: 0 1px 0 #dadada; -} -/* override default controls */ -.rn-carousel-control { - font-size:50px !important; - color:white; - opacity: 1; -} -.rn-carousel-control.rn-carousel-control-prev { - left: 5px; -} -.rn-carousel-control.rn-carousel-control-next { - right: 5px; + +ul[rn-carousel-transition="hexagon"] { + margin-left:100px; } diff --git a/dist/angular-carousel.css b/dist/angular-carousel.css index 9461d9e..80c3978 100755 --- a/dist/angular-carousel.css +++ b/dist/angular-carousel.css @@ -1,73 +1,58 @@ -/* variables */ -/* general */ -.rn-carousel-container { +body { + background: #ccc; } + +input[type=range] { + width: 300px; } + +ul[rn-carousel] { overflow: hidden; + padding: 0; + white-space: nowrap; position: relative; + -webkit-perspective: 1000px; + -ms-perspective: 1000px; + perspective: 1000px; -ms-touch-action: none; touch-action: none; } + ul[rn-carousel] li { + color: black; + -webkit-backface-visibility: hidden; + -ms-backface-visibility: hidden; + backface-visibility: hidden; + overflow: visible; + vertical-align: top; + position: absolute; + left: 0; + right: 0; + white-space: normal; + padding: 0; + margin: 0; + list-style-type: none; + width: 100%; + height: 100%; + display: inline-block; } -.rn-carousel-slides { - -webkit-transform: translate3d(0, 0, 0); - -ms-transform: translate3d(0, 0, 0); - transform: translate3d(0, 0, 0); - position: relative; - white-space: nowrap; - overflow: visible; - padding: 0; - margin: 0; } +/* prevent flickering when moving buffer */ +ul[rn-carousel-buffered] li { + display: none; } -/* IE 9 */ -:root .rn-carousel-slides { - -webkit-transform: translate(0, 0); - -ms-transform: translate(0, 0); - transform: translate(0, 0); - position: relative; - white-space: nowrap; - overflow: visible; - padding: 0; - margin: 0; } - -.rn-carousel-slide { - white-space: normal; - vertical-align: top; - display: inline-block; - width: 100%; - height: 100%; - -webkit-backface-visibility: hidden; - -ms-backface-visibility: hidden; - backface-visibility: hidden; } +ul[rn-carousel-transition="hexagon"] { + overflow: visible; } /* indicators */ -.rn-carousel-indicator { - width: 100%; - text-align: center; - height: 20px; - background-color: black; - background-color: rgba(0, 0, 0, 0.6); - position: relative; - bottom: 0; - cursor: pointer; } - .rn-carousel-indicator span { - -webkit-transition: color .2s ease-out; - transition: color .2s ease-out; - padding: 0 5px; - color: #333; } - .rn-carousel-indicator span:before { - content: "\25cf"; } - .rn-carousel-indicator span.ng-leave { - -webkit-transition: none !important; - transition: none !important; } - .rn-carousel-indicator .active { +div[rn-carousel-indicators] span { + cursor: pointer; + color: #666; } + div[rn-carousel-indicators] span.active { color: white; } -/* controls */ +/* prev/next controls */ .rn-carousel-control { -webkit-transition: opacity 0.2s ease-out; transition: opacity 0.2s ease-out; - font-size: 30px; + font-size: 2rem; position: absolute; - top: 50%; - margin-top: -35px; + top: 40%; opacity: 0.75; cursor: pointer; } .rn-carousel-control:hover { diff --git a/dist/angular-carousel.js b/dist/angular-carousel.js index 1bc9173..f08e401 100755 --- a/dist/angular-carousel.js +++ b/dist/angular-carousel.js @@ -1,6 +1,6 @@ /** * Angular Carousel - Mobile friendly touch carousel for AngularJS - * @version v0.2.4 - 2014-07-25 + * @version v0.3.0 - 2014-10-13 * @link http://revolunet.github.com/angular-carousel * @author Julien Bouquillon * @license MIT License, http://www.opensource.org/licenses/MIT @@ -14,7 +14,8 @@ http://github.com/revolunet/angular-carousel */ angular.module('angular-carousel', [ - 'ngTouch' + 'ngTouch', + 'angular-carousel.shifty' ]); angular.module('angular-carousel') @@ -72,52 +73,27 @@ angular.module('angular-carousel') }]); angular.module('angular-carousel') -.directive('rnCarouselControls', [function() { +.directive('rnCarouselIndicators', ['$parse', function($parse) { return { restrict: 'A', - replace: true, scope: { - items: '=', - index: '=' + slides: '=', + index: '=rnCarouselIndex' }, - link: function(scope, element, attrs) { - scope.prev = function() { - if (scope.index > 0) scope.index--; + templateUrl: 'carousel-indicators.html', + link: function(scope, iElement, iAttributes) { + var indexModel = $parse(iAttributes.rnCarouselIndex); + scope.goToSlide = function(index) { + indexModel.assign(scope.$parent.$parent, index); }; - scope.next = function() { - if (scope.index < scope.items.length-1) scope.index++; - }; - }, - templateUrl: 'carousel-controls.html' - }; -}]); - -angular.module('angular-carousel').run(['$templateCache', function($templateCache) { - $templateCache.put('carousel-controls.html', - '' - ); -}]); -angular.module('angular-carousel') - -.directive('rnCarouselIndicators', [function() { - return { - restrict: 'A', - replace: true, - scope: { - items: '=', - index: '=' - }, - templateUrl: 'carousel-indicators.html' + } }; }]); angular.module('angular-carousel').run(['$templateCache', function($templateCache) { $templateCache.put('carousel-indicators.html', - '')}]),angular.module("angular-carousel").directive("rnCarouselIndicators",[function(){return{restrict:"A",replace:!0,scope:{items:"=",index:"="},templateUrl:"carousel-indicators.html"}}]),angular.module("angular-carousel").run(["$templateCache",function(a){a.put("carousel-indicators.html",'')}]),function(){"use strict";angular.module("angular-carousel").directive("rnCarousel",["$swipe","$window","$document","$parse","$compile","$rootScope",function(a,b,c,d,e,f){var g=0,h=75,i=.05,j=3,k=b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame;return{restrict:"A",scope:!0,compile:function(l,m){var n,o,p=l.children()[0].attributes,q=!1,r=!1,s=!1;return l.addClass("rn-carousel-slides"),l.children().addClass("rn-carousel-slide"),["ng-repeat","data-ng-repeat","x-ng-repeat"].every(function(a){var b=p[a];if(angular.isDefined(b)){var c=b.value.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),d=c[3];if(n=c[1],o=c[2],n)return angular.isDefined(m.rnCarouselBuffered)&&(r=!0,b.value=n+" in "+o+"|carouselSlice:carouselBufferIndex:carouselBufferSize",d&&(b.value+=" track by "+d)),q=!0,!1}return!0}),function(l,m,n){function p(){for(var a=[],b=0;Q>b;b++)a[b]=b;l.carouselIndicatorArray=a}function t(){var a=T.children();return I=0===a.length?T[0].getBoundingClientRect().width:a[0].getBoundingClientRect().width}function u(){U.css("width","100%");var a=t();a&&U.css("width",a+"px")}function v(a){isNaN(a)&&(a=l.carouselIndex*I),P=a;var b=-Math.round(P);b+=l.carouselBufferIndex*I,T[0].style[J]=Z?"translate3d("+b+"px, 0, 0)":"translate("+b+"px, 0)"}function w(){var a,b;M&&(a=Date.now()-O,b=M*Math.exp(-a/h),b>j||-j>b?(v(N-b),k(w)):z(N/I))}function x(a){return a>=Q?Q:0>=a?0:a}function y(){var a=0,b=(l.carouselBufferSize-1)/2;r&&(a=l.carouselIndex<=b?0:QQ-l.carouselBufferSize?Q-l.carouselBufferSize:l.carouselIndex-b),l.carouselBufferIndex=a}function z(a,b){return isNaN(a)&&(a=l.carouselIndex),b?(P=a*I,F(null,null,!0),void 0):(l.carouselIndex=x(a),y(),"$apply"!==f.$$phase&&"$digest"!==f.$$phase&&(s?l.$apply():l.$digest()),v(),void 0)}function A(){return i*I}function B(a){R=!0,F({x:a.clientX,y:a.clientY},a)}function C(a){var b=a;return 0===l.carouselIndex?b=Math.max(-A(),b):l.carouselIndex===Q-1&&(b=Math.min((Q-1)*I+A(),b)),b}function D(a){return c.bind("mouseup",B),K=!0,L=a.x,M=0,O=Date.now(),!1}function E(a){var b,c;return K&&(b=a.x,c=L-b,(c>2||-2>c)&&(R=!0,L=b,k(function(){v(C(P+c))}))),!1}function F(a,b,d){if(!b||R){c.unbind("mouseup",B),K=!1,R=!1,N=P;var e=A(),f=l.carouselIndex*I,g=f-N,h=-Math[g>=0?"ceil":"floor"](g/I),i=Math.abs(g)>e;h+l.carouselIndex>=Q&&(h=Q-1-l.carouselIndex),h+l.carouselIndex<0&&(h=-l.carouselIndex);var j=i?h:0;return N=(j+l.carouselIndex)*I,M=N-P,O=Date.now(),d&&(M=P-f),k(w),!1}}function G(){var a,b=document.createElement("p"),c={webkitTransform:"-webkit-transform",msTransform:"-ms-transform",transform:"transform"};document.body.insertBefore(b,null);for(var d in c)void 0!==b.style[d]&&(b.style[d]="translate3d(1px,1px,1px)",a=window.getComputedStyle(b).getPropertyValue(c[d]));return document.body.removeChild(b),void 0!==a&&a.length>0&&"none"!==a}function H(){u(),z()}g++;var I,J,K,L,M,N,O,P=0,Q=0,R=!1,S=!0,T=m.wrap(""),U=T.parent();if((angular.isDefined(n.rnCarouselIndicator)||angular.isDefined(n.rnCarouselControl))&&(p(),l.$watch("carouselIndex",function(a){l.indicatorIndex=a,l.carouselExposedIndex=a}),l.$watch("indicatorIndex",function(a){z(a,!0)})),angular.isDefined(n.rnCarouselPreventAnimation)&&(S=!1),l.$watch("carouselExposedIndex",function(a){z(a,!0)}),angular.isDefined(n.rnCarouselIndicator)){var V=e("")(l);U.append(V)}if(angular.isDefined(n.rnCarouselControl)){var W=e("")(l);U.append(W)}if(l.carouselBufferIndex=0,l.carouselBufferSize=5,l.carouselIndex=0,n.rnCarouselIndex){var X=function(a){Y.assign(l.$parent,a)},Y=d(n.rnCarouselIndex);angular.isFunction(Y.assign)?(l.$watch("carouselIndex",function(a){X(a)}),l.carouselIndex=Y(l),l.$parent.$watch(Y,function(a){void 0!==a&&(a>=Q?(a=Q-1,X(a)):0>a&&(a=0,X(a)),z(a,S))}),s=!0):isNaN(n.rnCarouselIndex)||(l.carouselIndex=parseInt(n.rnCarouselIndex,10))}q?l.$watchCollection(o,function(a){Q=0,angular.isArray(a)?Q=a.length:angular.isObject(a)&&(Q=Object.keys(a).length),p(),I||u(),z(l.carouselIndex)}):(Q=m.children().length,p(),u()),n.$observe("rnCarouselSwipe",function(b){"false"!==b&&"off"!==b?a.bind(T,{start:D,move:E,end:F,cancel:function(a){F({},a)}}):T.unbind()}),s||z(l.carouselIndex),J="transform",["webkit","Moz","O","ms"].every(function(a){var b=a+"Transform";return"undefined"!=typeof document.body.style[b]?(J=b,!1):!0});var Z=G(),$=angular.element(b);$.bind("orientationchange",H),$.bind("resize",H),l.$on("$destroy",function(){c.unbind("mouseup",B),$.unbind("orientationchange",H),$.unbind("resize",H)})}}}}])}(),function(){"use strict";angular.module("angular-carousel").filter("carouselSlice",function(){return function(a,b,c){return angular.isArray(a)?a.slice(b,b+c):angular.isObject(a)?a:void 0}})}(); \ No newline at end of file +angular.module("angular-carousel",["ngTouch","angular-carousel.shifty"]),angular.module("angular-carousel").directive("rnCarouselAutoSlide",["$timeout",function(a){return{restrict:"A",link:function(b,c,d){var e=Math.round(1e3*parseFloat(d.rnCarouselAutoSlide)),f=increment=!1,g=c.children().length;b.carouselExposedIndex||(b.carouselExposedIndex=0),stopAutoplay=function(){angular.isDefined(f)&&a.cancel(f),f=void 0},increment=function(){b.carouselExposedIndex=b.carouselExposedIndex\n')}]),function(){"use strict";angular.module("angular-carousel").service("DeviceCapabilities",function(){function a(){var a="transform";return["webkit","moz","o","ms"].every(function(b){var c="-"+b+"-transform";return"undefined"!=typeof document.body.style[c]?(a=c,!1):!0}),a}function b(){var a,b=document.createElement("p"),c={webkitTransform:"-webkit-transform",msTransform:"-ms-transform",transform:"transform"};document.body.insertBefore(b,null);for(var d in c)void 0!==b.style[d]&&(b.style[d]="translate3d(1px,1px,1px)",a=window.getComputedStyle(b).getPropertyValue(c[d]));return document.body.removeChild(b),void 0!==a&&a.length>0&&"none"!==a}return{has3d:b(),transformProperty:a()}}).service("computeCarouselSlideStyle",function(a){return function(b,c,d){var e,f={display:"inline-block"},g=100*b+c,h=a.has3d?"translate3d("+g+"%, 0, 0)":"translate3d("+g+"%, 0)",i=(100-Math.abs(g))/100;if("fadeAndSlide"==d)f[a.transformProperty]=h,e=0,Math.abs(g)<100&&(e=.3+.7*i),f.opacity=e;else if("hexagon"==d){var j=100,k=0,l=60*(i-1);j=-100*b>c?100:0,k=-100*b>c?l:-l,f[a.transformProperty]=h+" rotateY("+k+"deg)",f["transform-origin"]=j+"% 50%"}else if("zoom"==d){f[a.transformProperty]=h;var m=1;Math.abs(g)<100&&(m=1+2*(1-i)),f[a.transformProperty]+=" scale("+m+")",f["transform-origin"]="50% 50%",e=0,Math.abs(g)<100&&(e=.3+.7*i),f.opacity=e}else f[a.transformProperty]=h;return f}}).service("createStyleString",function(){return function(a){var b=[];return angular.forEach(a,function(a,c){b.push(c+":"+a)}),b.join(";")}}).directive("rnCarousel",["$swipe","$window","$document","$parse","$compile","$timeout","$interval","computeCarouselSlideStyle","createStyleString","Tweenable",function(a,b,c,d,e,f,g,h,i,j){{var k=0,l=.05;b.requestAnimationFrame||b.webkitRequestAnimationFrame||b.mozRequestAnimationFrame}return{restrict:"A",scope:!0,compile:function(m,n){var o,p,q=m[0].querySelector("li").attributes,r=!1,s=!1;return["ng-repeat","data-ng-repeat","ng:repeat","x-ng-repeat"].every(function(a){var b=q[a];if(angular.isDefined(b)){var c=b.value.match(/^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/),d=c[3];if(o=c[1],p=c[2],o)return angular.isDefined(n.rnCarouselBuffered)&&(s=!0,b.value=o+" in "+p+"|carouselSlice:carouselBufferIndex:carouselBufferSize",d&&(b.value+=" track by "+d)),r=!0,!1}return!0}),function(m,n,o){function q(){return n[0].querySelectorAll("li")}function t(a){L=!0,A({x:a.clientX,y:a.clientY},a)}function u(a){var b,c;c=100*m.carouselBufferIndex+a,angular.forEach(q(),function(a,d){b=i(h(d,c,I.transitionType)),a.getAttribute("style")!==b&&a.setAttribute("style",b)})}function v(a,b){if(1===k&&console.log("goToSlide",arguments,O),void 0===a&&(a=m.carouselIndex),b=b||{},b.animate===!1||"none"===I.transitionType)return O=!1,K=-100*a,m.carouselIndex=a,B(),void 0;O=!0;var c=new j;c.tween({from:{x:K},to:{x:-100*a},duration:I.transitionDuration,easing:I.transitionEasing,step:function(a){u(a.x)},finish:function(){O=!1,m.$apply(function(){m.carouselIndex=a,K=-100*a,B()})}})}function w(){return n[0].getBoundingClientRect().width}function x(){M=w()}function y(a){return c.bind("mouseup",t),x(),N=n[0].querySelector("li").getBoundingClientRect().left,D=!0,E=a.x,!1}function z(a){var b,c;if(D&&(b=a.x,c=E-b,c>2||-2>c)){L=!0;var d=K+100*-c/M;u(d)}return!1}function A(a,b){if((!b||L)&&(c.unbind("mouseup",t),D=!1,L=!1,F=E-a.x,0!==F&&!O))if(K+=100*-F/M,I.isSequential){var d=l*M,e=-F,f=-Math[e>=0?"ceil":"floor"](e/M),g=Math.abs(e)>d;G&&f+m.carouselIndex>=G.length&&(f=G.length-1-m.carouselIndex),f+m.carouselIndex<0&&(f=-m.carouselIndex);var h=g?f:0;F=m.carouselIndex+h,v(F)}else m.$apply(function(){m.carouselIndex=parseInt(-K/100,10),B()})}function B(){var a=0,b=(m.carouselBufferSize-1)/2;s?(a=m.carouselIndex<=b?0:G&&G.lengthG.length-m.carouselBufferSize?G.length-m.carouselBufferSize:m.carouselIndex-b,m.carouselBufferIndex=a,f(function(){u(K)},0,!1)):f(function(){u(K)},0,!1)}function C(){x(),v()}k++;var D,E,F,G,H={transitionType:o.rnCarouselTransition||"slide",transitionEasing:"easeTo",transitionDuration:300,isSequential:!0,autoSlideDuration:3,bufferSize:5},I=angular.extend({},H),J=!1,K=0,L=!1,M=null,N=null,O=!1;if(void 0!==o.rnCarouselControls){var P='';n.append(e(angular.element(P))(m))}a.bind(n,{start:y,move:z,end:A,cancel:function(a){A({},a)}}),m.nextSlide=function(a){1===k&&console.log("nextSlide, scope.carouselIndex",m.carouselIndex);var b=m.carouselIndex+1;b>G.length-1&&(b=0),O||v(b,a)},m.prevSlide=function(a){var b=m.carouselIndex-1;0>b&&(b=G.length-1),v(b,a)};var Q=!0;m.carouselIndex=0,r||(G=[],angular.forEach(q(),function(a,b){G.push({id:b})}));var R;if(void 0!==o.rnCarouselAutoSlide){var S=parseInt(o.rnCarouselAutoSlide,10)||I.autoSlideDuration;R=g(function(){O||D||m.nextSlide()},1e3*S)}if(o.rnCarouselIndex){var T=function(a){U.assign(m.$parent,a)},U=d(o.rnCarouselIndex);angular.isFunction(U.assign)?(m.$watch("carouselIndex",function(a){console.log("watch carouselIndex",a),O||T(a)}),m.$parent.$watch(U,function(a){void 0!==a&&null!==a&&(G&&a>=G.length?(a=G.length-1,T(a)):G&&0>a&&(a=0,T(a)),O||v(a,{animate:!Q}),Q=!1)}),J=!0):isNaN(o.rnCarouselIndex)||v(parseInt(o.rnCarouselIndex,10),{animate:!1})}else v(0,{animate:!Q}),Q=!1;r&&m.$watchCollection(p,function(a){G=a,v(m.carouselIndex)}),m.$on("$destroy",function(){c.unbind("mouseup",t)}),m.carouselBufferIndex=0,m.carouselBufferSize=I.bufferSize;var V=angular.element(b);V.bind("orientationchange",C),V.bind("resize",C),m.$on("$destroy",function(){c.unbind("mouseup",t),V.unbind("orientationchange",C),V.unbind("resize",C)})}}}}])}(),angular.module("angular-carousel.shifty",[]).factory("Tweenable",function(){return function(a){"undefined"==typeof SHIFTY_DEBUG_NOW&&(SHIFTY_DEBUG_NOW=function(){return+new Date});var b=function(){"use strict";function b(){}function c(a,b){var c;for(c in a)Object.hasOwnProperty.call(a,c)&&b(c)}function d(a,b){return c(b,function(c){a[c]=b[c]}),a}function e(a,b){c(b,function(c){"undefined"==typeof a[c]&&(a[c]=b[c])})}function f(a,b,c,d,e,f,h){var i,j=(a-f)/e;for(i in b)b.hasOwnProperty(i)&&(b[i]=g(c[i],d[i],l[h[i]],j));return b}function g(a,b,c,d){return a+(b-a)*c(d)}function h(a,b){var d=k.prototype.filter,e=a._filterArgs;c(d,function(c){"undefined"!=typeof d[c][b]&&d[c][b].apply(a,e)})}function i(a,b,c,d,e,g,i,j,k){s=b+c,t=Math.min(r(),s),u=t>=s,a.isPlaying()&&!u?(k(a._timeoutHandler,p),h(a,"beforeTween"),f(t,d,e,g,c,b,i),h(a,"afterTween"),j(d)):u&&(j(g),a.stop(!0))}function j(a,b){var d={};return"string"==typeof b?c(a,function(a){d[a]=b}):c(a,function(a){d[a]||(d[a]=b[a]||n)}),d}function k(a,b){this._currentState=a||{},this._configured=!1,this._scheduleFunction=m,"undefined"!=typeof b&&this.setConfig(b)}var l,m,n="linear",o=500,p=1e3/60,q=Date.now?Date.now:function(){return+new Date},r=SHIFTY_DEBUG_NOW?SHIFTY_DEBUG_NOW:q;m="undefined"!=typeof window?window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||window.mozCancelRequestAnimationFrame&&window.mozRequestAnimationFrame||setTimeout:setTimeout;var s,t,u;return k.prototype.tween=function(a){return this._isTweening?this:(void 0===a&&this._configured||this.setConfig(a),this._start(this.get()),this.resume())},k.prototype.setConfig=function(a){a=a||{},this._configured=!0,this._pausedAtTime=null,this._start=a.start||b,this._step=a.step||b,this._finish=a.finish||b,this._duration=a.duration||o,this._currentState=a.from||this.get(),this._originalState=this.get(),this._targetState=a.to||this.get(),this._timestamp=r();var c=this._currentState,d=this._targetState;return e(d,c),this._easing=j(c,a.easing||n),this._filterArgs=[c,this._originalState,d,this._easing],h(this,"tweenCreated"),this},k.prototype.get=function(){return d({},this._currentState)},k.prototype.set=function(a){this._currentState=a},k.prototype.pause=function(){return this._pausedAtTime=r(),this._isPaused=!0,this},k.prototype.resume=function(){this._isPaused&&(this._timestamp+=r()-this._pausedAtTime),this._isPaused=!1,this._isTweening=!0;var a=this;return this._timeoutHandler=function(){i(a,a._timestamp,a._duration,a._currentState,a._originalState,a._targetState,a._easing,a._step,a._scheduleFunction)},this._timeoutHandler(),this},k.prototype.stop=function(a){return this._isTweening=!1,this._isPaused=!1,this._timeoutHandler=b,a&&(d(this._currentState,this._targetState),h(this,"afterTweenEnd"),this._finish.call(this,this._currentState)),this},k.prototype.isPlaying=function(){return this._isTweening&&!this._isPaused},k.prototype.setScheduleFunction=function(a){this._scheduleFunction=a},k.prototype.dispose=function(){var a;for(a in this)this.hasOwnProperty(a)&&delete this[a]},k.prototype.filter={},k.prototype.formula={linear:function(a){return a}},l=k.prototype.formula,d(k,{now:r,each:c,tweenProps:f,tweenProp:g,applyFilter:h,shallowCopy:d,defaults:e,composeEasingObject:j}),"function"==typeof SHIFTY_DEBUG_NOW&&(a.timeoutHandler=i),"object"==typeof exports?module.exports=k:"function"==typeof define&&define.amd?define(function(){return k}):"undefined"==typeof a.Tweenable&&(a.Tweenable=k),k}();!function(){b.shallowCopy(b.prototype.formula,{easeInQuad:function(a){return Math.pow(a,2)},easeOutQuad:function(a){return-(Math.pow(a-1,2)-1)},easeInOutQuad:function(a){return(a/=.5)<1?.5*Math.pow(a,2):-.5*((a-=2)*a-2)},easeInCubic:function(a){return Math.pow(a,3)},easeOutCubic:function(a){return Math.pow(a-1,3)+1},easeInOutCubic:function(a){return(a/=.5)<1?.5*Math.pow(a,3):.5*(Math.pow(a-2,3)+2)},easeInQuart:function(a){return Math.pow(a,4)},easeOutQuart:function(a){return-(Math.pow(a-1,4)-1)},easeInOutQuart:function(a){return(a/=.5)<1?.5*Math.pow(a,4):-.5*((a-=2)*Math.pow(a,3)-2)},easeInQuint:function(a){return Math.pow(a,5)},easeOutQuint:function(a){return Math.pow(a-1,5)+1},easeInOutQuint:function(a){return(a/=.5)<1?.5*Math.pow(a,5):.5*(Math.pow(a-2,5)+2)},easeInSine:function(a){return-Math.cos(a*(Math.PI/2))+1},easeOutSine:function(a){return Math.sin(a*(Math.PI/2))},easeInOutSine:function(a){return-.5*(Math.cos(Math.PI*a)-1)},easeInExpo:function(a){return 0===a?0:Math.pow(2,10*(a-1))},easeOutExpo:function(a){return 1===a?1:-Math.pow(2,-10*a)+1},easeInOutExpo:function(a){return 0===a?0:1===a?1:(a/=.5)<1?.5*Math.pow(2,10*(a-1)):.5*(-Math.pow(2,-10*--a)+2)},easeInCirc:function(a){return-(Math.sqrt(1-a*a)-1)},easeOutCirc:function(a){return Math.sqrt(1-Math.pow(a-1,2))},easeInOutCirc:function(a){return(a/=.5)<1?-.5*(Math.sqrt(1-a*a)-1):.5*(Math.sqrt(1-(a-=2)*a)+1)},easeOutBounce:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},easeInBack:function(a){var b=1.70158;return a*a*((b+1)*a-b)},easeOutBack:function(a){var b=1.70158;return(a-=1)*a*((b+1)*a+b)+1},easeInOutBack:function(a){var b=1.70158;return(a/=.5)<1?.5*a*a*(((b*=1.525)+1)*a-b):.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},elastic:function(a){return-1*Math.pow(4,-8*a)*Math.sin(2*(6*a-1)*Math.PI/2)+1},swingFromTo:function(a){var b=1.70158;return(a/=.5)<1?.5*a*a*(((b*=1.525)+1)*a-b):.5*((a-=2)*a*(((b*=1.525)+1)*a+b)+2)},swingFrom:function(a){var b=1.70158;return a*a*((b+1)*a-b)},swingTo:function(a){var b=1.70158;return(a-=1)*a*((b+1)*a+b)+1},bounce:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?7.5625*(a-=1.5/2.75)*a+.75:2.5/2.75>a?7.5625*(a-=2.25/2.75)*a+.9375:7.5625*(a-=2.625/2.75)*a+.984375},bouncePast:function(a){return 1/2.75>a?7.5625*a*a:2/2.75>a?2-(7.5625*(a-=1.5/2.75)*a+.75):2.5/2.75>a?2-(7.5625*(a-=2.25/2.75)*a+.9375):2-(7.5625*(a-=2.625/2.75)*a+.984375)},easeFromTo:function(a){return(a/=.5)<1?.5*Math.pow(a,4):-.5*((a-=2)*Math.pow(a,3)-2)},easeFrom:function(a){return Math.pow(a,4)},easeTo:function(a){return Math.pow(a,.25)}})}(),function(){function a(a,b,c,d,e,f){function g(a){return((n*a+o)*a+p)*a}function h(a){return((q*a+r)*a+s)*a}function i(a){return(3*n*a+2*o)*a+p}function j(a){return 1/(200*a)}function k(a,b){return h(m(a,b))}function l(a){return a>=0?a:0-a}function m(a,b){var c,d,e,f,h,j;for(e=a,j=0;8>j;j++){if(f=g(e)-a,l(f)e)return c;if(e>d)return d;for(;d>c;){if(f=g(e),l(f-a)f?c=e:d=e,e=.5*(d-c)+c}return e}var n=0,o=0,p=0,q=0,r=0,s=0;return p=3*b,o=3*(d-b)-p,n=1-p-o,s=3*c,r=3*(e-c)-s,q=1-s-r,k(a,j(f))}function c(b,c,d,e){return function(f){return a(f,b,c,d,e,1)}}b.setBezierFunction=function(a,d,e,f,g){var h=c(d,e,f,g);return h.x1=d,h.y1=e,h.x2=f,h.y2=g,b.prototype.formula[a]=h},b.unsetBezierFunction=function(a){delete b.prototype.formula[a]}}(),function(){function a(a,c,d,e,f){return b.tweenProps(e,c,a,d,1,0,f)}var c=new b;c._filterArgs=[],b.interpolate=function(d,e,f,g){var h=b.shallowCopy({},d),i=b.composeEasingObject(d,g||"linear");c.set({});var j=c._filterArgs;j.length=0,j[0]=h,j[1]=d,j[2]=e,j[3]=i,b.applyFilter(c,"tweenCreated"),b.applyFilter(c,"beforeTween");var k=a(d,h,e,f,i);return b.applyFilter(c,"afterTween"),k}}(),function(a){function b(a,b){B.length=0;var c,d=a.length;for(c=0;d>c;c++)B.push("_"+b+"_"+c);return B}function c(a){var b=a.match(v);return b?(1===b.length||a[0].match(u))&&b.unshift(""):b=["",""],b.join(A)}function d(b){a.each(b,function(a){var c=b[a];"string"==typeof c&&c.match(z)&&(b[a]=e(c))})}function e(a){return i(z,a,f)}function f(a){var b=g(a);return"rgb("+b[0]+","+b[1]+","+b[2]+")"}function g(a){return a=a.replace(/#/,""),3===a.length&&(a=a.split(""),a=a[0]+a[0]+a[1]+a[1]+a[2]+a[2]),C[0]=h(a.substr(0,2)),C[1]=h(a.substr(2,2)),C[2]=h(a.substr(4,2)),C}function h(a){return parseInt(a,16)}function i(a,b,c){var d=b.match(a),e=b.replace(a,A);if(d)for(var f,g=d.length,h=0;g>h;h++)f=d.shift(),e=e.replace(A,c(f));return e}function j(a){return i(x,a,k)}function k(a){for(var b=a.match(w),c=b.length,d=a.match(y)[0],e=0;c>e;e++)d+=parseInt(b[e],10)+",";return d=d.slice(0,-1)+")"}function l(d){var e={};return a.each(d,function(a){var f=d[a];if("string"==typeof f){var g=r(f);e[a]={formatString:c(f),chunkNames:b(g,a)}}}),e}function m(b,c){a.each(c,function(a){for(var d=b[a],e=r(d),f=e.length,g=0;f>g;g++)b[c[a].chunkNames[g]]=+e[g];delete b[a]})}function n(b,c){a.each(c,function(a){var d=b[a],e=o(b,c[a].chunkNames),f=p(e,c[a].chunkNames);d=q(c[a].formatString,f),b[a]=j(d)})}function o(a,b){for(var c,d={},e=b.length,f=0;e>f;f++)c=b[f],d[c]=a[c],delete a[c];return d}function p(a,b){D.length=0;for(var c=b.length,d=0;c>d;d++)D.push(a[b[d]]);return D}function q(a,b){for(var c=a,d=b.length,e=0;d>e;e++)c=c.replace(A,+b[e].toFixed(4));return c}function r(a){return a.match(w)}function s(b,c){a.each(c,function(a){for(var d=c[a],e=d.chunkNames,f=e.length,g=b[a].split(" "),h=g[g.length-1],i=0;f>i;i++)b[e[i]]=g[i]||h;delete b[a]})}function t(b,c){a.each(c,function(a){for(var d=c[a],e=d.chunkNames,f=e.length,g="",h=0;f>h;h++)g+=" "+b[e[h]],delete b[e[h]];b[a]=g.substr(1)})}var u=/(\d|\-|\.)/,v=/([^\-0-9\.]+)/g,w=/[0-9.\-]+/g,x=new RegExp("rgb\\("+w.source+/,\s*/.source+w.source+/,\s*/.source+w.source+"\\)","g"),y=/^.*\(/,z=/#([0-9]|[a-f]){3,6}/gi,A="VAL",B=[],C=[],D=[];a.prototype.filter.token={tweenCreated:function(a,b,c){d(a),d(b),d(c),this._tokenData=l(a)},beforeTween:function(a,b,c,d){s(d,this._tokenData),m(a,this._tokenData),m(b,this._tokenData),m(c,this._tokenData)},afterTween:function(a,b,c,d){n(a,this._tokenData),n(b,this._tokenData),n(c,this._tokenData),t(d,this._tokenData)}}}(b)}(this),this.Tweenable}),function(){"use strict";angular.module("angular-carousel").filter("carouselSlice",function(){return function(a,b,c){return angular.isArray(a)?a.slice(b,b+c):angular.isObject(a)?a:void 0}})}(); \ No newline at end of file diff --git a/index.html b/index.html index 235a15f..c1de146 100644 --- a/index.html +++ b/index.html @@ -19,161 +19,127 @@

AngularJS Touch Carousel

Swipe these demos with your mouse or finger -

ngRepeat demo (buffered carousel)

-
A simple buffered ng-repeat with a custom template. -
- Swipe 50 slides with only 5 slides in the DOM -
-
    -
  • -
    - {{ slide.label }} / {{ slides.length }} +
    +
    +

    Buffered ngRepeat demo

    +
    A simple buffered ng-repeat with a custom template.
    - carouselIndex: {{ carouselIndex }}
    - carouselBufferIndex: {{ carouselBufferIndex }}
    + Swipe 50 slides with only 5 slides in the DOM. use builtin controls
    -
  • -
- -

template-based demo

-
Various blocks automagically converted to a carousel. + +
+
+

ngRepeat with auto-slide, controls and indicators

+
+
+ +

- Just add rn-carousel-indicator to display clickable indicators - -
    -
  • - This is a standard template -
    slide #1
    -
  • -
  • - Here's sophie :
    - -
  • -
  • - A friend of mine :
    - -
  • -
  • - And to finish : - -
  • -
- -

Standard carousel with thumbs navigation

-
This one has an initial index and the thumbs controls the rn-carousel-index binding
-
    -
  • -
-
-
-
- -

carousel with builtin prev/next controls

-
just add rn-carousel-control attribute to enable builtin controls
-
    -
  • -
    - {{ slide.label }} / {{ slides.length }} +
    +

    ngRepeat with custom transition

    +
    Use the 'hexagon' transition. index is shared with the carousel below.
    -
  • -
- -

buffered ngRepeat carousel with custom controls

-
Custom controls demo, just update the rn-carousel-index index binding
-
    -
  • -
    - {{ slide.label }} / {{ slides4.length }} -
    - carouselIndex: {{ carouselIndex }}
    - carouselBufferIndex: {{ carouselBufferIndex }}
    + -
  • -
-
- - {{ slideIndex + 1 }} / {{ slides4.length }} - - - -
- -

object-based ngRepeat carousel with indicators

-
Use the object-based ngRepeat syntax. (not compatible with buffering)
-
    -
  • -
    {{ label }}
    -
  • -
- -

togglable carousel via ng-if

-
If you use ng-if, be sure to use the dot-notation syntax for the index binding as it creates a child scope.
- -

- -
    -
  • -
    #{{ $index + 1 }}
    -
  • -
+ +
+
+

ngRepeat with custom transition

+
Use the 'zoom' transition. index is shared with the carousel above. +
+ +
+
+
+

Custom templates without ng-repeat and auto-slide

+
+
+ +
-

Autoplay slider

-
- By adding rn-carousel-auto-slide with an integer value will make the slider automatically change the visible slide after n seconds -
- By adding rn-carousel-pause-on-hover="true" the slide will pause on mouse hover and start on mouse leave
-
    -
  • - This is a standard template -
    slide #1
    -
  • -
  • - Here's sophie :
    - -
  • -
  • - A friend of mine :
    - -
  • -
  • - And to finish : - -
  • -
-

-

Other demos

- -

- - + - --> + +