PROWAREtech
JavaScript: Download Images with Progress Indicator Bar
How to download images to the browser while showing the user a percent completion of the download while they wait.
This prototype function Image.progressload()
will download an image and issue calls to a progress callback function while the download is happening. See code notes for more information.
This code is compatible with Internet Explorer 11 (IE11) if still developing for this browser.
// NOTE: progress_callback is called with the percent of download completion passed,
// and done_callback is called when the download is complete with the image object passed
Image.prototype.progressload = function (image_url, progress_callback, done_callback) {
var this_img = this, xhr = new XMLHttpRequest();
xhr.open("get", image_url, true);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
var blob = new Blob([this.response]);
this_img.src = URL.createObjectURL(blob);
if (typeof done_callback == "function") {
done_callback(this_img);
}
setTimeout(function () { URL.revokeObjectURL(this_img.src); }, 5000); // NOTE: this frees the resource after it has presumably been used
};
xhr.onprogress = function (ev) {
if (ev.lengthComputable && typeof progress_callback == "function") {
progress_callback((ev.loaded / ev.total) * 100);
}
};
xhr.onloadstart = function () {
if (typeof progress_callback == "function") {
progress_callback(0);
}
};
xhr.onloadend = function () {
if (typeof progress_callback == "function") {
progress_callback(100);
}
}
xhr.send();
};
Here is an alternate version that, under heavy load and usage is not as reliable due to a bug in Chrome/Edge, but it should work best, certainly if and when the bug is fixed. This is the best code!
// NOTE: progress_callback is called with the percent of download completion passed,
// and done_callback is called when the download is complete with the image object passed
Image.prototype.progressload = function (image_url, progress_callback, done_callback) {
var this_img = this, xhr = new XMLHttpRequest();
if (typeof done_callback == "function") {
this_img.onload = function () {
done_callback(this_img);
};
}
xhr.open("get", image_url, true);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
var blob = new Blob([this.response]);
this_img.src = URL.createObjectURL(blob);
setTimeout(function () { URL.revokeObjectURL(this_img.src); }, 5000); // NOTE: this frees the resource after it has presumably been used
};
xhr.onprogress = function (ev) {
if (ev.lengthComputable && typeof progress_callback == "function") {
progress_callback((ev.loaded / ev.total) * 100);
}
};
xhr.onloadstart = function () {
if (typeof progress_callback == "function") {
progress_callback(0);
}
};
xhr.onloadend = function () {
if (typeof progress_callback == "function") {
progress_callback(100);
}
}
xhr.send();
};
An example HTML page using the above prototype. It has a very much not elegant red progress bar that shows the progress of the download and then displays the image when it is done with its download. NOTE: this only works well on large images.
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Download Images with Progress Using JavaScript</title>
<style>
body {
margin: 0;
padding: 0;
}
img {
width: 100%;
height: auto;
}
</style>
</head>
<body>
<div class="page">
<script type="text/javascript">
// NOTE: progress_callback is called with the percent of download completion passed,
// and done_callback is called when the download is complete with the image object passed
Image.prototype.progressload = function (image_url, progress_callback, done_callback) {
var this_img = this, xhr= new XMLHttpRequest();
xhr.open("get", image_url, true);
xhr.responseType = "arraybuffer";
xhr.onload = function () {
var blob = new Blob([this.response]);
this_img.src = URL.createObjectURL(blob);
if (typeof done_callback == "function") {
done_callback(this_img);
}
setTimeout(function () { URL.revokeObjectURL(this_img.src); }, 5000); // NOTE: this frees the resource after it has presumably been used
};
xhr.onprogress = function (ev) {
if (ev.lengthComputable && typeof progress_callback == "function") {
progress_callback((ev.loaded / ev.total) * 100);
}
};
xhr.onloadstart = function () {
if (typeof progress_callback == "function") {
progress_callback(0);
}
};
xhr.onloadend = function () {
if (typeof progress_callback == "function") {
progress_callback(100);
}
}
xhr.send();
};
window.onload = function () {
var img = new Image();
img.progressload("/img/blob.jpg?v=" + Number(new Date()), function (percent) { // NOTE: specify a parameter to force a new download
var prog = document.getElementById("progress");
prog.style.width = percent + "%";
prog.innerText = Math.round(percent) + "%";
}, function (image) {
document.body.appendChild(image);
});
};
</script>
<div style="background-color:transparent;height:25px;width:100%;text-align:left;">
<div id="progress" style="display:inline-block;background-color:red;color:white;height:inherit;width:0;overflow:hidden;line-height:25px;"></div>
</div>
</body>
</html>
Comment