Масштабирование изображения внутри canvas

466
06 апреля 2017, 17:25

Создаю миниатюру загруженного изображения. Отрисовываю её в canvas. Задаю ему статическую высоту, а ширину - авто, чтобы изображение не растягивалось. Есть ли какой-то способ, чтобы задать для canvas статические высоту и ширину, а уже изображение внутри масштабировать, по типу как работает свойство:

object-fit: cover;
object-position: 50% 50%;

Привожу пример скрипта:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<div>
    <input type="file" multiple="" id="photo">
</div>
<div>
    <ul id="preview-photo">
    </ul>
</div>
<script>
    var previewWidth = 150, // ширина превью
        previewHeight = 150, // высота превью
        maxFileSize = 2 * 1024 * 1024, // (байт) Максимальный размер файла (2мб)
        selectedFiles = {},// объект, в котором будут храниться выбранные файлы
        queue = [],
        image = new Image(),
        imgLoadHandler,
        isProcessing = false,
        errorMsg, // сообщение об ошибке при валидации файла
        previewPhotoContainer = document.querySelector('#preview-photo'); // контейнер, в котором будут отображаться превью
        // Когда пользователь выбрал файлы, обрабатываем их
        $('input[type=file][id=photo]').on('change', function() {
            var newFiles = $(this)[0].files; // массив с выбранными файлами
            for (var i = 0; i < newFiles.length; i++) {
                var file = newFiles[i];
                // В качестве "ключей" в объекте selectedFiles используем названия файлов
                // чтобы пользователь не мог добавлять один и тот же файл
                // Если файл с текущим названием уже существует в массиве, переходим к следующему файлу
                if (selectedFiles[file.name] != undefined) continue;
                // Валидация файлов (проверяем формат и размер)
                if ( errorMsg = validateFile(file) ) {
                    alert(errorMsg);
                    return;
                }
                // Добавляем файл в объект selectedFiles
                selectedFiles[file.name] = file;
                queue.push(file);
            }
            $(this).val('');
            processQueue(); // запускаем процесс создания миниатюр
        });
            // Валидация выбранного файла (формат, размер)
            var validateFile = function(file)
            {
                if ( !file.type.match(/image\/(jpeg|jpg|png|gif)/) ) {
                    return 'Фотография должна быть в формате jpg, png или gif';
            }
            if ( file.size > maxFileSize ) {
                return 'Размер фотографии не должен превышать 2 Мб';
            }
        };
        var listen = function(element, event, fn) {
            return element.addEventListener(event, fn, false);
        };
        // Создание миниатюры
        var processQueue = function()
        {
            // Миниатюры будут создаваться поочередно
            // чтобы в один момент времени не происходило создание нескольких миниатюр
            // проверяем запущен ли процесс
        if (isProcessing) { return; }
        // Если файлы в очереди закончились, завершаем процесс
        if (queue.length == 0) {
            isProcessing = false;
            return;
        }
        isProcessing = true;
        var file = queue.pop(); // Берем один файл из очереди
        var li = document.createElement('LI');
        var span = document.createElement('SPAN');
        var spanDel = document.createElement('SPAN');
        var canvas = document.createElement('CANVAS');
        var ctx = canvas.getContext('2d');
        span.setAttribute('class', 'img');
        spanDel.setAttribute('class', 'delete');
        spanDel.innerHTML = '<img src="/public/images/deletes.svg">';
        li.appendChild(span);
        li.appendChild(spanDel);
        li.setAttribute('data-id', file.name);                                                                              
        image.removeEventListener('load', imgLoadHandler, false);
        // создаем миниатюру
        imgLoadHandler = function() {
            ratio = realW/realH;
            previewHeight = 100;
            previewWidth = 100 * ratio;
            canvas.setAttribute('width', previewWidth); //ширина области отображения превью
            canvas.setAttribute('height', previewHeight); //высота области отображения превью
            ctx.drawImage(image, 0, 0, previewWidth, previewHeight);
            URL.revokeObjectURL(image.src);
            span.appendChild(canvas);
            isProcessing = false;
            setTimeout(processQueue, 200); // запускаем процесс создания миниатюры для следующего изображения
        };
        // Выводим миниатюру в контейнере previewPhotoContainer                                     
        previewPhotoContainer.appendChild(li);
        listen(image, 'load', imgLoadHandler);
        image.src = URL.createObjectURL(file);
        // Сохраняем содержимое оригинального файла в base64 в отдельном поле формы
        // чтобы при отправке формы файл был передан на сервер
        var fr = new FileReader();
        fr.readAsDataURL(file);
        fr.onload = (function (file){
            return function (e) {
            realW = image.width;
            realH = image.height;
            $('#preview-photo').append(
                '<input type="hidden" name="photos[]" value="' + e.target.result + '" data-id="' + file.name+ '">'
            );
        }
    }) (file);
};
// Удаление фотографии
$(document).on('click', '#preview-photo li span.delete', function() {
    var fileId = $(this).parents('li').attr('data-id');
    if (selectedFiles[fileId] != undefined) delete selectedFiles[fileId]; // Удаляем файл из объекта selectedFiles                                                  
    $(this).parents('li').remove(); // Удаляем превью
    $('input[name^=photo][data-id="' + fileId + '"]').remove(); // Удаляем поле с содержимым файла
});
</script>
READ ALSO
Галерея на javascript

Галерея на javascript

Задача том, что бы он выводил на экран одну большую картинку, под ней несколько превью , которые листаются и при нажатии на них на месте большой...

341
как растянуть сайдбар до конца страницы?

как растянуть сайдбар до конца страницы?

У меня имеется: контент - сайдбар - футер

284
Как в Bootstrap v4.0.0-alpha.6 подключить классы с flex?

Как в Bootstrap v4.0.0-alpha.6 подключить классы с flex?

В проекте используется Bootstrap v40

357