От автора: так сложилось, что множество веб-приложений содержат в своей структуре разделы, где располагается личная информация пользователя, то есть страницы учетной записи. При этом, зачастую, помимо простых данных – эта информация включает в себя и фото зарегистрированного пользователя. Соответственно фотографии могут отображаться на различных страницах, и как правило, в подобных случаях для этого необходимы изображения различных размеров.
Первое – миниатюра, для отображения очень краткой информации, и второе – большого размера, для более детального описания. И, конечно же, всегда возникает вопрос, как именно загружать изображения в таких ситуациях?
Можно предоставить пользователю возможность загрузки сразу нескольких картинок различных размеров, но это не совсем удобно. Наилучший вариант – это загрузка одного большого изображения, обрезка его до нужных параметров и отображение специального интерфейса для визуального выбора области, которая будет отсечена. Вот как раз реализацией данного функционала мы с Вами и займемся в текущем уроке. Итак, какие инструменты нам понадобятся для урока:
Библиотека, с помощью которой на экране будет показан визуальный интерфейс по выбору обрезаемой области.
Библиотека по формированию всплывающих блоков (попапов).
Собственно, в интернете можно найти множество решений по данной теме, но в качестве инструмента под номером один я выбрал простую и бесплатную библиотеку под названием Croppie.
Согласитесь, что, используя подобный интерфейс, удобно выбрать необходимую часть изображения для обрезки.
В качестве второго инструмента мы используем библиотеку arcticModal, конечно для формирования можно было выбрать и что-то получше, к примеру Bootstrap, но она мне нравится из-за своей простоты.
Теперь, что касается логики работы будущего приложения. Для начала пользователь кликает по кнопке загрузить или сменить фото. При этом на экране отображается диалоговое окно по выбору файла. Как только будет осуществлен выбор нужного изображения, без перезагрузки, на сервер будет отправляться выбранная картинка для ее сохранения и, возможно, предварительной обрезки. Затем от сервера, в качестве ответа, будет возвращено имя сохраненного файла и сразу же откроется попап с визуальным интерфейсом по выбору области обрезки уже сохраненного изображения. После этого кликнув в попапе на кнопку сохранить, без перезагрузки выбранная часть изображения отправляется на сервер для сохранения.
Вот, собственно, и все, а значит давайте реализуем указанную логику работы. Итак, для начала html разметка тестовой страницы.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="css/croppie.css"/> <link rel="stylesheet" href="css/jquery.arcticmodal.css"/> <link rel="stylesheet" href="css/themes/simple.css"> <title>Test project</title> </head> <body> <section> <h2>Test form</h2> <form> <div>Field 1<input type="text"/></div> <div>Field 2<input type="text"/></div> <div>Field 3<input type="text"/></div> <div>Field 4<input type="text"/></div> <div class="perscab-photoedit-body"> <p> <a href="#" class="add-photo">change photo</a> </p> <input style="display:none;" id="c_input24" name="file" multiple="false" type="file"> <input style="display:none;" name="photo_c" multiple="false" type="hidden" value=""> <input style="display:none;" name="photo_i" value="" multiple="false" type="hidden"> </div> <input type="submit" value="save"> </form> <div class="perscab-photoedit-img"> <img src="#" alt=""> </div> </section> <div style="display:none"> <div class="profile-modal-photo box-modal"> <div class="box-modal_close arcticmodal-close"></div> <div> <img class="profile_photo_i" src=""> </div> <div class="modal-footer center-wrap"> <button class="reg-btn reg-btn_empty reg-btn_empty-wht reg-btn_blk-hover js-main-image">Submit</button> </div> </div> </div> </body> <script src="js/jquery-3.1.1.min.js"></script> <script src="js/croppie.min.js"></script> <script src="js/jquery.arcticmodal.js"></script> <script src="js/script.js"></script> </html>
Обратите внимание, что в коде уже присутствует подключение составляющих (стилей и скриптов), указанных выше библиотек. По большому счету в указанном файле, нас интересуют два блока. Первый это форма с ссылкой change photo, полем загрузки файла и двумя скрытыми полями для хранения имен сохраненных файлов. И второй – это блок, который размещается в контейнере, со стилевым правилом display:none и по сути, который является содержимым, отображаемым в попапе.
Теперь открываем файл scrip.js и начинаем кодировать. Для начала, опишем обработчик события клика мыши, по ссылке change photo.
$('.add-photo').on('click',function() { $("#c_input24").trigger('click'); return false; });
Как Вы идите, клик мыши по ссылке, активирует срабатывание аналогичного триггера для поля загрузки файла, тем самым открывая диалоговое окно по выбору изображения. Это сделано для удобства, так как ссылку значительно проще стилизировать, нежели поле формы. Далее, нам потребуется обработчик события change для вышеуказанного элемента формы.
$("#c_input24").on('change',function() { });
И соответственно в коде указанной выше анонимной функции, мы продолжим кодировать. Так как файл, на сервер, нужно отправить методом AJAX и файл это не просто текст, то необходимо использовать объект formData
var formData = new FormData(); formData.append('file',$(this)[0].files[0]);
Далее, отправка файла на сервер.
$.ajaxSetup({ headers: { //headers } }); $.ajax({ url:'server.php', type:"POST", data:formData, processData: false, contentType: false, dataType:"json" }) .done(function(html) { if(html.status == "success") { } })
Собственно, на сервер в файл server.php, отправляется файл, который располагается в объекте formData.
На сервере, необходимо сохранить переданный файл, при необходимости обработать (уменьшить размер, изменить формат и т.д.) и вернуть в качестве ответа, статус, его имя (после сохранения) и полный абсолютный URL, который понадобиться для отображения в попапе. Далее описываем код функции, которая выполнится после успешного выполнения запроса.
$('input[name="photo_c"]').val(html.file_max); $('.profile_photo_i').attr('src',html.path_max);
Для начала, используя полученные данные, записываем в скрытое поле формы имя файла, а в атрибут src изображения попапа его абсолютный URL. Таким образом, по сути, сейчас если открыть попап, то мы увидим изображение. Далее активируем визуальный интерфейс библиотеки Croppie:
basic = $('.profile_photo_i').croppie({ viewport : { width : 200, height : 200, type : 'circle' }
Обратите внимание, что переменная basic – глобальная и она понадобится нам на завершающем шаге. Собственно использование очень простое, достаточно вызвать на исполнение метод croppie() для интересующего изображения и задать параметры видимой области. Далее, показываем попап.
$('.profile-modal-photo').arcticmodal({ beforeOpen: function() { }, afterClose : function() { $('.profile_photo_i').croppie('destroy'); } });
Таким образом, в попапе пользователь имеет возможность выбрать требуемую область для обрезки и при необходимости изменить масштаб. Для сохранения изменений, потребуется нажать кнопку Submit, а значит давайте опишем обработчик для нее.
$('.js-main-image').on('click',function() { basic.croppie('result','base64').then(function(html) { $.ajaxSetup({ headers: { // } }); $.ajax({ url:'server.php', type:"POST", data:'photo=' + html + "&photo_c=" + $('input[name="photo_c"]').val(), dataType:"json" }) .done(function (html) { if(html.status == "success") { $('input[name="photo_i"]').val(html.file_mini); $('.perscab-photoedit-img img').attr('src',html.path_mini); $('.profile-modal-photo').arcticmodal('close'); } }) ; }); });
Как Вы видите, код здесь довольно прост, все та же отправка данных на сервер. Однако есть небольшой нюанс, связанный с вот этим участком.
basic.croppie('result','base64').then(function(html) {
По сути – эта одна строка кода, предоставляет нам доступ к изображению, которое было сформировано библиотекой Croppie в формате ‘base64′. При этом после получения изображения, оно доступно в виде строки, в переменной html в анонимной функции, метода then().
Ну и последний этап – это сохранения изображения на сервере и возвращение его имени и абсолютного URL для последующего отображения на экране. Ниже привожу тестовый код файла server.php. Хотел бы заметить, что его очень и очень просто и подготовлен только лишь для примера, ведь тема урока – это не сохранение данных на сервере, для и серверная реализация в каждом проекте индивидуальна.
<?php $uploaddir = 'upload/'; if(isset($_POST['photo'])) { $arr = []; $str = str_random(8); if($_POST['photo']) { $file = 'uploaded_photo_'.$str.'_min.png'; $uploadfile = $uploaddir . $file; $img = str_replace('data:image/png;base64,', '', $_POST['photo']); $img = str_replace(' ', '+', $img); $fileData = base64_decode($img); $url = $uploadfile; file_put_contents($url, $fileData); $arr['status'] = 'success'; $arr['path_mini'] = "http://localhost/crop/".$uploadfile; $arr['file_mini'] = $file; ////save in DB optional /*$this->user->photo_i = $file; $this->user->photo_c = $data['photo_c']; $this->user->update();*/ } } else { $uploadfile = $uploaddir . basename($_FILES['file']['name']); $arr = array(); //crop if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) { $arr['status'] = 'success'; $arr['path_max'] = "http://localhost/crop/".$uploadfile; $arr['file_max'] = $_FILES['file']['name']; } else { $arr['status'] = 'fail'; } } function str_random($length) { return substr(md5(microtime()),0,$length); } header('Content-type: application/json'); echo json_encode($arr); exit();
На этом данный урок завершен. Как обычно в видео версии урока, более подробно прокомментированы строки кода и некоторые моменты связанные с работой тестового скрипта. Всего Вам доброго и удачного кодирования!