Reputation: 25554
I'm building a photos uploader in Javascript and to read the already uploaded photos I've this code:
// Populate with existing photos
var index;
for (index = 0; index < params.photosToPopulate.length; ++index) {
// Get the data of the image
getDataUri(params.photosToPopulate[index], params, function(dataURI){
// Get the Blob
dataURItoBlob(dataURI, function(dataurl){
var blob = URL.createObjectURL(dataurl);
// fileItem
var fileItem = document.createElement("div");
fileItem.setAttribute('angle', 0);
fileItem.setAttribute('blob', blob);
fileItem.className = 'imageloaderplusFile';
filesdiv.appendChild(fileItem);
// fileImg
var fileImg = document.createElement("div");
fileImg.className = 'imageloaderplusImage';
fileImg.style.backgroundImage = 'url(' + dataURI + ')';
fileItem.appendChild(fileImg);
// fileRotate
var fileRotate = document.createElement("div");
fileRotate.className = 'imageloaderRotate';
fileRotate.setAttribute('title', 'Rotate');
fileItem.appendChild(fileRotate);
fileRotate.onclick = function(){
var angle;
switch(parseInt(this.parentNode.getAttribute('angle'))){
case 0:
angle = 90;
break;
case 90:
angle = 180;
break;
case 180:
angle = 270;
break;
case 270:
angle = 0;
break;
}
this.parentNode.setAttribute('angle', angle);
// css
var image = this.parentNode.firstChild;
image.style.webkitTransform = 'rotate(' + angle + 'deg)';
image.style.mozTransform = 'rotate(' + angle + 'deg)';
image.style.msTransform = 'rotate(' + angle + 'deg)';
image.style.oTransform = 'rotate(' + angle + 'deg)';
image.style.transform = 'rotate(' + angle + 'deg)';
// draw
ImageLoaderPlus.draw(this.parentNode, params);
}
// fileRemove
var fileRemove = document.createElement("div");
fileRemove.className = 'imageloaderRemove';
fileRemove.setAttribute('title', 'Remove');
fileItem.appendChild(fileRemove);
fileRemove.onclick = function(){
this.parentNode.parentNode.removeChild(this.parentNode);
}
// draw
ImageLoaderPlus.draw(fileItem, params);
});
});
} // End For Loop
In the For Loop I've the ordered photos, but some times because of the async functions getDataUri() and dataURItoBlob() the order of the items in the For Loop will not translate to the order in de UI/DOM and the photos are displayed in the incorrect order. How can I prevent this from happening?
The async functions are this ones:
function getDataUri(url, params, callback) {
var image = new Image();
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
//image.crossOrigin = "anonymous"; // This enables CORS
// get scale
var scale = (params.resize && (image.width > params.maxWidth || image.height > params.maxHeight)) ? Math.min(params.maxWidth / image.width, params.maxHeight / image.height) : 1;
image.onload = function (event) {
try {
canvas.width = Math.round(image.width * scale);
canvas.height = Math.round(image.height * scale);
ctx.drawImage(image, 0, 0, canvas.width, canvas.height);
//console.log( ctx.canvas.toDataURL('image/jpeg', params.jpegQuality) );
result = ctx.canvas.toDataURL('image/jpeg', params.jpegQuality)
callback(result);
} catch (e) {
alert(e);
}
};
image.src = url;
}
// To convert URL to Blob
function dataURItoBlob(dataURI, callback) {
// convert base64 to raw binary data held in a string
// doesn't handle URLEncoded DataURIs
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0) {
byteString = atob(dataURI.split(',')[1]);
} else {
byteString = unescape(dataURI.split(',')[1]);
}
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to an ArrayBuffer
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
try {
result = new Blob([ab], {type: mimeString});
//return new Blob([ab], {type: mimeString});
} catch (e) {
// The BlobBuilder API has been deprecated in favour of Blob, but older
// browsers don't know about the Blob constructor
// IE10 also supports BlobBuilder, but since the `Blob` constructor
// also works, there's no need to add `MSBlobBuilder`.
var BlobBuilder = window.WebKitBlobBuilder || window.MozBlobBuilder;
var bb = new BlobBuilder();
bb.append(ab);
result = bb.getBlob(mimeString);
//return bb.getBlob(mimeString);
}
callback(result);
}
Any clues on how to avoid this problem?
Best Regards,
Upvotes: 0
Views: 72
Reputation: 350272
You could solve this by storing the dataurl
values in an array as you receive them, but at the right index in that array. And then when you have counted that you received all those dataurl
values, you perform the loop over that array and execute the element creation code like you have it now.
// Intermediate array to store the dataURI and dataurl values in order
var urls = [];
var URIs = [];
// Keep count of how many dataurl values we received
var leftOver = params.photosToPopulate.length;
// Iterate in a way that you create a new closure on every iteration,
// each iteration has its proper index variable
params.photosToPopulate.forEach(function (photo, index) {
// Get the data of the image
getDataUri(photo, params, function(dataURI){
// Store at the right place in our array
URIs[index] = dataURI;
// Get the Blob
dataURItoBlob(dataURI, function(dataurl){
// Only store the url at the right place in our array
urls[index] = dataurl;
// ... and update the count
leftOver--;
// All done? Then iterate over the dataurl values in the correct order
if (!leftOver) urls.forEach(function(dataurl, index) {
var dataURI = URIs[index]; // get correct dataURI
var blob = URL.createObjectURL(dataurl);
// fileItem
var fileItem = document.createElement("div");
// ...etc, all your element creation code comes here, unchanged.
// ...
// draw
ImageLoaderPlus.draw(fileItem, params);
});
});
});
});
Upvotes: 1