Image preload

    Those using HTML5 Canvas know that a picture cannot be used via the URL to it. The image must first be loaded either through the img tag, either through the Image object, or via data: url .
    In order not to think about loading each picture, they download all the necessary pictures before rendering the scene itself. In this topic, I will give an example my image loader, which uses Mootools with its mechanisms for working with classes.

    What should such a class look like in terms of design? It should accept the addresses of the images that should be loaded, and in some way, notify about the download process.
    Fortunately, Mootools provides some facilities for convenient handling of events.

    The class implements onload, onerror, onabort event handlers for Image objects, and when the percentage of total load has changed, its own are generated.
    The class generates three events:
    • onStart () : called at boot start;
    • onUpdate (percent) : called when the load percentage has changed;
    • onComplete () : called when all images have loaded.

    var Imageloader = new Class({
      //Наследуем интерфейсы Options и Events
      Implements : [Options, Events],
      options : {
        //Описания событий
        //загрузка началась
        onStart : $empty,
        //обновился процент загрузки
        onUpdate : $empty,
        //загрузка завершилась
        onComplete : $empty,
        //Массив хешей изображений. Хеш вида
        //{
        // "url" : url,
        // "key" : key,
        // "size" : size
        //}
        images : []
      },
      initialize : function(options) {
        this.setOptions(options);
        //В этом хеше будут храниться загруженные картинки
        this.images = {};

        //Объявляем начальные переменные
        this.totalCount = this.options.images.length;
        this.successCount = this.failureCount = this.loadedCount = 0;
        this.successSize = this.failureSize = this.loadedSize = this.totalSize = 0;
        this.progress = 0;

      },
      start : function() {
        //Создаем объекты Image,
        //добавляем слушатели
        $each(this.options.images, function(obj) {
          this.totalSize += obj.size;
          var image = new Image();
          image.onload = this.onComplete.bind(this,obj);
          image.onerror = this.onFailure.bind(this,obj);
          image.onabort = this.onFailure.bind(this,obj);
          image.src = obj.url;
          this.images[obj.key] = image;
        }.bind(this));
        this.fireEvent('start');
      },
      //Метод возвращает объект Image по ключу
      getImage : function( key ) {
        return this.images[key];
      },
      //изображение загрузилось
      onComplete : function( image ) {
        //Увеличиваем счетчики
        this.successCount++;
        this.successSize += image.size;
        
        this.onImageEvent(image);
      },
      //изображение не загрузилось
      onFailure : function( image ) {
        //Увеличиваем счетчики
        this.failureCount++;
        this.failureSize += image.size;
        //Вместо незагруженного изображения подставляем пустое
        this.images[image.key] = new Image();
        this.onImageEvent(image);
      },
      onImageEvent : function( image ) {
        //Увеличиваем счетчики
        this.loadedCount++;
        this.loadedSize += image.size;

        //Высчитываем общий прогресс
        var progress = Math.round(this.loadedSize*100/this.totalSize);
        if ( this.progress != progress ) {
          this.progress = progress;
          //Вызываем событие update
          this.fireEvent('update',progress);
        }
        //Если все изображения загружены
        if ( this.totalCount == this.loadedCount ) {
          this.fireEvent('complete');
        }

      }
    });


    * This source code was highlighted with Source Code Highlighter.

    Usage example:

          var il = new Imageloader({
            onUpdate : function(percent) {
              //Обновляем процент загрузки
              alert(percent);
            },
            onComplete : function( ) {
              //Можем успешно использовать загруженные изображения
              alert("done");
              alert(d.getImage("winter2010").complete);
            },
            //Хеш изображений
            images : [{
              'url' : 'http://www.google.com/intl/en_ALL/images/srpr/logo1w.png',
              'key' : 'main_logo',
              'size' : 7
            },{
              'url' : 'http://www.google.com/logos/winter2010_1-hp.jpg',
              'key' : 'winter2010',
              'size' : 32
            },{
              'url' : 'http://www.google.com/logos/komensky10_hp.gif',
              'key' : 'komensky',
              'size' : 26
            }]
          });
          //Запускаем загрузку
          il.start();

    * This source code was highlighted with Source Code Highlighter.


    As a representation of progress, I wrote another class that draws a progress bar through Canvas.

    An example of the implementation can be found here (it loads somewhere around 100KB of Google logos)

    PS I plan to write a series of articles about gaming through the Html5 Canvas. This is the first, although it is a little banal. In the next article I will try to describe the principle of building a landscape in isometric projection (by tiles).

    Also popular now: