Предварительная загрузка изображений с помощью css. Предварительная загрузка изображений
Для того чтобы можно было загружать на сервер один или несколько файлов, в форме применяется специальное поле. В браузерах Firefox, IE и Opera такой элемент отображается как текстовое поле, рядом с которым располагается кнопка с надписью «Обзор...» (рис. 1). В Safari и Chrome доступна только кнопка «Выберите файл» (рис. 2).
Рис. 1. Вид поля для загрузки файла в Firefox
При нажатии на кнопку открывается окно для выбора файла, где можно указать, какой файл пользователь желает использовать.
Синтаксис поля для отправки файла следующий.
Атрибуты перечислены в табл. 1.
Прежде, чем использовать данное поле, в форме необходимо сделать следующее:
- задать метод отправки данных POST (method="post" );
- установить у атрибута enctype значение multipart/form-data .
Форма для загрузки файла продемонстрирована в примере 1.
Пример 1. Создание поля для отправки файла
HTML5 IE Cr Op Sa Fx
Хотя можно установить ширину поля через атрибут size , в действительности ширина никак не влияет на результат работы формы. В браузерах Safari и Chrome этот атрибут вообще никакого воздействия не оказывает.
Атрибут multiple более важен, он позволяет не ограничиваться одним файлом для выбора, а указать их сразу несколько для одновременной загрузки.
Если атрибут accept не указывать, тогда добавляются и загружаются файлы любого типа. Наличие accept позволяет ограничить выбор файла, что особенно важно, когда требуется загрузить только изображение или видео. В качестве значения выступает , несколько значений разделяются между собой запятой. Также можно использовать следующие ключевые слова:
- audio/* - выбор музыкальных файлов любого типа;
- image/* - графические файлы;
- video/* - видеофайлы.
В табл. 2 показаны некоторые допустимые значения атрибута accept .
Использование дополнительных атрибутов показано в примере 2.
HTML5 IE 10+ Cr Op Sa Fx
Не все браузеры поддерживают новые атрибуты. IE полностью игнорирует multiple и accept , Safari не поддерживает accept , а Firefox не работает с MIME-типом, только с ключевыми словами. Поэтому в примере выше специально для Firefox установлено значение image/*,image/jpeg . Также учтите странную ошибку в Опере, она не допускает пробелы после запятой внутри accept .
Результат примера показан на рис. 3. Обратите внимание, что из-за наличия multiple несколько изменился вид поля.
Для игры нужно подгрузить заранее в районе 12 изображений, причем эти изображения могут варьироваться от случая к случаю. То есть сейчас мне нужно подгрузить одни 12 изображений (SVG), а завтра нужно будет другие 12. Поэтому вариант помещения их в
не подходит, ибо в этом случае придется постоянно грузить все изображения, а понадобятся мне из них всего 12. Поэтому было решено подгружать их средствами JavaScript перед началом игры. Для этого я реализовал небольшой класс "AssetsPreloader", который, пока что, имеет единственный метод "preload", который принимает массив из объектов вида {src: "ссылка", id: "id"} и подгружает необходимые изображения путем простого создания экземпляра класса Image() (нативный).Class AssetsPreloader { static preload(arr) { arr.map((a) => { let img = new Image(); img.src = a.src; img.id = a.id; (this.assets = this.assets || ).push(img); }); } }
Все подгруженные изображения в итоге попадают в статическое свойство assets этого класса.
Следующим в коде идет отрисовка первого кадра игры, где эти изображения уже используются. И, в общем-то, проблема в том, что отрисовка не происходит. До нее выполнение кода доходит, это я проверял, и после нее код выполняется, но сами изображения не отрисовываются. Насколько я понимаю, происходит это потому, что изображения не успевают загрузиться (даже несмотря на то, что загрузка их происходит с диска). Однако, если запросить отрисовку первого кадра прямо из консоли браузера, то все работает как надо и кадр рисуется нормально.
Весь код в общем и целом выглядит примерно так:
Class AssetsPreloader { static preload(arr) { arr.map((a) => { let img = new Image(); img.src = a.src; img.id = a.id; (this.assets = this.assets || ).push(img); this.done = true; }); } } AssetsPreloader.preload([ {src: "images/image.svg", id: "id_of_image"}, ... ]); // ... GAME.field.draw();
В итоге, вопрос сводится к тому, как максимально правильно подгружать изображения (да и вообще различного рода файлы) так, чтобы, пока они не загрузились, код далше не выполнялся. Причем, возможно, на экране в этот момент будет какой-нибудь прогресс-бар (то есть полностью фризиться скрипт тоже не должен). Первым делом мне в голову пришло добавить весь остальной код в коллбэк к методу preload() , но эта идея успехом не увенчалась.
Прошу помощи. Интересует не только как, но и как наиболее правильно (best-practice, все такое).
P.S. Файл скрипта подключен к странице с атрибутом defer . При использовании, например, async , отрисовка либо происходит, либо нет (отчего зависит - не могу сказать). А вешать в сам код обработчики проверки загрузки страницы, готовности DOM или что-то в этом роде не хочу.
Когда занимаешься версткой и созданием всяких хитростей с картинками (обычно с подменой при наведении или даже их анимацией), всегда вспылывает такой нюанс как заторможенная подгрузка картинки/изображения . На первый взгляд проблема не такая уж серьезная и, как только картинки загрузятся, все работает отлично, но вот этот первый hover эффект, который пытается загрузить картинку и одновременно заменить её, создает такой эффект рывка, который не редко смотрится не очень красиво и может испортить первое впечатление пользователей вашего сайта.
С анимацией дела обстоят еще хуже. Представьте, например, что вам нужно реализовать на JS (JQuery) проезжаюшую легковую машину, заменяюшуюся через 2 секунды автобусом. Изображения с машиной и автобусом разные. При этом они начнут подгружаться только в тот момент, когда браузер получит на них ссылку с возможностью подгрузки (то есть в начале анимации ). На загрузку такой картинки нужно будет несколько секунд. То есть получается, что половину двухсекундной анимации это изображение только будет подгружаться - это не порядок.
Но это все можно исправить предзагрузкой (предварительной загрузкой ) изображений, которая позволяет подгружать картинку в буфер сразу при загрузке основной страницы (или даже перед этим ). Об этом я и хочу рассказать в данной заметке.
Предзагрузка картинок на JavaScript (JQuery)
Вариант с загрузкой на JS, как мне кажется, один из самых лучший, особенно если вы имеете дело с анимацией. Его суть в том, что вы просто посредством JavaScript создаете копию картинки и загружаете её в буфер браузера, тем самым при необходимости уже не нужно будет подгружать картинку, так как она уже будет предварительно загружена .Сложно звучит? =) А выглядит всего лишь вот таким кодом, где нужно заменить путь к картинке на свой и все будет работать:
//создаем JQuery функцию, которая будет подгружать изображения в буфер jQuery.preloadImages = function() { for(var i = 0; i < arguments.length; i++) { jQuery("").attr("src", arguments[ i ]); } }; //указываем путь к изображению, которое нужно подгрузить $.preloadImages("/tpl/testimg.png");
Если же вам нужно подгрузить несколько изображений, то вы просто можете перечислить их через запятую, вот так:
$.preloadImages("imageone.jpg", "dirname/imageok.jpg", "/tpl/testimg.png");
Картинок может быть любое количество. Главное не забывайте про JQuery функцию, без нее предзагрузка работать не будет.
У этого способа есть и недостатки, например в том, что он зависит от того, включен ли JS в браузере пользователя. Но по личному опыту скажу, что если равняться на тех, у кого выключен JS, то в современных технологиях сайтостроения очень много не удастся реализовать. Да и таких юзеров, я думаю, не так уж много. Вообще нужно равняться на большинство, а большинство не кастомизирует браузер до такой степени.
Я лично во многих проектах предпочитаю использовать именно такой способ подгрузки ввиду того, что он удобен в реализации.
Предзагрузка изображений с помощью новых возможнестей HTML5
Этот способ появился относительно недавно ввиду того, что сама технология HTML5 была запущена не так давно. Суть его в том, что вы проставляете ссылку на картинку через тег link, а в атрибуте rel (тип подгружаемого элемента ) вы прописываете, что это предзагрузка. Тем самым браузер видит этот тег и автоматически загружает в буфер картинку .Делается это добавлением в html код вот такого тега (только ссылку на изображение меняете на свою
):
Здесь в rel прописано 2 параметра: prerender - для его величества Chrome и prefetch - для остальных браузеров. Если вы хотите подгружать большее число картинок, то копируете тег и заменяете ссылку нужное количество раз:
Плюс этого способа в том, что отключение JS никак не повлияет на предзагрузку, но лично я вижу 2 явных недостатка:
1)
Технология HTML5, а значит и этот способ предзагрузки, поддерживается далеко не всеми браузерами. Сейчас, правда, браузеры обновляются и большинство современных развивающихся браузеров распознают HTML5, но всеравно это еще далеко от идеала.
2)
Более грамоздкий в отличае от JS реализации, ведь придется каждое изображение описывать отдельным тегом (причем с разными параметрами rel, что бы добиться чего-то близкого к кроссбраузерности
).
В общем считаю, что этот способ перспективен, но ему нужно время. Сейчас в нем не хватает универсальности .
Предварительная загрузка картинок на проверенном временем HTML
Самая первая идея, которая приходит обычно в голову на чистом html - это создать div блок с параметром CSS "display:none;" , в нем картинку и это должно стать предзагрузкой. На самом деле это не работает, браузер начнет загрузку в буфер только тогда, когда display станет отличное от none.Но я придумал способ с использованием хитростей CSS. Расскажу подробнее про него.
Размещение в невидимом блоке через CSS opacity и position (позиционирование)
В CSS есть такое свойство - opacity . Его предназначение - менять прозрачность и изменить прозрачность можно вплоть до нуля. Кроме того, в CSS есть еще и свойство position, которое нужно для позиционирования элемента на странице (можно попиксельно сдвигать блок с информацией хоть куда в пределах и за пределы видимости страницы ). Все это нам и пригодится:Тем самым мы получаем невидимый блок c картинкой, который еще и фактически расположен за пределами видимой пользователю информации. Таким видом позиционирования за пределами экрана, кстати, часто пользуются, если хотят создать какой-то невидимый блок, частенько видел как вшивают ссылки на бесплатные шаблоны именно таким образом. Так что вы тебе все знаете =)
Если вы хотите сделать прелоад нескольких картинок таким способом, то достаточно их указать внутри div блока, вот так:
Вот такие способы предзагрузки картинок/изображений можно использовать в разработке сайтов. Если у Вас есть еще какие-то идеи, то рад буду их почитать в комментариях.
Всем удачи в верстке и создании анимации! =)
Привносит новое, удивительное API. Если вы соедините это API с элементом
Было бы неплохо, если бы кто-то отписал в комментариях, как он использует ту или иную технологию уже сейчас в своих проектах.
Получить изображение
Чтобы загрузить файл на сервер, Вам понадобится элемент . Но вы также должны позволить пользователю перетаскивать изображения с рабочего стола прямо на веб-страницу Вашего сайта.
Множественный выбор файлов для загрузки
Чтобы позволить пользователю выбрать за один раз несколько файлов надо вставить в элемент file атрибут multiple
Предварительная обработка файлов
Используем File API
(Детали работы с File API смотрите )
После того как вы выбрали файлы в элемент file, датапикером или при помощи drag&drop у Вас есть список файлов готовых к использованию.
//из type="file" var filesToUpload = input.files; //либо при помощи Drag-and-Drop function onDrop(e) { filesToUpload = e.dataTransfer.files; }
Убедитесь, что эти файлыявляются изображениями:
If (!file.type.match(/image.*/)) { // этот файл не изображение };
Показать миниатюрку/превьюшку
Есть два варианта. Вы можете использовать FileReader (из File API), или использовать новый метод createObjectURL () .
createObjectURL()
Var img = document.createElement("img"); img.src = window.URL.createObjectURL(file);
FileReader
Var img = document.createElement("img"); var reader = new FileReader(); reader.onload = function(e) {img.src = e.target.result} reader.readAsDataURL(file);
Используем Canvas
Вы можете нарисовать файл на элементе
Var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0);
Изменение размера изображения
Люди привыкли загружать изображения прямо из своей камеры. Это дает высокое разрешение и чрезвычайно тяжелые (несколько мегабайт) файлы. В зависимости от использования, вы можете изменить размер таких изображений. Фокус в том, чтобы просто иметь небольшой canvas(800 × 600, например) и нарисовать это изображение в этот canvas. Конечно, вам придется изменить размеры canvas"а, чтобы сохранить отношения сторон изображения.
Var MAX_WIDTH = 800; var MAX_HEIGHT = 600; var width = img.width; var height = img.height; if (width > height) { if (width > MAX_WIDTH) { height *= MAX_WIDTH / width; width = MAX_WIDTH; } } else { if (height > MAX_HEIGHT) { width *= MAX_HEIGHT / height; height = MAX_HEIGHT; } } canvas.width = width; canvas.height = height; var ctx = canvas.getContext("2d"); ctx.drawImage(img, 0, 0, width, height);
Редактирование изображения
Теперь у вас есть изображение в canvas. Теперь Ваши возможности безграничны. Допустим, вы хотите применить фильтр сепия:
Var imgData = ctx.createImageData(width, height); var data = imgData.data; var pixels = ctx.getImageData(0, 0, width, height); for (var i = 0, ii = pixels.data.length; i < ii; i += 4) { var r = pixels.data; var g =pixels.data; var b = this.pixels.data; data = (r * .393) + (g *.769) + (b * .189); data = (r * .349) + (g *.686) + (b * .168) data = (r * .272) + (g *.534) + (b * .131) data = 255; } ctx.putImageData(imgData, 0, 0);
Загрузить с XMLHttpRequest
Теперь, когда вы загрузили изображения на клиента, в конечном итоге Вы хотите отправить их на сервер.
Как отправить canvas
Опять же, у Вас есть два варианта. Вы можете конвертировать canvas очень длинный URL или (в Firefox) создать файл из canvas.
canvas.toDataURL()
Var dataurl = canvas.toDataURL("image/png");
Создайте файл из canvas
Var file = canvas.mozGetAsFile("foo.png");
Неделимая загрузка
Разрешить пользователю загрузить только один файл или все файлы, в то же время.
Показать ход загрузки
Используйте событие загрузки для создания индикатора:
Xhr.upload.addEventListener("progress", function(e) { if (e.lengthComputable) { var percentage = Math.round((e.loaded * 100) / e.total); // do something }, false);
Используйте FormData
Вы, наверное, вряд ли хотите просто загрузить файл (который может быть легко сделано с помощью: xhr.send (файл)), но также добавить стороннюю информацию (например, ключ и название).
В этом случае вы должны создать multipart/form-data запрос с помощью объекта FormData
Var fd = new FormData(); fd.append("name", "paul"); fd.append("image", canvas.mozGetAsFile("foo.png")); fd.append("key", "××××××××××××"); var xhr = new XMLHttpRequest(); xhr.open("POST", "http://your.api.com/upload.json"); xhr.send(fd);
Откройте Ваше API сайта
Может быть, вы хотите, чтобы другие сайты, использовали Ваш сайт как сервис.\