如何检测画布对象的绘制是否完成?

时间:2019-03-15 18:51:04

标签: javascript canvas

我有以下JS代码(在stackoverflow上找到,并进行了少许修改),该代码使用 canvas 在客户端调整了图像大小。

function FileListItem(a) {
    // Necesary to proper-work of CatchFile function (especially image-resizing).
    // Code by Jimmy Wärting (https://github.com/jimmywarting)
    a = [].slice.call(Array.isArray(a) ? a : arguments)
    for (var c, b = c = a.length, d = !0; b-- && d;) d = a[b] instanceof File
    if (!d) throw new TypeError('expected argument to FileList is File or array of File objects')
    for (b = (new ClipboardEvent('')).clipboardData || new DataTransfer; c--;) b.items.add(a[c])
    return b.files
}

function CatchFile(obj) {
    // Based on ResizeImage function.
    // Original code by Jimmy Wärting (https://github.com/jimmywarting)

    var file = obj.files[0];
    // Check that file is image (regex)
    var imageReg = /[\/.](gif|jpg|jpeg|tiff|png|bmp)$/i;
    if (!file) return

    var uploadButtonsDiv = document.getElementById('upload_buttons_area');
    // Check, that it is first uploaded file, or not
    // If first, draw a div for showing status
    var uploadStatusDiv = document.getElementById('upload_status_area');

    if (!uploadStatusDiv) {
        var uploadStatusDiv = document.createElement('div');
        uploadStatusDiv.setAttribute('class', 'upload-status-area');
        uploadStatusDiv.setAttribute('id', 'upload_status_area');
        uploadButtonsDiv.parentNode.insertBefore(uploadStatusDiv, uploadButtonsDiv.nextSibling);
        // Draw sub-div for each input field
        var i;
        for (i = 0; i < 3; i++) {
          var uploadStatus = document.createElement('div');
          uploadStatus.setAttribute('class', 'upload-status');
          uploadStatus.setAttribute('id', ('upload_status_id_commentfile_set-' + i + '-file'));
          uploadStatusDiv.append(uploadStatus);
        }
    }

    var canvasDiv = document.getElementById('canvas-area');
    var currField = document.getElementById(obj.id);
    var currFieldLabel = document.getElementById(('label_' + obj.id));

    // Main image-converting procedure
    if (imageReg.test(file.name)) {
        file.image().then(img => {
            const canvas = document.createElement('canvas')
            canvas.setAttribute('id', ('canvas_' + obj.id));
            const ctx = canvas.getContext('2d')
            const maxWidth = 1600
            const maxHeight = 1200

            // Calculate new size
            const ratio = Math.min(maxWidth / img.width, maxHeight / img.height)
            const width = img.width * ratio + .5|0
            const height = img.height * ratio + .5|0

            // Resize the canvas to the new dimensions
            canvas.width = width
            canvas.height = height

            // Drawing canvas-object is necessary to proper-work
            // on mobile browsers.
            // In this case, canvas is inserted to hidden div (display: none)
            ctx.drawImage(img, 0, 0, width, height)
            canvasDiv.appendChild(canvas)

            // Get the binary (aka blob)
            canvas.toBlob(blob => {
                const resizedFile = new File([blob], file.name, file)
                const fileList = new FileListItem(resizedFile)

                // Temporary remove event listener since
                // assigning a new filelist to the input
                // will trigger a new change event...
                obj.onchange = null
                obj.files = fileList
                obj.onchange = CatchFile
            }, 'image/jpeg', 0.70)
        }
        )

        // If file is image, during conversion show status
        function ShowConvertConfirmation() {
            if (document.getElementById('canvas_' + obj.id)) {
                document.getElementById(('upload_status_' + obj.id)).innerHTML =
                '<font color="#4CAF50">Konwertowanie pliku ' + file.name + ' zakończone!</font>';
                return true;
            }
            else {
                document.getElementById(('upload_status_' + obj.id)).innerHTML =
                '<font color="#4CAF50">Konwertowanie pliku ' + file.name + ' zakończone!</font>';
                return false;
            }
        }

        // Loop ShowConvertConfirmation function untill return true (file is converted)
        var convertConfirmationLoop = setInterval(function() {
            var isConfirmed = ShowConvertConfirmation();
            if (!isConfirmed) {
                ShowConvertConfirmation();
            }
            else {
                // Break loop
                clearInterval(convertConfirmationLoop);
            }
        }, 2000); // Check every 2000ms
        }
    // If file is not an image, show status with filename
    else {
        document.getElementById(('upload_status_' + obj.id)).innerHTML =
        '<font color="#4CAF50">Dodano plik ' + file.name + '</font>';
        //uploadStatusDiv.append(uploadStatus);
    }
}

在隐藏的div中绘制画布:

<div id="canvas-area" style="overflow: hidden; height: 0;"></div>

我只检测到显示了

canvas-area 区域,并以此为基础,JS附加了另一个具有状态的div。

不幸的是,在某些移动设备(中端智能手机)上,消息将在绘制完成之前显示(这是错误的)。因此,某些上传的图像已损坏或保持原始大小。

如何防止这种情况?

1 个答案:

答案 0 :(得分:0)

图像加载后应该发生的所有事情,都应该在then回调中执行,或者在其中调用。

重要的是要意识到,回调中 not 的代码将在绘图完成之前立即执行。