Как стать автором
Обновить

Предварительная загрузка изображений

Время на прочтение5 мин
Количество просмотров13K
Те, кто использует HTML5 Canvas знают, что картинку нельзя использовать через URL к ней. Картинку нужно сначала загрузить либо через тэг img, либо через объект Image, либо через data: url.
Чтобы не думать о загрузке каждой картинки, делают загрузку всех необходимых картинок перед отрисовкой самой сцены. В этом топике я приведу в пример свой загрузчик изображений, который использует Mootools с его механизмов для работы с классами.

Как должен выглядеть такой класс с точки зрения проектирования? Он должен принимать адреса изображений, которые должны загрузиться, и каким-то образом, оповещать о процессе загрузки.
К счастью, Mootools предоставляет некоторые средства для удобной работы с событиями.

В классе реализуются обработчики событий onload, onerror, onabort объектов Image, и, когда процент общей загрузки изменился, генерируются свои.
Класс генерирует три события:
  • onStart(): вызывается на старте загрузки;
  • onUpdate( percent ): вызывается, когда процент загрузки изменился;
  • onComplete(): вызывается, когда все изображения загрузились.

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.

Пример использования:

      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.


В качестве представления прогресса я написал еще один класс, который через Canvas рисует прогрессбар.

Пример реализации можно посмотреть здесь ( грузит где-то 100кбайт Гугловских логотипов )

P.S. Я планирую написать цикл статьей про игростроительство через Html5 Canvas. Это первая, хоть она и немного банальная. В следующей статьей я постараюсь описать принцип построения ландшафта в изометрической проекции ( по тайлам ).
Теги:
Хабы:
Всего голосов 29: ↑23 и ↓6+17
Комментарии7

Публикации

Истории

Работа

Ближайшие события

One day offer от ВСК
Дата16 – 17 мая
Время09:00 – 18:00
Место
Онлайн
Конференция «Я.Железо»
Дата18 мая
Время14:00 – 23:59
Место
МоскваОнлайн
Антиконференция X5 Future Night
Дата30 мая
Время11:00 – 23:00
Место
Онлайн
Конференция «IT IS CONF 2024»
Дата20 июня
Время09:00 – 19:00
Место
Екатеринбург
Summer Merge
Дата28 – 30 июня
Время11:00
Место
Ульяновская область