JavaScript loading progress of an image

前端 未结 7 1904
慢半拍i
慢半拍i 2020-11-29 18:55

Is there a way in JS to get the progress of a loading image while the image is being loaded? I want to use the new Progress tag of HTML5 to show the progress of loading imag

相关标签:
7条回答
  • 2020-11-29 19:01

    With this, you add 2 new functions on the Image() object:

     Image.prototype.load = function(url){
            var thisImg = this;
            var xmlHTTP = new XMLHttpRequest();
            xmlHTTP.open('GET', url,true);
            xmlHTTP.responseType = 'arraybuffer';
            xmlHTTP.onload = function(e) {
                var blob = new Blob([this.response]);
                thisImg.src = window.URL.createObjectURL(blob);
            };
            xmlHTTP.onprogress = function(e) {
                thisImg.completedPercentage = parseInt((e.loaded / e.total) * 100);
            };
            xmlHTTP.onloadstart = function() {
                thisImg.completedPercentage = 0;
            };
            xmlHTTP.send();
        };
    
        Image.prototype.completedPercentage = 0;
    

    And here you use the load function and append the image on a div.

    var img = new Image();
    img.load("url");
    document.getElementById("myDiv").appendChild(img);
    

    During the loading state you can check the progress percentage using img.completedPercentage.

    0 讨论(0)
  • 2020-11-29 19:08

    for xmlhttpreq v2 check, use:

    var xmlHTTP = new XMLHttpRequest();
    if ('onprogress' in xmlHTTP) {
     // supported 
    } else {
     // isn't supported
    }
    
    0 讨论(0)
  • 2020-11-29 19:11

    Just to add to the improvements, I've modified Julian's answer (which in turn modified Sebastian's). I've moved the logic to a function instead of modifying the Image object. This function returns a Promise that resolves with the URL object, which only needs to be inserted as the src attribute of an image tag.

    /**
     * Loads an image with progress callback.
     *
     * The `onprogress` callback will be called by XMLHttpRequest's onprogress
     * event, and will receive the loading progress ratio as an whole number.
     * However, if it's not possible to compute the progress ratio, `onprogress`
     * will be called only once passing -1 as progress value. This is useful to,
     * for example, change the progress animation to an undefined animation.
     *
     * @param  {string}   imageUrl   The image to load
     * @param  {Function} onprogress
     * @return {Promise}
     */
    function loadImage(imageUrl, onprogress) {
      return new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        var notifiedNotComputable = false;
    
        xhr.open('GET', imageUrl, true);
        xhr.responseType = 'arraybuffer';
    
        xhr.onprogress = function(ev) {
          if (ev.lengthComputable) {
            onprogress(parseInt((ev.loaded / ev.total) * 100));
          } else {
            if (!notifiedNotComputable) {
              notifiedNotComputable = true;
              onprogress(-1);
            }
          }
        }
    
        xhr.onloadend = function() {
          if (!xhr.status.toString().match(/^2/)) {
            reject(xhr);
          } else {
            if (!notifiedNotComputable) {
              onprogress(100);
            }
    
            var options = {}
            var headers = xhr.getAllResponseHeaders();
            var m = headers.match(/^Content-Type\:\s*(.*?)$/mi);
    
            if (m && m[1]) {
              options.type = m[1];
            }
    
            var blob = new Blob([this.response], options);
    
            resolve(window.URL.createObjectURL(blob));
          }
        }
    
        xhr.send();
      });
    }
    
    /*****************
     * Example usage
     */
    
    var imgContainer = document.getElementById('imgcont');
    var progressBar = document.getElementById('progress');
    var imageUrl = 'https://placekitten.com/g/2000/2000';
    
    loadImage(imageUrl, (ratio) => {
      if (ratio == -1) {
        // Ratio not computable. Let's make this bar an undefined one.
        // Remember that since ratio isn't computable, calling this function
        // makes no further sense, so it won't be called again.
        progressBar.removeAttribute('value');
      } else {
        // We have progress ratio; update the bar.
        progressBar.value = ratio;
      }
    })
    .then(imgSrc => {
      // Loading successfuly complete; set the image and probably do other stuff.
      imgContainer.src = imgSrc;
    }, xhr => {
      // An error occured. We have the XHR object to see what happened.
    });
    <progress id="progress" value="0" max="100" style="width: 100%;"></progress>
    
    <img id="imgcont" />

    0 讨论(0)
  • 2020-11-29 19:12

    Here is a small update of the code of Julian Jensen in order to be able to draw the image in a Canvas after it is loaded :

    xmlHTTP.onload = function( e ) {
            var h = xmlHTTP.getAllResponseHeaders(),
                m = h.match( /^Content-Type\:\s*(.*?)$/mi ),
                mimeType = m[ 1 ] || 'image/png';
                // Remove your progress bar or whatever here. Load is done.
    
            var blob = new Blob( [ this.response ], { type: mimeType } );
            thisImg.src = window.URL.createObjectURL( blob );
    
             thisImg.onload = function()
                {
                    if ( callback ) callback( this );
                };
        };
    
    0 讨论(0)
  • 2020-11-29 19:17

    Actually, in latest chrome you can use it.

    $progress = document.querySelector('#progress');
    
    var url = 'https://placekitten.com/g/2000/2000';
    
    var request = new XMLHttpRequest();
    request.onprogress = onProgress;
    request.onload = onComplete;
    request.onerror = onError;
    
    function onProgress(event) {
      if (!event.lengthComputable) {
        return;
      }
      var loaded = event.loaded;
      var total = event.total;
      var progress = (loaded / total).toFixed(2);
    
      $progress.textContent = 'Loading... ' + parseInt(progress * 100) + ' %';
    
      console.log(progress);
    }
    
    function onComplete(event) {
      var $img = document.createElement('img');
      $img.setAttribute('src', url);
      $progress.appendChild($img);
      console.log('complete', url);
    }
    
    function onError(event) {
      console.log('error');
    }
    
    
    $progress.addEventListener('click', function() {
      request.open('GET', url, true);
      request.overrideMimeType('text/plain; charset=x-user-defined');
      request.send(null);
    });
    <div id="progress">Click me to load</div>

    0 讨论(0)
  • 2020-11-29 19:18

    If you want to process your loaded image, than you have to add one more function, because

    thisImg.src = window.URL.createObjectURL(blob)
    

    just starts to process the image as a thread.

    You have to add a new a function to the body of load prototype, like

      this.onload = function(e)
      {
        var canvas = document.createElement('canvas')
    
        canvas.width = this.width
        canvas.height = this.height
    
        canvas.getContext('2d').drawImage(this, 0, 0)
       }
    

    This make me headache to realize :)

    0 讨论(0)
提交回复
热议问题