Monday, 25 May 2015

AngularJS - simple image switcher / cycler / swapper with preload

This time, taking previous post into consideration, I'll show basic web control build as a directive. It will consist of a single image (being preloaded) which will be switched to the next one from the list of all enclosed images to render. We will specify base delay for switching the images, list of images and some other stuff. The main dependency of this new directive is the preloaded-image directive from previous post. This control is to be used across the project since it is the directive. Here is the code:

image-cycler


 define(['directives/directives', 'angular', 'lodash'], function (directives, angular, _) {  
   'use strict';  
   directives.directive('imageCycler', ['$log', 'ApplicationConstants', '$timeout', '$interval', '$compile', '$window',  
     function ($log, ApplicationConstants, $timeout, $interval, $compile, $window) {  
       return {  
         restrict: 'E',  
         scope: {  
           containerId: '@',  
           images: '=',  
           baseDelay: '@',  
           external: '@',  
           placeholderText: '@',  
           placeholderWidth: '@',  
           placeholderHeight: '@',  
           tooltipText: '@',  
         },  
         templateUrl: '/public/js/directives/templates/imageCycler.html',  
         link: function (scope, element, attrs) {  
           scope.isImagePreloading = false;  
           var delay = parseInt(scope.baseDelay) + (($window.Math.random() * parseInt(scope.baseDelay)) | 0);  
           scope.$on(ApplicationConstants.events.imagePreloadStart, function (event, imageId) {  
             $timeout(function () {  
               if (_.has(scope.images, imageId)) {  
                 scope.isImagePreloading = true;  
               }  
             });  
           });  
           scope.$on(ApplicationConstants.events.imagePreloadEnd, function (event, imageId) {  
             $timeout(function () {  
               if (_.has(scope.images, imageId)) {  
                 scope.isImagePreloading = false;  
               }  
             });  
           });  
           scope.$watch('isImagePreloading', function (newValue, oldValue) {  
             $log.debug(newValue, oldValue);  
             if (newValue === true) {  
               $timeout(scope.updateImage, delay);  
             }  
           });  
           var currentImage = 0;  
           scope.updateImage = function () {  
             var baseUrl = '/public/'  
             switch (ApplicationConstants.env) {  
               case 'release':  
                 baseUrl += 'release/images/';  
                 break;  
               case 'dev':  
                 baseUrl += 'js/images/';  
                 break;  
             }  
             if (scope.external) {  
               baseUrl = '';  
             }  
             var imageIds = _.keys(scope.images);  
             if (scope.isImagePreloading) {  
               return;  
             }  
             if (currentImage === imageIds.length) {  
               currentImage = 0;  
             }  
             angular.element('#imageContainer-' + scope.containerId).empty();  
             var preloadedImage = '<preloaded-image image-id="' + imageIds[currentImage] + '" image-src="' + baseUrl + scope.images[imageIds[currentImage]] + '" placeholder-width="' + scope.placeholderWidth + '" placeholder-height="' + scope.placeholderHeight + '" placeholder-text="' + scope.placeholderText + '" tooltip="' + scope.tooltipText + '" tooltip-placement="bottom" tooltip-animation="false" tooltip-class="default"></preloaded-image>'  
             angular.element('#imageContainer-' + scope.containerId).append(preloadedImage)  
             $compile(angular.element('#imageContainer-' + scope.containerId).contents())(scope);  
             ++currentImage;  
           };  
           $timeout(function () {  
             scope.updateImage();  
           });  
         }  
       };  
     }]);  
 });  

As you can see in the code - it depends on the events broadcasted from preloaded-image directive from previous post and running $timeout with delay when image is preloaded / displayed. It inserts the new preloaded image directive's html to the current element and then compiles it allowing angular do it's work.

image-cycler-tpl


 <div id="imageContainer-{{containerId}}"></div>  

usage: controller


 define(['controllers/controllers'], function (controllers) {  
   'use strict';  
   controllers.controller('IndexCtrl', ['$scope', '$location', '$window', function ($scope, $location, $window) {  
     $scope.Math = $window.Math;  
     $scope.images = {  
       'img_1': 'img_1.gif',  
       'img_2': 'img_2.gif',  
       'img_3': 'img_3.gif',  
       'img_4': 'img_4.gif',  
       'img_5': 'img_5.gif',  
       'img_6': 'img_6.gif',  
       'img_7': 'img_7.gif'  
     };  
   }]);  
 });  

usage: view


 <div class="panel-body">  
     <image-cycler container-id="images-cycler" images="images" base-delay="10000" preloader-text="image" placeholder-width="300" placeholder-height="250" tooltip-text="This application helps you plan and carry out your dietary plans."></image-cycler>  
 </div>  


No comments:

Post a Comment